File indexing completed on 2024-05-12 15:57:03
0001 /* 0002 * SPDX-FileCopyrightText: 2018 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef KISLAZYSTORAGE_H 0008 #define KISLAZYSTORAGE_H 0009 0010 #include <functional> 0011 #include <memory> 0012 #include <atomic> 0013 0014 #include <QMutex> 0015 #include <QMutexLocker> 0016 #include "KisMpl.h" 0017 0018 /** 0019 * KisLazyStorage is a special class implementing some kind 0020 * of lazy evaluation. It mimics the behaviorof a normal 0021 * pointer type, but creates `T` only on the first trt to 0022 * dereference this pointer. 0023 */ 0024 template <typename T, typename... Args> 0025 class KisLazyStorage 0026 { 0027 public: 0028 struct init_value_tag { explicit init_value_tag() = default; }; 0029 0030 /** 0031 * Create a storage with a deferred creation of the object 0032 * `T`. The arguments \p args are passed to the constructor 0033 * of `T` on the first dereference operation on the storage. 0034 */ 0035 explicit KisLazyStorage(Args... args) 0036 : m_constructionArgs(std::forward<Args>(args)...), 0037 m_data(0) 0038 { 0039 } 0040 0041 /** 0042 * Create a storage and initialize it with \p value 0043 * right away without any deferring. Please take it into 0044 * account that the storage will still store a default- 0045 * initialized values of types `Args...` in an internal 0046 * tuple. If you want to avoid this default-construction, 0047 * then just wrap the arguments into std::optional. 0048 */ 0049 explicit KisLazyStorage(init_value_tag, T &&value) 0050 : m_data(new T(std::forward<T>(value))) 0051 { 0052 } 0053 0054 KisLazyStorage(const KisLazyStorage &rgh) = delete; 0055 KisLazyStorage(KisLazyStorage &&rgh) = delete; 0056 0057 0058 ~KisLazyStorage() { 0059 delete m_data.load(); 0060 } 0061 0062 T* operator->() { 0063 return getPointer(); 0064 } 0065 0066 T& operator*() { 0067 return *getPointer(); 0068 } 0069 0070 private: 0071 T* getPointer() { 0072 if(!m_data) { 0073 QMutexLocker l(&m_mutex); 0074 if(!m_data) { 0075 m_data = kismpl::apply_r<T*>(&constructObject, m_constructionArgs); 0076 } 0077 } 0078 return m_data; 0079 } 0080 0081 static inline T* constructObject(Args... args) { 0082 return new T(std::forward<Args>(args)...); 0083 } 0084 0085 private: 0086 std::tuple<Args...> m_constructionArgs; 0087 std::atomic<T*> m_data; 0088 QMutex m_mutex; 0089 }; 0090 0091 #endif // KISLAZYSTORAGE_H