Mercurial > hg > svcore
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, |