comparison data/fileio/CSVStreamWriter.h @ 1445:4437209348ef streaming-csv-writer

Introduce overload of writeInChunks taking a MultiSelection. Simplifies the progress reporting.
author Lucas Thompson <dev@lucas.im>
date Tue, 17 Apr 2018 10:03:50 +0100
parents 4507be815384
children 5bd240517c1a
comparison
equal deleted inserted replaced
1444:4507be815384 1445:4437209348ef
21 #include "base/ProgressReporter.h" 21 #include "base/ProgressReporter.h"
22 #include "base/DataExportOptions.h" 22 #include "base/DataExportOptions.h"
23 #include "data/model/Model.h" 23 #include "data/model/Model.h"
24 #include <QString> 24 #include <QString>
25 #include <algorithm> 25 #include <algorithm>
26 26 #include <numeric>
27 namespace
28 {
29 const auto initProgressCalculator = [](sv_frame_t nFramesToWrite) {
30 return [nFramesToWrite](sv_frame_t nFramesWritten) {
31 return 100 * nFramesWritten / nFramesToWrite;
32 };
33 };
34 } // namespace
35 27
36 namespace CSVStreamWriter 28 namespace CSVStreamWriter
37 { 29 {
38 30
39 template < 31 template <class OutStream>
40 class OutStream, 32 bool
41 class ProgressCalculatorInit = decltype(initProgressCalculator) 33 writeInChunks(OutStream& oss,
42 > 34 const Model& model,
35 const MultiSelection& regions,
36 ProgressReporter* reporter = nullptr,
37 QString delimiter = ",",
38 DataExportOptions options = DataExportDefaults,
39 const sv_frame_t blockSize = 16384)
40 {
41 if (blockSize <= 0) return false;
42
43 // TODO, some form of checking validity of selections?
44 const auto nFramesToWrite = std::accumulate(
45 regions.getSelections().begin(),
46 regions.getSelections().end(),
47 0,
48 [](sv_frame_t acc, const Selection& current) -> sv_frame_t {
49 return acc + (current.getEndFrame() - current.getStartFrame());
50 }
51 );
52
53 const auto wasCancelled = [&reporter]() {
54 return reporter && reporter->wasCancelled();
55 };
56
57 sv_frame_t nFramesWritten = 0;
58 int previousProgress = 0;
59
60 for (const auto& extents : regions.getSelections()) {
61 const auto startFrame = extents.getStartFrame();
62 const auto endFrame = extents.getEndFrame();
63 auto readPtr = startFrame;
64 while (readPtr < endFrame) {
65 if (wasCancelled()) return false;
66
67 const auto start = readPtr;
68 const auto end = std::min(start + blockSize, endFrame);
69
70 oss << model.toDelimitedDataStringSubsetWithOptions(
71 delimiter,
72 options,
73 start,
74 end
75 ) << (end < endFrame ? "\n" : "");
76 nFramesWritten += end - start;
77 const auto currentProgress = 100 * nFramesWritten / nFramesToWrite;
78 const bool hasIncreased = currentProgress > previousProgress;
79 if (hasIncreased) {
80 if (reporter) reporter->setProgress(currentProgress);
81 previousProgress = currentProgress;
82 }
83 readPtr = end;
84 }
85 }
86 return !wasCancelled(); // setProgress could process event loop
87 }
88
89 template <class OutStream>
43 bool 90 bool
44 writeInChunks(OutStream& oss, 91 writeInChunks(OutStream& oss,
45 const Model& model, 92 const Model& model,
46 const Selection& extents, 93 const Selection& extents,
47 ProgressReporter* reporter = nullptr, 94 ProgressReporter* reporter = nullptr,
48 QString delimiter = ",", 95 QString delimiter = ",",
49 DataExportOptions options = DataExportDefaults, 96 DataExportOptions options = DataExportDefaults,
50 const sv_frame_t blockSize = 16384, 97 const sv_frame_t blockSize = 16384)
51 const ProgressCalculatorInit& initCalc = initProgressCalculator)
52 { 98 {
53 if (blockSize <= 0) return false;
54 const auto startFrame = extents.isEmpty() ? 99 const auto startFrame = extents.isEmpty() ?
55 model.getStartFrame() : extents.getStartFrame(); 100 model.getStartFrame() : extents.getStartFrame();
56 const auto endFrame = extents.isEmpty() ? 101 const auto endFrame = extents.isEmpty() ?
57 model.getEndFrame() : extents.getEndFrame(); 102 model.getEndFrame() : extents.getEndFrame();
58 const auto hasValidExtents = startFrame >= 0 && endFrame > startFrame; 103 const auto hasValidExtents = startFrame >= 0 && endFrame > startFrame;
59 if (!hasValidExtents) return false; 104 if (!hasValidExtents) return false;
60 const auto calculateProgress = initCalc(endFrame - startFrame); 105 Selection all {
61 106 startFrame,
62 auto readPtr = startFrame; 107 endFrame
63 int previousPercentagePoint = 0;
64
65 const auto wasCancelled = [&reporter]() {
66 return reporter && reporter->wasCancelled();
67 }; 108 };
68 109 MultiSelection regions;
69 while (readPtr < endFrame) { 110 regions.addSelection(all);
70 if (wasCancelled()) return false; 111 return CSVStreamWriter::writeInChunks(
71 112 oss,
72 const auto start = readPtr; 113 model,
73 const auto end = std::min(start + blockSize, endFrame); 114 regions,
74 115 reporter,
75 oss << model.toDelimitedDataStringSubsetWithOptions( 116 delimiter,
76 delimiter, 117 options,
77 options, 118 blockSize
78 start, 119 );
79 end
80 ) << (end < endFrame ? "\n" : "");
81 const auto nFramesWritten = end - startFrame;
82 const auto currentPercentage = calculateProgress(nFramesWritten);
83 const bool hasIncreased = currentPercentage > previousPercentagePoint;
84
85 if (hasIncreased) {
86 if (reporter) reporter->setProgress(currentPercentage);
87 previousPercentagePoint = currentPercentage;
88 }
89 readPtr = end;
90 }
91 return !wasCancelled(); // setProgress could process event loop
92 } 120 }
93 121
94 template <class OutStream> 122 template <class OutStream>
95 bool 123 bool
96 writeInChunks(OutStream& oss, 124 writeInChunks(OutStream& oss,