Ditto 4.13.1
 
Loading...
Searching...
No Matches
SynchronizedValue.hpp
1#ifndef DITTO_SYNCHRONIZEDVALUE_H
2#define DITTO_SYNCHRONIZEDVALUE_H
3
4#include <functional>
5#include <mutex>
6#include <type_traits>
7#include <utility>
8
9namespace ditto {
10
11// Elements in the ditto::internal namespace are not considered to be part of
12// the public Ditto C++ API, and may change at any time. Do not use them in
13// customer code.
14namespace internal {
15
16// Inspired by the proposal for a C++ std::synchronized_value<T> type
17// <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0290r3.html>
18// but compatible with C++11.
19
29template <class T, class Mutex = std::mutex> class SynchronizedValue {
30private:
31 mutable Mutex mtx;
32 T value;
33
34 template <class R_, class F_, class T_, class M_>
35 friend R_ apply(F_ &&f, SynchronizedValue<T_, M_> &sv);
36
37 template <class R_, class F_, class T_, class M_>
38 friend R_ apply(F_ &&f, const SynchronizedValue<T_, M_> &sv);
39
40 template <class F_, class T_, class M_>
41 friend void apply(F_ &&f, SynchronizedValue<T_, M_> &sv);
42
43 template <class F_, class T_, class M_>
44 friend void apply(F_ &&f, const SynchronizedValue<T_, M_> &sv);
45
46 template <class F_, class T_, class U_, class M_, class N_>
47 friend void apply(F_ &&f, SynchronizedValue<T_, M_> &lhs,
48 SynchronizedValue<U_, N_> &rhs);
49
50public:
51 using mutex_type = Mutex;
52 using value_type = T;
53
55 template <class U = T,
56 typename std::enable_if<std::is_default_constructible<U>::value,
57 int>::type = 0>
58 SynchronizedValue() : value() {}
59
62 SynchronizedValue(const T &desired) : value(desired) {}
63
66 SynchronizedValue(T &&desired) noexcept(
67 std::is_nothrow_move_constructible<T>::value)
68 : value(std::move(desired)) {}
69
70 ~SynchronizedValue() = default;
71
72 SynchronizedValue(const SynchronizedValue &) = delete;
73 SynchronizedValue &operator=(const SynchronizedValue &) = delete;
74 SynchronizedValue(SynchronizedValue &&) = delete;
75 SynchronizedValue &operator=(SynchronizedValue &&) = delete;
76
79 void apply(std::function<void(T &)> f) {
80 std::lock_guard<Mutex> lock(mtx);
81 f(value);
82 }
83
86 void apply(std::function<void(const T &)> f) const {
87 std::lock_guard<Mutex> lock(mtx);
88 f(value);
89 }
90
93 T get() const {
94 std::lock_guard<Mutex> lock(mtx);
95 return value;
96 }
97
101 T exchange(T new_value) {
102 std::lock_guard<Mutex> lock(mtx);
103 T old_value = std::move(value);
104 value = std::move(new_value);
105 return old_value;
106 }
107
110 void operator=(const T &desired) {
111 std::lock_guard<Mutex> lock(mtx);
112 value = desired;
113 }
114
117 void operator=(T &&desired) {
118 std::lock_guard<Mutex> lock(mtx);
119 value = std::move(desired);
120 }
121};
122
127template <class R, class F, class T, class M>
128R apply(F &&f, SynchronizedValue<T, M> &sv) {
129 std::lock_guard<M> lock(sv.mtx);
130 return f(sv.value);
131}
132
137template <class R, class F, class T, class M>
138R apply(F &&f, const SynchronizedValue<T, M> &sv) {
139 std::lock_guard<M> lock(sv.mtx);
140 return f(sv.value);
141}
142
147template <class F, class T, class M>
148void apply(F &&f, SynchronizedValue<T, M> &sv) {
149 std::lock_guard<M> lock(sv.mtx);
150 f(sv.value);
151}
152
157template <class F, class T, class M>
158void apply(F &&f, const SynchronizedValue<T, M> &sv) {
159 std::lock_guard<M> lock(sv.mtx);
160 f(sv.value);
161}
162
172template <class F, class T, class U, class M, class N>
173void apply(F &&f, SynchronizedValue<T, M> &lhs, SynchronizedValue<U, N> &rhs) {
174 if ((void *)&lhs == (void *)&rhs) {
175 // same object, so only lock once
176 std::lock_guard<M> lock(lhs.mtx);
177 f(lhs.value, rhs.value);
178 } else {
179 std::lock(lhs.mtx, rhs.mtx);
180 std::lock_guard<M> lock_lhs(lhs.mtx, std::adopt_lock);
181 std::lock_guard<N> lock_rhs(rhs.mtx, std::adopt_lock);
182 f(lhs.value, rhs.value);
183 }
184}
185
195template <class T, class M, class N>
196void swap(SynchronizedValue<T, M> &lhs, SynchronizedValue<T, N> &rhs) {
197 if ((void *)&lhs == (void *)&rhs) {
198 return;
199 }
200 apply([](T &a, T &b) { std::swap(a, b); }, lhs, rhs);
201}
202
203} // namespace internal
204
205} // namespace ditto
206
207#endif
Namespace for internal Ditto SDK functionality.
Definition Ditto.hpp:29
R apply(F &&f, SynchronizedValue< T, M > &sv)
Applies a function to the wrapped value of a SynchronizedValue.
Definition SynchronizedValue.hpp:128
void swap(SynchronizedValue< T, M > &lhs, SynchronizedValue< T, N > &rhs)
Swaps the values of two SynchronizedValue objects.
Definition SynchronizedValue.hpp:196
Namespace for the Ditto C++ SDK types and functions.
Definition AbstractDocumentPath.hpp:19