From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- gfx/angle/checkout/src/common/SynchronizedValue.h | 540 ++++++++++++++++++++++ 1 file changed, 540 insertions(+) create mode 100644 gfx/angle/checkout/src/common/SynchronizedValue.h (limited to 'gfx/angle/checkout/src/common/SynchronizedValue.h') diff --git a/gfx/angle/checkout/src/common/SynchronizedValue.h b/gfx/angle/checkout/src/common/SynchronizedValue.h new file mode 100644 index 0000000000..95432cfbcd --- /dev/null +++ b/gfx/angle/checkout/src/common/SynchronizedValue.h @@ -0,0 +1,540 @@ +// +// Copyright 2021 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SynchronizedValue.h: +// A class that ensures that the correct mutex is locked when the encapsulated data is accessed. +// Based on boost::synchronized_value, which probably becomes part of the next C++ standard. +// https://www.boost.org/doc/libs/1_76_0/doc/html/thread/sds.html#thread.sds.synchronized_valuesxxx + +#ifndef COMMON_SYNCHRONIZEDVALUE_H_ +#define COMMON_SYNCHRONIZEDVALUE_H_ + +#include "common/debug.h" + +#include +#include + +namespace angle +{ + +template +class ConstStrictLockPtr +{ + public: + using value_type = T; + using mutex_type = Lockable; + + ConstStrictLockPtr(const T &value, Lockable &mutex) : mLock(mutex), mValue(value) {} + ConstStrictLockPtr(const T &value, Lockable &mutex, std::adopt_lock_t) noexcept + : mLock(mutex, std::adopt_lock), mValue(value) + {} + + ConstStrictLockPtr(ConstStrictLockPtr &&other) noexcept + : mLock(std::move(other.mLock)), mValue(other.mValue) + {} + + ConstStrictLockPtr(const ConstStrictLockPtr &) = delete; + ConstStrictLockPtr &operator=(const ConstStrictLockPtr &) = delete; + + ~ConstStrictLockPtr() = default; + + const T *operator->() const { return &mValue; } + const T &operator*() const { return mValue; } + + protected: + std::unique_lock mLock; + T const &mValue; +}; + +template +class StrictLockPtr : public ConstStrictLockPtr +{ + private: + using BaseType = ConstStrictLockPtr; + + public: + StrictLockPtr(T &value, Lockable &mutex) : BaseType(value, mutex) {} + StrictLockPtr(T &value, Lockable &mutex, std::adopt_lock_t) noexcept + : BaseType(value, mutex, std::adopt_lock) + {} + + StrictLockPtr(StrictLockPtr &&other) noexcept + : BaseType(std::move(static_cast(other))) + {} + + StrictLockPtr(const StrictLockPtr &) = delete; + StrictLockPtr &operator=(const StrictLockPtr &) = delete; + + ~StrictLockPtr() = default; + + T *operator->() { return const_cast(&this->mValue); } + T &operator*() { return const_cast(this->mValue); } +}; + +template +struct SynchronizedValueStrictLockPtr +{ + using type = StrictLockPtr; +}; + +template +struct SynchronizedValueStrictLockPtr +{ + using type = ConstStrictLockPtr; +}; + +template +class ConstUniqueLockPtr : public std::unique_lock +{ + private: + using BaseType = std::unique_lock; + + public: + using value_type = T; + using mutex_type = Lockable; + + ConstUniqueLockPtr(const T &value, Lockable &mutex) : BaseType(mutex), mValue(value) {} + ConstUniqueLockPtr(const T &value, Lockable &mutex, std::adopt_lock_t) noexcept + : BaseType(mutex, std::adopt_lock), mValue(value) + {} + ConstUniqueLockPtr(const T &value, Lockable &mutex, std::defer_lock_t) noexcept + : BaseType(mutex, std::defer_lock), mValue(value) + {} + ConstUniqueLockPtr(const T &value, Lockable &mutex, std::try_to_lock_t) noexcept + : BaseType(mutex, std::try_to_lock), mValue(value) + {} + + ConstUniqueLockPtr(ConstUniqueLockPtr &&other) noexcept + : BaseType(std::move(static_cast(other))), mValue(other.mValue) + {} + + ConstUniqueLockPtr(const ConstUniqueLockPtr &) = delete; + ConstUniqueLockPtr &operator=(const ConstUniqueLockPtr &) = delete; + + ~ConstUniqueLockPtr() = default; + + const T *operator->() const + { + ASSERT(this->owns_lock()); + return &mValue; + } + const T &operator*() const + { + ASSERT(this->owns_lock()); + return mValue; + } + + protected: + T const &mValue; +}; + +template +class UniqueLockPtr : public ConstUniqueLockPtr +{ + private: + using BaseType = ConstUniqueLockPtr; + + public: + UniqueLockPtr(T &value, Lockable &mutex) : BaseType(value, mutex) {} + UniqueLockPtr(T &value, Lockable &mutex, std::adopt_lock_t) noexcept + : BaseType(value, mutex, std::adopt_lock) + {} + UniqueLockPtr(T &value, Lockable &mutex, std::defer_lock_t) noexcept + : BaseType(value, mutex, std::defer_lock) + {} + UniqueLockPtr(T &value, Lockable &mutex, std::try_to_lock_t) noexcept + : BaseType(value, mutex, std::try_to_lock) + {} + + UniqueLockPtr(UniqueLockPtr &&other) noexcept + : BaseType(std::move(static_cast(other))) + {} + + UniqueLockPtr(const UniqueLockPtr &) = delete; + UniqueLockPtr &operator=(const UniqueLockPtr &) = delete; + + ~UniqueLockPtr() = default; + + T *operator->() + { + ASSERT(this->owns_lock()); + return const_cast(&this->mValue); + } + T &operator*() + { + ASSERT(this->owns_lock()); + return const_cast(this->mValue); + } +}; + +template +struct SynchronizedValueUniqueLockPtr +{ + using type = UniqueLockPtr; +}; + +template +struct SynchronizedValueUniqueLockPtr +{ + using type = ConstUniqueLockPtr; +}; + +template +class SynchronizedValue +{ + public: + using value_type = T; + using mutex_type = Lockable; + + SynchronizedValue() noexcept(std::is_nothrow_default_constructible::value) : mValue() {} + + SynchronizedValue(const T &other) noexcept(std::is_nothrow_copy_constructible::value) + : mValue(other) + {} + + SynchronizedValue(T &&other) noexcept(std::is_nothrow_move_constructible::value) + : mValue(std::move(other)) + {} + + template + SynchronizedValue(Args &&... args) noexcept(noexcept(T(std::forward(args)...))) + : mValue(std::forward(args)...) + {} + + SynchronizedValue(const SynchronizedValue &other) + { + std::lock_guard lock(other.mMutex); + mValue = other.mValue; + } + + SynchronizedValue(SynchronizedValue &&other) + { + std::lock_guard lock(other.mMutex); + mValue = std::move(other.mValue); + } + + SynchronizedValue &operator=(const SynchronizedValue &other) + { + if (&other != this) + { + std::unique_lock lock1(mMutex, std::defer_lock); + std::unique_lock lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + mValue = other.mValue; + } + return *this; + } + + SynchronizedValue &operator=(SynchronizedValue &&other) + { + if (&other != this) + { + std::unique_lock lock1(mMutex, std::defer_lock); + std::unique_lock lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + mValue = std::move(other.mValue); + } + return *this; + } + + SynchronizedValue &operator=(const T &value) + { + { + std::lock_guard lock(mMutex); + mValue = value; + } + return *this; + } + + SynchronizedValue &operator=(T &&value) + { + { + std::lock_guard lock(mMutex); + mValue = std::move(value); + } + return *this; + } + + T get() const + { + std::lock_guard lock(mMutex); + return mValue; + } + + explicit operator T() const { return get(); } + + void swap(SynchronizedValue &other) + { + if (this == &other) + { + return; + } + std::unique_lock lock1(mMutex, std::defer_lock); + std::unique_lock lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + std::swap(mValue, other.mValue); + } + + void swap(T &other) + { + std::lock_guard lock(mMutex); + std::swap(mValue, other); + } + + StrictLockPtr operator->() { return StrictLockPtr(mValue, mMutex); } + ConstStrictLockPtr operator->() const + { + return ConstStrictLockPtr(mValue, mMutex); + } + + StrictLockPtr synchronize() { return StrictLockPtr(mValue, mMutex); } + ConstStrictLockPtr synchronize() const + { + return ConstStrictLockPtr(mValue, mMutex); + } + + UniqueLockPtr unique_synchronize() + { + return UniqueLockPtr(mValue, mMutex); + } + ConstUniqueLockPtr unique_synchronize() const + { + return ConstUniqueLockPtr(mValue, mMutex); + } + + UniqueLockPtr defer_synchronize() noexcept + { + return UniqueLockPtr(mValue, mMutex, std::defer_lock); + } + ConstUniqueLockPtr defer_synchronize() const noexcept + { + return ConstUniqueLockPtr(mValue, mMutex, std::defer_lock); + } + + UniqueLockPtr try_to_synchronize() noexcept + { + return UniqueLockPtr(mValue, mMutex, std::try_to_lock); + } + ConstUniqueLockPtr try_to_synchronize() const noexcept + { + return ConstUniqueLockPtr(mValue, mMutex, std::try_to_lock); + } + + UniqueLockPtr adopt_synchronize() noexcept + { + return UniqueLockPtr(mValue, mMutex, std::adopt_lock); + } + ConstUniqueLockPtr adopt_synchronize() const noexcept + { + return ConstUniqueLockPtr(mValue, mMutex, std::adopt_lock); + } + + class DerefValue + { + public: + DerefValue(DerefValue &&other) : mLock(std::move(other.mLock)), mValue(other.mValue) {} + + DerefValue(const DerefValue &) = delete; + DerefValue &operator=(const DerefValue &) = delete; + + operator T &() { return mValue; } + + DerefValue &operator=(const T &other) + { + mValue = other; + return *this; + } + + private: + explicit DerefValue(SynchronizedValue &outer) : mLock(outer.mMutex), mValue(outer.mValue) {} + + std::unique_lock mLock; + T &mValue; + + friend class SynchronizedValue; + }; + + class ConstDerefValue + { + public: + ConstDerefValue(ConstDerefValue &&other) + : mLock(std::move(other.mLock)), mValue(other.mValue) + {} + + ConstDerefValue(const ConstDerefValue &) = delete; + ConstDerefValue &operator=(const ConstDerefValue &) = delete; + + operator const T &() { return mValue; } + + private: + explicit ConstDerefValue(const SynchronizedValue &outer) + : mLock(outer.mMutex), mValue(outer.mValue) + {} + + std::unique_lock mLock; + const T &mValue; + + friend class SynchronizedValue; + }; + + DerefValue operator*() { return DerefValue(*this); } + ConstDerefValue operator*() const { return ConstDerefValue(*this); } + + template + void save(OStream &os) const + { + std::lock_guard lock(mMutex); + os << mValue; + } + + template + void load(IStream &is) + { + std::lock_guard lock(mMutex); + is >> mValue; + } + + bool operator==(const SynchronizedValue &other) const + { + std::unique_lock lock1(mMutex, std::defer_lock); + std::unique_lock lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue == other.mValue; + } + + bool operator!=(const SynchronizedValue &other) const + { + std::unique_lock lock1(mMutex, std::defer_lock); + std::unique_lock lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue != other.mValue; + } + + bool operator<(const SynchronizedValue &other) const + { + std::unique_lock lock1(mMutex, std::defer_lock); + std::unique_lock lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue < other.mValue; + } + + bool operator>(const SynchronizedValue &other) const + { + std::unique_lock lock1(mMutex, std::defer_lock); + std::unique_lock lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue > other.mValue; + } + + bool operator<=(const SynchronizedValue &other) const + { + std::unique_lock lock1(mMutex, std::defer_lock); + std::unique_lock lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue <= other.mValue; + } + + bool operator>=(const SynchronizedValue &other) const + { + std::unique_lock lock1(mMutex, std::defer_lock); + std::unique_lock lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue >= other.mValue; + } + + bool operator==(const T &other) const + { + std::lock_guard lock(mMutex); + return mValue == other; + } + + bool operator!=(const T &other) const + { + std::lock_guard lock(mMutex); + return mValue != other; + } + + bool operator<(const T &other) const + { + std::lock_guard lock(mMutex); + return mValue < other; + } + + bool operator>(const T &other) const + { + std::lock_guard lock(mMutex); + return mValue > other; + } + + bool operator<=(const T &other) const + { + std::lock_guard lock(mMutex); + return mValue <= other; + } + + bool operator>=(const T &other) const + { + std::lock_guard lock(mMutex); + return mValue >= other; + } + + private: + T mValue; + mutable Lockable mMutex; +}; + +template +inline OStream &operator<<(OStream &os, SynchronizedValue const &sv) +{ + sv.save(os); + return os; +} + +template +inline IStream &operator>>(IStream &is, SynchronizedValue &sv) +{ + sv.load(is); + return is; +} + +template +bool operator==(const T &lhs, const SynchronizedValue &rhs) +{ + return rhs == lhs; +} + +template +bool operator!=(const T &lhs, const SynchronizedValue &rhs) +{ + return rhs != lhs; +} + +template +bool operator<(const T &lhs, const SynchronizedValue &rhs) +{ + return rhs < lhs; +} + +template +bool operator>(const T &lhs, const SynchronizedValue &rhs) +{ + return rhs > lhs; +} + +template +bool operator<=(const T &lhs, const SynchronizedValue &rhs) +{ + return rhs <= lhs; +} + +template +bool operator>=(const T &lhs, const SynchronizedValue &rhs) +{ + return rhs >= lhs; +} + +} // namespace angle + +#endif // COMMON_SYNCHRONIZEDVALUE_H_ -- cgit v1.2.3