1 #ifndef SRC_NODE_THREADSAFE_COW_H_ 2 #define SRC_NODE_THREADSAFE_COW_H_ 3 4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 5 6 #include "util.h" 7 #include "uv.h" 8 9 #include <memory> // std::shared_ptr<T> 10 #include <utility> // std::forward<T> 11 12 namespace node { 13 14 // Copy-on-write utility. Not threadsafe, i.e. there is no synchronization 15 // of the copy operation with other operations. 16 template <typename T> 17 class CopyOnWrite final { 18 public: 19 template <typename... Args> CopyOnWrite(Args &&...args)20 explicit CopyOnWrite(Args&&... args) 21 : data_(std::make_shared<T>(std::forward<Args>(args)...)) {} 22 23 CopyOnWrite(const CopyOnWrite<T>& other) = default; 24 CopyOnWrite& operator=(const CopyOnWrite<T>& other) = default; 25 CopyOnWrite(CopyOnWrite<T>&& other) = default; 26 CopyOnWrite& operator=(CopyOnWrite<T>&& other) = default; 27 read()28 const T* read() const { return data_.get(); } 29 T* write(); 30 31 const T& operator*() const { return *read(); } 32 const T* operator->() const { return read(); } 33 34 private: 35 std::shared_ptr<T> data_; 36 }; 37 38 // Threadsafe copy-on-write utility. Consumers need to use the Read and 39 // Write helpers to access the target data structure. 40 template <typename T> 41 class ThreadsafeCopyOnWrite final { 42 private: 43 // Define this early since some of the public members depend on it 44 // and some compilers need it to be defined first in that case. 45 struct Impl { ImplImpl46 explicit Impl(const T& data) : data(data) {} ImplImpl47 explicit Impl(T&& data) : data(std::move(data)) {} 48 49 Impl(const Impl& other); 50 Impl& operator=(const Impl& other) = delete; 51 Impl(Impl&& other) = delete; 52 Impl& operator=(Impl&& other) = delete; 53 54 RwLock mutex; 55 T data; 56 }; 57 58 public: 59 template <typename... Args> ThreadsafeCopyOnWrite(Args &&...args)60 ThreadsafeCopyOnWrite(Args&&... args) 61 : impl_(T(std::forward<Args>(args)...)) {} 62 63 ThreadsafeCopyOnWrite(const ThreadsafeCopyOnWrite<T>& other) = default; 64 ThreadsafeCopyOnWrite& operator=(const ThreadsafeCopyOnWrite<T>& other) = 65 default; 66 ThreadsafeCopyOnWrite(ThreadsafeCopyOnWrite<T>&& other) = default; 67 ThreadsafeCopyOnWrite& operator=(ThreadsafeCopyOnWrite<T>&& other) = default; 68 69 class Read { 70 public: 71 explicit Read(const ThreadsafeCopyOnWrite<T>* cow); 72 73 const T& operator*() const; 74 const T* operator->() const; 75 76 private: 77 const ThreadsafeCopyOnWrite<T>* cow_; 78 RwLock::ScopedReadLock lock_; 79 }; 80 81 class Write { 82 public: 83 explicit Write(ThreadsafeCopyOnWrite<T>* cow); 84 85 T& operator*(); 86 T* operator->(); 87 88 private: 89 ThreadsafeCopyOnWrite<T>* cow_; 90 typename ThreadsafeCopyOnWrite<T>::Impl* impl_; 91 RwLock::ScopedLock lock_; 92 }; 93 read()94 Read read() const { return Read(this); } write()95 Write write() { return Write(this); } 96 97 private: 98 CopyOnWrite<Impl> impl_; 99 }; 100 101 } // namespace node 102 103 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 104 105 #endif // SRC_NODE_THREADSAFE_COW_H_ 106