xref: /aosp_15_r20/external/angle/src/common/SynchronizedValue.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // SynchronizedValue.h:
7 //   A class that ensures that the correct mutex is locked when the encapsulated data is accessed.
8 //   Based on boost::synchronized_value, which probably becomes part of the next C++ standard.
9 // https://www.boost.org/doc/libs/1_76_0/doc/html/thread/sds.html#thread.sds.synchronized_valuesxxx
10 
11 #ifndef COMMON_SYNCHRONIZEDVALUE_H_
12 #define COMMON_SYNCHRONIZEDVALUE_H_
13 
14 #include "common/SimpleMutex.h"
15 #include "common/debug.h"
16 
17 #include <mutex>
18 #include <type_traits>
19 
20 namespace angle
21 {
22 
23 template <typename T, typename Lockable = angle::SimpleMutex>
24 class ConstStrictLockPtr
25 {
26   public:
27     using value_type = T;
28     using mutex_type = Lockable;
29 
ConstStrictLockPtr(const T & value,Lockable & mutex)30     ConstStrictLockPtr(const T &value, Lockable &mutex) : mLock(mutex), mValue(value) {}
ConstStrictLockPtr(const T & value,Lockable & mutex,std::adopt_lock_t)31     ConstStrictLockPtr(const T &value, Lockable &mutex, std::adopt_lock_t) noexcept
32         : mLock(mutex, std::adopt_lock), mValue(value)
33     {}
34 
ConstStrictLockPtr(ConstStrictLockPtr && other)35     ConstStrictLockPtr(ConstStrictLockPtr &&other) noexcept
36         : mLock(std::move(other.mLock)), mValue(other.mValue)
37     {}
38 
39     ConstStrictLockPtr(const ConstStrictLockPtr &)            = delete;
40     ConstStrictLockPtr &operator=(const ConstStrictLockPtr &) = delete;
41 
42     ~ConstStrictLockPtr() = default;
43 
44     const T *operator->() const { return &mValue; }
45     const T &operator*() const { return mValue; }
46 
47   protected:
48     std::unique_lock<Lockable> mLock;
49     T const &mValue;
50 };
51 
52 template <typename T, typename Lockable = angle::SimpleMutex>
53 class StrictLockPtr : public ConstStrictLockPtr<T, Lockable>
54 {
55   private:
56     using BaseType = ConstStrictLockPtr<T, Lockable>;
57 
58   public:
StrictLockPtr(T & value,Lockable & mutex)59     StrictLockPtr(T &value, Lockable &mutex) : BaseType(value, mutex) {}
StrictLockPtr(T & value,Lockable & mutex,std::adopt_lock_t)60     StrictLockPtr(T &value, Lockable &mutex, std::adopt_lock_t) noexcept
61         : BaseType(value, mutex, std::adopt_lock)
62     {}
63 
StrictLockPtr(StrictLockPtr && other)64     StrictLockPtr(StrictLockPtr &&other) noexcept
65         : BaseType(std::move(static_cast<BaseType &&>(other)))
66     {}
67 
68     StrictLockPtr(const StrictLockPtr &)            = delete;
69     StrictLockPtr &operator=(const StrictLockPtr &) = delete;
70 
71     ~StrictLockPtr() = default;
72 
73     T *operator->() { return const_cast<T *>(&this->mValue); }
74     T &operator*() { return const_cast<T &>(this->mValue); }
75 };
76 
77 template <typename SV>
78 struct SynchronizedValueStrictLockPtr
79 {
80     using type = StrictLockPtr<typename SV::value_type, typename SV::mutex_type>;
81 };
82 
83 template <typename SV>
84 struct SynchronizedValueStrictLockPtr<const SV>
85 {
86     using type = ConstStrictLockPtr<typename SV::value_type, typename SV::mutex_type>;
87 };
88 
89 template <typename T, typename Lockable = angle::SimpleMutex>
90 class ConstUniqueLockPtr : public std::unique_lock<Lockable>
91 {
92   private:
93     using BaseType = std::unique_lock<Lockable>;
94 
95   public:
96     using value_type = T;
97     using mutex_type = Lockable;
98 
99     ConstUniqueLockPtr(const T &value, Lockable &mutex) : BaseType(mutex), mValue(value) {}
100     ConstUniqueLockPtr(const T &value, Lockable &mutex, std::adopt_lock_t) noexcept
101         : BaseType(mutex, std::adopt_lock), mValue(value)
102     {}
103     ConstUniqueLockPtr(const T &value, Lockable &mutex, std::defer_lock_t) noexcept
104         : BaseType(mutex, std::defer_lock), mValue(value)
105     {}
106     ConstUniqueLockPtr(const T &value, Lockable &mutex, std::try_to_lock_t) noexcept
107         : BaseType(mutex, std::try_to_lock), mValue(value)
108     {}
109 
110     ConstUniqueLockPtr(ConstUniqueLockPtr &&other) noexcept
111         : BaseType(std::move(static_cast<BaseType &&>(other))), mValue(other.mValue)
112     {}
113 
114     ConstUniqueLockPtr(const ConstUniqueLockPtr &)            = delete;
115     ConstUniqueLockPtr &operator=(const ConstUniqueLockPtr &) = delete;
116 
117     ~ConstUniqueLockPtr() = default;
118 
119     const T *operator->() const
120     {
121         ASSERT(this->owns_lock());
122         return &mValue;
123     }
124     const T &operator*() const
125     {
126         ASSERT(this->owns_lock());
127         return mValue;
128     }
129 
130   protected:
131     T const &mValue;
132 };
133 
134 template <typename T, typename Lockable = angle::SimpleMutex>
135 class UniqueLockPtr : public ConstUniqueLockPtr<T, Lockable>
136 {
137   private:
138     using BaseType = ConstUniqueLockPtr<T, Lockable>;
139 
140   public:
141     UniqueLockPtr(T &value, Lockable &mutex) : BaseType(value, mutex) {}
142     UniqueLockPtr(T &value, Lockable &mutex, std::adopt_lock_t) noexcept
143         : BaseType(value, mutex, std::adopt_lock)
144     {}
145     UniqueLockPtr(T &value, Lockable &mutex, std::defer_lock_t) noexcept
146         : BaseType(value, mutex, std::defer_lock)
147     {}
148     UniqueLockPtr(T &value, Lockable &mutex, std::try_to_lock_t) noexcept
149         : BaseType(value, mutex, std::try_to_lock)
150     {}
151 
152     UniqueLockPtr(UniqueLockPtr &&other) noexcept
153         : BaseType(std::move(static_cast<BaseType &&>(other)))
154     {}
155 
156     UniqueLockPtr(const UniqueLockPtr &)            = delete;
157     UniqueLockPtr &operator=(const UniqueLockPtr &) = delete;
158 
159     ~UniqueLockPtr() = default;
160 
161     T *operator->()
162     {
163         ASSERT(this->owns_lock());
164         return const_cast<T *>(&this->mValue);
165     }
166     T &operator*()
167     {
168         ASSERT(this->owns_lock());
169         return const_cast<T &>(this->mValue);
170     }
171 };
172 
173 template <typename SV>
174 struct SynchronizedValueUniqueLockPtr
175 {
176     using type = UniqueLockPtr<typename SV::value_type, typename SV::mutex_type>;
177 };
178 
179 template <typename SV>
180 struct SynchronizedValueUniqueLockPtr<const SV>
181 {
182     using type = ConstUniqueLockPtr<typename SV::value_type, typename SV::mutex_type>;
183 };
184 
185 template <typename T, typename Lockable = angle::SimpleMutex>
186 class SynchronizedValue
187 {
188   public:
189     using value_type = T;
190     using mutex_type = Lockable;
191 
192     SynchronizedValue() noexcept(std::is_nothrow_default_constructible<T>::value) : mValue() {}
193 
194     SynchronizedValue(const T &other) noexcept(std::is_nothrow_copy_constructible<T>::value)
195         : mValue(other)
196     {}
197 
198     SynchronizedValue(T &&other) noexcept(std::is_nothrow_move_constructible<T>::value)
199         : mValue(std::move(other))
200     {}
201 
202     template <typename... Args>
203     SynchronizedValue(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...)))
204         : mValue(std::forward<Args>(args)...)
205     {}
206 
207     SynchronizedValue(const SynchronizedValue &other)
208     {
209         std::lock_guard<Lockable> lock(other.mMutex);
210         mValue = other.mValue;
211     }
212 
213     SynchronizedValue(SynchronizedValue &&other)
214     {
215         std::lock_guard<Lockable> lock(other.mMutex);
216         mValue = std::move(other.mValue);
217     }
218 
219     SynchronizedValue &operator=(const SynchronizedValue &other)
220     {
221         if (&other != this)
222         {
223             std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);
224             std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);
225             std::lock(lock1, lock2);
226             mValue = other.mValue;
227         }
228         return *this;
229     }
230 
231     SynchronizedValue &operator=(SynchronizedValue &&other)
232     {
233         if (&other != this)
234         {
235             std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);
236             std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);
237             std::lock(lock1, lock2);
238             mValue = std::move(other.mValue);
239         }
240         return *this;
241     }
242 
243     SynchronizedValue &operator=(const T &value)
244     {
245         {
246             std::lock_guard<Lockable> lock(mMutex);
247             mValue = value;
248         }
249         return *this;
250     }
251 
252     SynchronizedValue &operator=(T &&value)
253     {
254         {
255             std::lock_guard<Lockable> lock(mMutex);
256             mValue = std::move(value);
257         }
258         return *this;
259     }
260 
261     T get() const
262     {
263         std::lock_guard<Lockable> lock(mMutex);
264         return mValue;
265     }
266 
267     explicit operator T() const { return get(); }
268 
269     void swap(SynchronizedValue &other)
270     {
271         if (this == &other)
272         {
273             return;
274         }
275         std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);
276         std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);
277         std::lock(lock1, lock2);
278         std::swap(mValue, other.mValue);
279     }
280 
281     void swap(T &other)
282     {
283         std::lock_guard<Lockable> lock(mMutex);
284         std::swap(mValue, other);
285     }
286 
287     StrictLockPtr<T, Lockable> operator->() { return StrictLockPtr<T, Lockable>(mValue, mMutex); }
288     ConstStrictLockPtr<T, Lockable> operator->() const
289     {
290         return ConstStrictLockPtr<T, Lockable>(mValue, mMutex);
291     }
292 
293     StrictLockPtr<T, Lockable> synchronize() { return StrictLockPtr<T, Lockable>(mValue, mMutex); }
294     ConstStrictLockPtr<T, Lockable> synchronize() const
295     {
296         return ConstStrictLockPtr<T, Lockable>(mValue, mMutex);
297     }
298 
299     UniqueLockPtr<T, Lockable> unique_synchronize()
300     {
301         return UniqueLockPtr<T, Lockable>(mValue, mMutex);
302     }
303     ConstUniqueLockPtr<T, Lockable> unique_synchronize() const
304     {
305         return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex);
306     }
307 
308     UniqueLockPtr<T, Lockable> defer_synchronize() noexcept
309     {
310         return UniqueLockPtr<T, Lockable>(mValue, mMutex, std::defer_lock);
311     }
312     ConstUniqueLockPtr<T, Lockable> defer_synchronize() const noexcept
313     {
314         return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex, std::defer_lock);
315     }
316 
317     UniqueLockPtr<T, Lockable> try_to_synchronize() noexcept
318     {
319         return UniqueLockPtr<T, Lockable>(mValue, mMutex, std::try_to_lock);
320     }
321     ConstUniqueLockPtr<T, Lockable> try_to_synchronize() const noexcept
322     {
323         return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex, std::try_to_lock);
324     }
325 
326     UniqueLockPtr<T, Lockable> adopt_synchronize() noexcept
327     {
328         return UniqueLockPtr<T, Lockable>(mValue, mMutex, std::adopt_lock);
329     }
330     ConstUniqueLockPtr<T, Lockable> adopt_synchronize() const noexcept
331     {
332         return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex, std::adopt_lock);
333     }
334 
335     class DerefValue
336     {
337       public:
338         DerefValue(DerefValue &&other) : mLock(std::move(other.mLock)), mValue(other.mValue) {}
339 
340         DerefValue(const DerefValue &)            = delete;
341         DerefValue &operator=(const DerefValue &) = delete;
342 
343         operator T &() { return mValue; }
344 
345         DerefValue &operator=(const T &other)
346         {
347             mValue = other;
348             return *this;
349         }
350 
351       private:
352         explicit DerefValue(SynchronizedValue &outer) : mLock(outer.mMutex), mValue(outer.mValue) {}
353 
354         std::unique_lock<Lockable> mLock;
355         T &mValue;
356 
357         friend class SynchronizedValue;
358     };
359 
360     class ConstDerefValue
361     {
362       public:
363         ConstDerefValue(ConstDerefValue &&other)
364             : mLock(std::move(other.mLock)), mValue(other.mValue)
365         {}
366 
367         ConstDerefValue(const ConstDerefValue &)            = delete;
368         ConstDerefValue &operator=(const ConstDerefValue &) = delete;
369 
370         operator const T &() { return mValue; }
371 
372       private:
373         explicit ConstDerefValue(const SynchronizedValue &outer)
374             : mLock(outer.mMutex), mValue(outer.mValue)
375         {}
376 
377         std::unique_lock<Lockable> mLock;
378         const T &mValue;
379 
380         friend class SynchronizedValue;
381     };
382 
383     DerefValue operator*() { return DerefValue(*this); }
384     ConstDerefValue operator*() const { return ConstDerefValue(*this); }
385 
386     template <typename OStream>
387     void save(OStream &os) const
388     {
389         std::lock_guard<Lockable> lock(mMutex);
390         os << mValue;
391     }
392 
393     template <typename IStream>
394     void load(IStream &is)
395     {
396         std::lock_guard<Lockable> lock(mMutex);
397         is >> mValue;
398     }
399 
400     bool operator==(const SynchronizedValue &other) const
401     {
402         std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);
403         std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);
404         std::lock(lock1, lock2);
405         return mValue == other.mValue;
406     }
407 
408     bool operator!=(const SynchronizedValue &other) const
409     {
410         std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);
411         std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);
412         std::lock(lock1, lock2);
413         return mValue != other.mValue;
414     }
415 
416     bool operator<(const SynchronizedValue &other) const
417     {
418         std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);
419         std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);
420         std::lock(lock1, lock2);
421         return mValue < other.mValue;
422     }
423 
424     bool operator>(const SynchronizedValue &other) const
425     {
426         std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);
427         std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);
428         std::lock(lock1, lock2);
429         return mValue > other.mValue;
430     }
431 
432     bool operator<=(const SynchronizedValue &other) const
433     {
434         std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);
435         std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);
436         std::lock(lock1, lock2);
437         return mValue <= other.mValue;
438     }
439 
440     bool operator>=(const SynchronizedValue &other) const
441     {
442         std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);
443         std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);
444         std::lock(lock1, lock2);
445         return mValue >= other.mValue;
446     }
447 
448     bool operator==(const T &other) const
449     {
450         std::lock_guard<Lockable> lock(mMutex);
451         return mValue == other;
452     }
453 
454     bool operator!=(const T &other) const
455     {
456         std::lock_guard<Lockable> lock(mMutex);
457         return mValue != other;
458     }
459 
460     bool operator<(const T &other) const
461     {
462         std::lock_guard<Lockable> lock(mMutex);
463         return mValue < other;
464     }
465 
466     bool operator>(const T &other) const
467     {
468         std::lock_guard<Lockable> lock(mMutex);
469         return mValue > other;
470     }
471 
472     bool operator<=(const T &other) const
473     {
474         std::lock_guard<Lockable> lock(mMutex);
475         return mValue <= other;
476     }
477 
478     bool operator>=(const T &other) const
479     {
480         std::lock_guard<Lockable> lock(mMutex);
481         return mValue >= other;
482     }
483 
484   private:
485     T mValue;
486     mutable Lockable mMutex;
487 };
488 
489 template <typename OStream, typename T, typename L>
490 inline OStream &operator<<(OStream &os, SynchronizedValue<T, L> const &sv)
491 {
492     sv.save(os);
493     return os;
494 }
495 
496 template <typename IStream, typename T, typename L>
497 inline IStream &operator>>(IStream &is, SynchronizedValue<T, L> &sv)
498 {
499     sv.load(is);
500     return is;
501 }
502 
503 template <typename T, typename L>
504 bool operator==(const T &lhs, const SynchronizedValue<T, L> &rhs)
505 {
506     return rhs == lhs;
507 }
508 
509 template <typename T, typename L>
510 bool operator!=(const T &lhs, const SynchronizedValue<T, L> &rhs)
511 {
512     return rhs != lhs;
513 }
514 
515 template <typename T, typename L>
516 bool operator<(const T &lhs, const SynchronizedValue<T, L> &rhs)
517 {
518     return rhs < lhs;
519 }
520 
521 template <typename T, typename L>
522 bool operator>(const T &lhs, const SynchronizedValue<T, L> &rhs)
523 {
524     return rhs > lhs;
525 }
526 
527 template <typename T, typename L>
528 bool operator<=(const T &lhs, const SynchronizedValue<T, L> &rhs)
529 {
530     return rhs <= lhs;
531 }
532 
533 template <typename T, typename L>
534 bool operator>=(const T &lhs, const SynchronizedValue<T, L> &rhs)
535 {
536     return rhs >= lhs;
537 }
538 
539 }  // namespace angle
540 
541 #endif  // COMMON_SYNCHRONIZEDVALUE_H_
542