annotate data/fileio/CSVStreamWriter.h @ 1833:21c792334c2e sensible-delimited-data-strings

Rewrite all the DelimitedDataString stuff so as to return vectors of individual cell strings rather than having the classes add the delimiters themselves. Rename accordingly to names based on StringExport. Take advantage of this in the CSV writer code so as to properly quote cells that contain delimiter characters.
author Chris Cannam
date Fri, 03 Apr 2020 17:11:05 +0100
parents 0d89abd631ac
children
rev   line source
dev@1430 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
dev@1430 2
dev@1430 3 /*
dev@1430 4 Sonic Visualiser
dev@1430 5 An audio file viewer and annotation editor.
dev@1430 6 Centre for Digital Music, Queen Mary, University of London.
dev@1438 7 This file copyright 2017 Queen Mary, University of London.
dev@1430 8
dev@1430 9 This program is free software; you can redistribute it and/or
dev@1430 10 modify it under the terms of the GNU General Public License as
dev@1430 11 published by the Free Software Foundation; either version 2 of the
dev@1430 12 License, or (at your option) any later version. See the file
dev@1430 13 COPYING included with this distribution for more information.
dev@1430 14 */
dev@1430 15
cannam@1452 16 #ifndef SV_CSV_STREAM_WRITER_H
cannam@1452 17 #define SV_CSV_STREAM_WRITER_H
dev@1430 18
dev@1434 19 #include "base/BaseTypes.h"
dev@1434 20 #include "base/Selection.h"
dev@1434 21 #include "base/ProgressReporter.h"
dev@1434 22 #include "base/DataExportOptions.h"
Chris@1833 23 #include "base/StringBits.h"
dev@1434 24 #include "data/model/Model.h"
Chris@1833 25
dev@1434 26 #include <QString>
dev@1434 27 #include <algorithm>
dev@1445 28 #include <numeric>
dev@1441 29
dev@1438 30 namespace CSVStreamWriter
dev@1430 31 {
dev@1430 32
dev@1445 33 template <class OutStream>
dev@1445 34 bool
dev@1445 35 writeInChunks(OutStream& oss,
dev@1445 36 const Model& model,
dev@1445 37 const MultiSelection& regions,
dev@1445 38 ProgressReporter* reporter = nullptr,
dev@1445 39 QString delimiter = ",",
dev@1445 40 DataExportOptions options = DataExportDefaults,
dev@1445 41 const sv_frame_t blockSize = 16384)
dev@1445 42 {
dev@1447 43 const auto selections = regions.getSelections();
dev@1447 44 if (blockSize <= 0 || selections.empty()) return false;
dev@1445 45
dev@1445 46 // TODO, some form of checking validity of selections?
dev@1445 47 const auto nFramesToWrite = std::accumulate(
dev@1447 48 selections.begin(),
dev@1447 49 selections.end(),
dev@1445 50 0,
dev@1445 51 [](sv_frame_t acc, const Selection& current) -> sv_frame_t {
dev@1445 52 return acc + (current.getEndFrame() - current.getStartFrame());
dev@1445 53 }
dev@1445 54 );
dev@1445 55
dev@1445 56 const auto wasCancelled = [&reporter]() {
dev@1445 57 return reporter && reporter->wasCancelled();
dev@1445 58 };
dev@1445 59
dev@1445 60 sv_frame_t nFramesWritten = 0;
dev@1445 61 int previousProgress = 0;
Chris@1609 62 bool started = false;
dev@1445 63
dev@1447 64 for (const auto& extents : selections) {
dev@1445 65 const auto startFrame = extents.getStartFrame();
dev@1445 66 const auto endFrame = extents.getEndFrame();
dev@1445 67 auto readPtr = startFrame;
dev@1445 68 while (readPtr < endFrame) {
dev@1445 69 if (wasCancelled()) return false;
dev@1445 70
dev@1445 71 const auto start = readPtr;
dev@1445 72 const auto end = std::min(start + blockSize, endFrame);
Chris@1833 73 const auto data = model.toStringExportRows(
dev@1445 74 options,
dev@1445 75 start,
Chris@1679 76 end - start
Chris@1833 77 );
dev@1449 78
Chris@1833 79 if (!data.empty()) {
Chris@1833 80 for (const auto &row: data) {
Chris@1833 81 if (started) {
Chris@1833 82 oss << "\n";
Chris@1833 83 } else {
Chris@1833 84 started = true;
Chris@1833 85 }
Chris@1833 86 oss << StringBits::joinDelimited(row, delimiter);
Chris@1609 87 }
dev@1449 88 }
dev@1449 89
dev@1445 90 nFramesWritten += end - start;
Chris@1454 91 const int currentProgress =
Chris@1454 92 int(100 * nFramesWritten / nFramesToWrite);
dev@1445 93 const bool hasIncreased = currentProgress > previousProgress;
dev@1445 94 if (hasIncreased) {
dev@1445 95 if (reporter) reporter->setProgress(currentProgress);
dev@1445 96 previousProgress = currentProgress;
dev@1445 97 }
dev@1445 98 readPtr = end;
dev@1445 99 }
dev@1445 100 }
dev@1445 101 return !wasCancelled(); // setProgress could process event loop
dev@1445 102 }
dev@1445 103
dev@1445 104 template <class OutStream>
dev@1441 105 bool
dev@1441 106 writeInChunks(OutStream& oss,
dev@1441 107 const Model& model,
dev@1441 108 const Selection& extents,
dev@1441 109 ProgressReporter* reporter = nullptr,
dev@1441 110 QString delimiter = ",",
dev@1441 111 DataExportOptions options = DataExportDefaults,
dev@1445 112 const sv_frame_t blockSize = 16384)
dev@1434 113 {
dev@1441 114 const auto startFrame = extents.isEmpty() ?
dev@1434 115 model.getStartFrame() : extents.getStartFrame();
dev@1441 116 const auto endFrame = extents.isEmpty() ?
dev@1434 117 model.getEndFrame() : extents.getEndFrame();
dev@1441 118 const auto hasValidExtents = startFrame >= 0 && endFrame > startFrame;
dev@1441 119 if (!hasValidExtents) return false;
dev@1445 120 Selection all {
dev@1445 121 startFrame,
dev@1445 122 endFrame
dev@1434 123 };
dev@1445 124 MultiSelection regions;
dev@1445 125 regions.addSelection(all);
Chris@1833 126 return writeInChunks(
dev@1445 127 oss,
dev@1445 128 model,
dev@1445 129 regions,
dev@1445 130 reporter,
dev@1445 131 delimiter,
dev@1445 132 options,
dev@1445 133 blockSize
dev@1445 134 );
dev@1434 135 }
dev@1434 136
dev@1434 137 template <class OutStream>
dev@1441 138 bool
dev@1441 139 writeInChunks(OutStream& oss,
dev@1441 140 const Model& model,
dev@1441 141 ProgressReporter* reporter = nullptr,
dev@1441 142 QString delimiter = ",",
dev@1441 143 DataExportOptions options = DataExportDefaults,
dev@1441 144 const sv_frame_t blockSize = 16384)
dev@1434 145 {
dev@1434 146 const Selection empty;
Chris@1833 147 return writeInChunks(
dev@1434 148 oss,
dev@1434 149 model,
dev@1434 150 empty,
dev@1434 151 reporter,
dev@1434 152 delimiter,
dev@1434 153 options,
dev@1434 154 blockSize
dev@1434 155 );
dev@1434 156 }
dev@1438 157 } // namespace CSVStreamWriter
cannam@1452 158 #endif