diff options
Diffstat (limited to 'gfx/angle/checkout/src/common/SynchronizedValue.h')
-rw-r--r-- | gfx/angle/checkout/src/common/SynchronizedValue.h | 540 |
1 files changed, 540 insertions, 0 deletions
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 <mutex> +#include <type_traits> + +namespace angle +{ + +template <typename T, typename Lockable = std::mutex> +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<Lockable> mLock; + T const &mValue; +}; + +template <typename T, typename Lockable = std::mutex> +class StrictLockPtr : public ConstStrictLockPtr<T, Lockable> +{ + private: + using BaseType = ConstStrictLockPtr<T, Lockable>; + + 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<BaseType &&>(other))) + {} + + StrictLockPtr(const StrictLockPtr &) = delete; + StrictLockPtr &operator=(const StrictLockPtr &) = delete; + + ~StrictLockPtr() = default; + + T *operator->() { return const_cast<T *>(&this->mValue); } + T &operator*() { return const_cast<T &>(this->mValue); } +}; + +template <typename SV> +struct SynchronizedValueStrictLockPtr +{ + using type = StrictLockPtr<typename SV::value_type, typename SV::mutex_type>; +}; + +template <typename SV> +struct SynchronizedValueStrictLockPtr<const SV> +{ + using type = ConstStrictLockPtr<typename SV::value_type, typename SV::mutex_type>; +}; + +template <typename T, typename Lockable = std::mutex> +class ConstUniqueLockPtr : public std::unique_lock<Lockable> +{ + private: + using BaseType = std::unique_lock<Lockable>; + + 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<BaseType &&>(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 <typename T, typename Lockable = std::mutex> +class UniqueLockPtr : public ConstUniqueLockPtr<T, Lockable> +{ + private: + using BaseType = ConstUniqueLockPtr<T, Lockable>; + + 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<BaseType &&>(other))) + {} + + UniqueLockPtr(const UniqueLockPtr &) = delete; + UniqueLockPtr &operator=(const UniqueLockPtr &) = delete; + + ~UniqueLockPtr() = default; + + T *operator->() + { + ASSERT(this->owns_lock()); + return const_cast<T *>(&this->mValue); + } + T &operator*() + { + ASSERT(this->owns_lock()); + return const_cast<T &>(this->mValue); + } +}; + +template <typename SV> +struct SynchronizedValueUniqueLockPtr +{ + using type = UniqueLockPtr<typename SV::value_type, typename SV::mutex_type>; +}; + +template <typename SV> +struct SynchronizedValueUniqueLockPtr<const SV> +{ + using type = ConstUniqueLockPtr<typename SV::value_type, typename SV::mutex_type>; +}; + +template <typename T, typename Lockable = std::mutex> +class SynchronizedValue +{ + public: + using value_type = T; + using mutex_type = Lockable; + + SynchronizedValue() noexcept(std::is_nothrow_default_constructible<T>::value) : mValue() {} + + SynchronizedValue(const T &other) noexcept(std::is_nothrow_copy_constructible<T>::value) + : mValue(other) + {} + + SynchronizedValue(T &&other) noexcept(std::is_nothrow_move_constructible<T>::value) + : mValue(std::move(other)) + {} + + template <typename... Args> + SynchronizedValue(Args &&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) + : mValue(std::forward<Args>(args)...) + {} + + SynchronizedValue(const SynchronizedValue &other) + { + std::lock_guard<Lockable> lock(other.mMutex); + mValue = other.mValue; + } + + SynchronizedValue(SynchronizedValue &&other) + { + std::lock_guard<Lockable> lock(other.mMutex); + mValue = std::move(other.mValue); + } + + SynchronizedValue &operator=(const SynchronizedValue &other) + { + if (&other != this) + { + std::unique_lock<Lockable> lock1(mMutex, std::defer_lock); + std::unique_lock<Lockable> 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<Lockable> lock1(mMutex, std::defer_lock); + std::unique_lock<Lockable> 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<Lockable> lock(mMutex); + mValue = value; + } + return *this; + } + + SynchronizedValue &operator=(T &&value) + { + { + std::lock_guard<Lockable> lock(mMutex); + mValue = std::move(value); + } + return *this; + } + + T get() const + { + std::lock_guard<Lockable> lock(mMutex); + return mValue; + } + + explicit operator T() const { return get(); } + + void swap(SynchronizedValue &other) + { + if (this == &other) + { + return; + } + std::unique_lock<Lockable> lock1(mMutex, std::defer_lock); + std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + std::swap(mValue, other.mValue); + } + + void swap(T &other) + { + std::lock_guard<Lockable> lock(mMutex); + std::swap(mValue, other); + } + + StrictLockPtr<T, Lockable> operator->() { return StrictLockPtr<T, Lockable>(mValue, mMutex); } + ConstStrictLockPtr<T, Lockable> operator->() const + { + return ConstStrictLockPtr<T, Lockable>(mValue, mMutex); + } + + StrictLockPtr<T, Lockable> synchronize() { return StrictLockPtr<T, Lockable>(mValue, mMutex); } + ConstStrictLockPtr<T, Lockable> synchronize() const + { + return ConstStrictLockPtr<T, Lockable>(mValue, mMutex); + } + + UniqueLockPtr<T, Lockable> unique_synchronize() + { + return UniqueLockPtr<T, Lockable>(mValue, mMutex); + } + ConstUniqueLockPtr<T, Lockable> unique_synchronize() const + { + return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex); + } + + UniqueLockPtr<T, Lockable> defer_synchronize() noexcept + { + return UniqueLockPtr<T, Lockable>(mValue, mMutex, std::defer_lock); + } + ConstUniqueLockPtr<T, Lockable> defer_synchronize() const noexcept + { + return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex, std::defer_lock); + } + + UniqueLockPtr<T, Lockable> try_to_synchronize() noexcept + { + return UniqueLockPtr<T, Lockable>(mValue, mMutex, std::try_to_lock); + } + ConstUniqueLockPtr<T, Lockable> try_to_synchronize() const noexcept + { + return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex, std::try_to_lock); + } + + UniqueLockPtr<T, Lockable> adopt_synchronize() noexcept + { + return UniqueLockPtr<T, Lockable>(mValue, mMutex, std::adopt_lock); + } + ConstUniqueLockPtr<T, Lockable> adopt_synchronize() const noexcept + { + return ConstUniqueLockPtr<T, Lockable>(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<Lockable> 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<Lockable> mLock; + const T &mValue; + + friend class SynchronizedValue; + }; + + DerefValue operator*() { return DerefValue(*this); } + ConstDerefValue operator*() const { return ConstDerefValue(*this); } + + template <typename OStream> + void save(OStream &os) const + { + std::lock_guard<Lockable> lock(mMutex); + os << mValue; + } + + template <typename IStream> + void load(IStream &is) + { + std::lock_guard<Lockable> lock(mMutex); + is >> mValue; + } + + bool operator==(const SynchronizedValue &other) const + { + std::unique_lock<Lockable> lock1(mMutex, std::defer_lock); + std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue == other.mValue; + } + + bool operator!=(const SynchronizedValue &other) const + { + std::unique_lock<Lockable> lock1(mMutex, std::defer_lock); + std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue != other.mValue; + } + + bool operator<(const SynchronizedValue &other) const + { + std::unique_lock<Lockable> lock1(mMutex, std::defer_lock); + std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue < other.mValue; + } + + bool operator>(const SynchronizedValue &other) const + { + std::unique_lock<Lockable> lock1(mMutex, std::defer_lock); + std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue > other.mValue; + } + + bool operator<=(const SynchronizedValue &other) const + { + std::unique_lock<Lockable> lock1(mMutex, std::defer_lock); + std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue <= other.mValue; + } + + bool operator>=(const SynchronizedValue &other) const + { + std::unique_lock<Lockable> lock1(mMutex, std::defer_lock); + std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock); + std::lock(lock1, lock2); + return mValue >= other.mValue; + } + + bool operator==(const T &other) const + { + std::lock_guard<Lockable> lock(mMutex); + return mValue == other; + } + + bool operator!=(const T &other) const + { + std::lock_guard<Lockable> lock(mMutex); + return mValue != other; + } + + bool operator<(const T &other) const + { + std::lock_guard<Lockable> lock(mMutex); + return mValue < other; + } + + bool operator>(const T &other) const + { + std::lock_guard<Lockable> lock(mMutex); + return mValue > other; + } + + bool operator<=(const T &other) const + { + std::lock_guard<Lockable> lock(mMutex); + return mValue <= other; + } + + bool operator>=(const T &other) const + { + std::lock_guard<Lockable> lock(mMutex); + return mValue >= other; + } + + private: + T mValue; + mutable Lockable mMutex; +}; + +template <typename OStream, typename T, typename L> +inline OStream &operator<<(OStream &os, SynchronizedValue<T, L> const &sv) +{ + sv.save(os); + return os; +} + +template <typename IStream, typename T, typename L> +inline IStream &operator>>(IStream &is, SynchronizedValue<T, L> &sv) +{ + sv.load(is); + return is; +} + +template <typename T, typename L> +bool operator==(const T &lhs, const SynchronizedValue<T, L> &rhs) +{ + return rhs == lhs; +} + +template <typename T, typename L> +bool operator!=(const T &lhs, const SynchronizedValue<T, L> &rhs) +{ + return rhs != lhs; +} + +template <typename T, typename L> +bool operator<(const T &lhs, const SynchronizedValue<T, L> &rhs) +{ + return rhs < lhs; +} + +template <typename T, typename L> +bool operator>(const T &lhs, const SynchronizedValue<T, L> &rhs) +{ + return rhs > lhs; +} + +template <typename T, typename L> +bool operator<=(const T &lhs, const SynchronizedValue<T, L> &rhs) +{ + return rhs <= lhs; +} + +template <typename T, typename L> +bool operator>=(const T &lhs, const SynchronizedValue<T, L> &rhs) +{ + return rhs >= lhs; +} + +} // namespace angle + +#endif // COMMON_SYNCHRONIZEDVALUE_H_ |