summaryrefslogtreecommitdiff
path: root/src/thread_utils.h
diff options
context:
space:
mode:
authorMikaël Capelle <capelle.mikael@gmail.com>2020-05-24 23:32:47 +0200
committerMikaël Capelle <capelle.mikael@gmail.com>2020-05-24 23:32:47 +0200
commit0aac4f3291d65ebc1b0bbee744fca347ecef7022 (patch)
treeec3ca88e1971a6ec380ebdc7301f9931b9a7d7fa /src/thread_utils.h
parentb352aa53e0005cc262ab7441bd374570d6423279 (diff)
Add MemoizedLocked.
Diffstat (limited to 'src/thread_utils.h')
-rw-r--r--src/thread_utils.h43
1 files changed, 43 insertions, 0 deletions
diff --git a/src/thread_utils.h b/src/thread_utils.h
index 2cb87a8d..6c044138 100644
--- a/src/thread_utils.h
+++ b/src/thread_utils.h
@@ -7,6 +7,49 @@
namespace MOShared {
/**
+ * Class that can be used to perform thread-safe memoization.
+ *
+ * Each instance hold a flag indicating if the current value is up-to-date
+ * or not. This flag can be reset using `invalidate()`. When the value is queried,
+ * the flag is checked, and if it is not up-to-date, the given callback is used
+ * to compute the value.
+ *
+ * The computation and update of the value is locked to avoid concurrent modifications.
+ *
+ * @tparam T Type of value ot memoized.
+ * @tparam Fn Type of the callback.
+ */
+template <class T, class Fn>
+struct MemoizedLocked {
+
+ MemoizedLocked(Fn callback, T value = {}) :
+ m_Fn{ callback }, m_Value{ std::move(value) } { }
+
+ template <class... Args>
+ T& value(Args&&... args) const {
+ if (m_NeedUpdating) {
+ std::scoped_lock lock(m_Mutex);
+ if (m_NeedUpdating) {
+ m_Value = std::invoke(m_Fn, std::forward<Args>(args)... );
+ m_NeedUpdating.store(false);
+ }
+ }
+ return m_Value;
+ }
+
+ void invalidate() const {
+ m_NeedUpdating.store(true);
+ }
+
+private:
+ mutable std::mutex m_Mutex;
+ mutable std::atomic<bool> m_NeedUpdating{ true };
+
+ Fn m_Fn;
+ mutable T m_Value;
+};
+
+/**
* @brief Apply the given callable to each element between the two given iterators
* in a parallel way.
*