From 0aac4f3291d65ebc1b0bbee744fca347ecef7022 Mon Sep 17 00:00:00 2001 From: Mikaƫl Capelle Date: Sun, 24 May 2020 23:32:47 +0200 Subject: Add MemoizedLocked. --- src/thread_utils.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'src') 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 @@ -6,6 +6,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 +struct MemoizedLocked { + + MemoizedLocked(Fn callback, T value = {}) : + m_Fn{ callback }, m_Value{ std::move(value) } { } + + template + 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)... ); + m_NeedUpdating.store(false); + } + } + return m_Value; + } + + void invalidate() const { + m_NeedUpdating.store(true); + } + +private: + mutable std::mutex m_Mutex; + mutable std::atomic 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. -- cgit v1.3.1