sandbox
Loading...
Searching...
No Matches
copy_on_write.hpp
1#ifndef LIBSBX_SIGNAL_COPY_ON_WRITE_HPP_
2#define LIBSBX_SIGNAL_COPY_ON_WRITE_HPP_
3
4#include <utility>
5#include <atomic>
6
7namespace sbx::signals {
8
9template<typename Type>
11
12 struct payload {
13
14 template<typename... Args>
15 explicit payload(Args&&... args)
16 : count{1},
17 value{std::forward<Args>(args)...} { }
18
19 ~payload() = default;
20
21 std::atomic<std::size_t> count;
22 Type value;
23
24 }; // struct payload
25
26 template<typename Other>
27 friend auto swap(copy_on_write<Other>& lhs, copy_on_write<Other>& rhs) noexcept -> void;
28
29public:
30
31 using value_type = Type;
32
34 : _payload{new payload{}} { }
35
36 template<typename Other>
37 requires (!std::is_same_v<std::decay_t<Other>, copy_on_write>)
38 explicit copy_on_write(Other&& other)
39 : _payload{new payload{std::forward<Other>(other)}} { }
40
41 copy_on_write(const copy_on_write& other) noexcept
42 : _payload{other._payload} {
43 if (_payload) {
44 _payload->count.fetch_add(1, std::memory_order_relaxed);
45 }
46 }
47
48 copy_on_write(copy_on_write&& other) noexcept
49 : _payload{std::exchange(other._payload, nullptr)} {}
50
52 _release();
53 }
54
55 auto operator=(const copy_on_write& other) noexcept -> copy_on_write& {
56 if (this != &other) {
57 _release();
58 _payload = other._payload;
59
60 if (_payload) {
61 _payload->count.fetch_add(1, std::memory_order_relaxed);
62 }
63 }
64
65 return *this;
66 }
67
68 auto operator=(copy_on_write&& other) noexcept -> copy_on_write& {
69 if (this != &other) {
70 _release();
71 _payload = std::exchange(other._payload, nullptr);
72 }
73
74 return *this;
75 }
76
77 auto read() const noexcept -> const value_type& {
78 return _payload->value;
79 }
80
81 auto write() -> value_type& {
82 if (!_is_unique()) {
83 *this = copy_on_write{read()};
84 }
85
86 return _payload->value;
87 }
88
89private:
90
91 auto _release() -> void {
92 if (_payload && _payload->count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
93 delete _payload;
94 }
95
96 _payload = nullptr;
97 }
98
99 auto _is_unique() const -> bool {
100 return _payload->count == 1;
101 }
102
103 payload* _payload;
104
105}; // class copy_on_write
106
107template<typename Type>
108inline auto swap(copy_on_write<Type>& lhs, copy_on_write<Type>& rhs) noexcept -> void {
109 using std::swap;
110 swap(lhs._payload, rhs._payload);
111}
112
113template<typename Type>
114auto cow_read(const Type& value) -> const Type& {
115 return value;
116}
117
118template<typename Type>
119auto cow_read(copy_on_write<Type>& value) -> const Type& {
120 return value.read();
121}
122
123template<typename Type>
124auto cow_write(Type& value) -> Type& {
125 return value;
126}
127
128template<typename Type>
129auto cow_write(copy_on_write<Type>& value) -> Type& {
130 return value.write();
131}
132
133} // namespace sbx::signals
134
135#endif // LIBSBX_SIGNAL_COPY_ON_WRITE_HPP_
Definition: copy_on_write.hpp:10