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
|