view data/fileio/CSVStreamWriter.h @ 1436:d61d6c33f14d streaming-csv-writer

Remove some duplication and make use of utility function for writing in chunks to avoid memory growth.
author Lucas Thompson <dev@lucas.im>
date Tue, 17 Apr 2018 10:03:49 +0100
parents 0684c6698e3f
children 09c2ba31a711
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

/*
    Sonic Visualiser
    An audio file viewer and annotation editor.
    Centre for Digital Music, Queen Mary, University of London.
    This file copyright 2017 Lucas Thompson.
    
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#ifndef _CSV_STREAM_WRITER_H_
#define _CSV_STREAM_WRITER_H_

#include "base/BaseTypes.h"
#include "base/Selection.h"
#include "base/ProgressReporter.h"
#include "base/DataExportOptions.h"
#include "data/model/Model.h"
#include <QString>
#include <algorithm>

namespace CSV
{
using Completed = bool;

template <class OutStream>
auto writeToStreamInChunks(
    OutStream& oss,
    const Model& model,
    const Selection& extents,
    ProgressReporter* reporter = nullptr,
    QString delimiter = ",",
    DataExportOptions options = DataExportDefaults,
    const sv_frame_t blockSize = 16384
) -> Completed
{
    if (blockSize <= 0) return false;
    sv_frame_t readPtr = extents.isEmpty() ?
        model.getStartFrame() : extents.getStartFrame();
    sv_frame_t endFrame = extents.isEmpty() ?
        model.getEndFrame() : extents.getEndFrame();
    int previousPercentagePoint = 0;

    const auto wasCancelled = [&reporter]() { 
        return reporter && reporter->wasCancelled(); 
    };

    while (readPtr < endFrame) {
        if (wasCancelled()) return false;

        const auto start = readPtr;
        const auto end = std::min(start + blockSize, endFrame);

        oss << model.toDelimitedDataStringSubsetWithOptions(
            delimiter,
            options,
            start,
            end
        ) << (end < endFrame ? "\n" : "");

        const auto currentPercentage = 100 * end / endFrame;
        const bool hasIncreased = currentPercentage > previousPercentagePoint;

        if (hasIncreased) {
            if (reporter) reporter->setProgress(currentPercentage);
            previousPercentagePoint = currentPercentage;
        }
        readPtr = end;
    }
    return !wasCancelled(); // setProgress could process event loop
}

template <class OutStream>
auto writeToStreamInChunks(
    OutStream& oss,
    const Model& model,
    ProgressReporter* reporter = nullptr,
    QString delimiter = ",",
    DataExportOptions options = DataExportDefaults,
    const sv_frame_t blockSize = 16384
) -> Completed
{
    const Selection empty;
    return CSV::writeToStreamInChunks(
        oss,
        model,
        empty,
        reporter,
        delimiter,
        options,
        blockSize
    );
}
} // namespace
#endif