• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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