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