summaryrefslogtreecommitdiffstats
path: root/src/async/progress-splitter.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/async/progress-splitter.h')
-rw-r--r--src/async/progress-splitter.h73
1 files changed, 73 insertions, 0 deletions
diff --git a/src/async/progress-splitter.h b/src/async/progress-splitter.h
new file mode 100644
index 0000000..9666611
--- /dev/null
+++ b/src/async/progress-splitter.h
@@ -0,0 +1,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