summaryrefslogtreecommitdiffstats
path: root/src/async/progress-splitter.h
blob: 966661105c4a88dc05d2bf47d767ebd298e268c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// SPDX-License-Identifier: GPL-2.0-or-later
/** \file Progress-splitter
 * Dynamically split a Progress into several sub-tasks.
 */
#ifndef INKSCAPE_ASYNC_PROGRESS_SPLITTER_H
#define INKSCAPE_ASYNC_PROGRESS_SPLITTER_H

#include <vector>
#include <optional>
#include "progress.h"

namespace Inkscape {
namespace Async {

/**
 * A RAII object for splitting a Progress into a dynamically-determined collection of sub-tasks.
 */
template <typename T, typename... S>
class ProgressSplitter
{
public:
    /// Construct a progress splitter for a given task.
    ProgressSplitter(Progress<T, S...> &parent) : parent(&parent) {}

    /// Add a SubProgress which makes progress \a amount.
    ProgressSplitter &add(std::optional<SubProgress<T, S...>> &progress, T amount)
    {
        entries.push_back({ &progress, amount });
        return *this;
    }

    /// Convenience method to enable a "fluent interface". Calls \a add if \a condition is true.
    ProgressSplitter &add_if(std::optional<SubProgress<T, S...>> &progress, T amount, bool condition)
    {
        return condition ? add(progress, amount) : *this;
    }

    /// Assign to each added SubProgress its portion of the total progress.
    ~ProgressSplitter() { apportion(); }

private:
    struct Entry
    {
        std::optional<SubProgress<T, S...>> *progress;
        T amount;
    };

    Progress<T, S...> *parent;
    std::vector<Entry> entries;

    void apportion() noexcept
    {
        if (entries.empty()) {
            return;
        }

        T total = 0;
        for (auto const &e : entries) {
            total += e.amount;
        }

        T from = 0;
        for (auto &e : entries) {
            e.progress->emplace(*parent, from / total, e.amount / total);
            from += e.amount;
        }
    }
};

} // namespace Async
} // namespace Inkscape

#endif // INKSCAPE_ASYNC_PROGRESS_SPLITTER_H