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
12namespace node {
13
14// Copy-on-write utility. Not threadsafe, i.e. there is no synchronization
15// of the copy operation with other operations.
16template <typename T>
17class CopyOnWrite final {
18 public:
19  template <typename... 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
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.
40template <typename T>
41class 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 {
46    explicit Impl(const T& data) : data(data) {}
47    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>
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
94  Read read() const { return Read(this); }
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