Path: blob/main_old/src/common/SynchronizedValue.h
1693 views
//1// Copyright 2021 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//5// SynchronizedValue.h:6// A class that ensures that the correct mutex is locked when the encapsulated data is accessed.7// Based on boost::synchronized_value, which probably becomes part of the next C++ standard.8// https://www.boost.org/doc/libs/1_76_0/doc/html/thread/sds.html#thread.sds.synchronized_valuesxxx910#ifndef COMMON_SYNCHRONIZEDVALUE_H_11#define COMMON_SYNCHRONIZEDVALUE_H_1213#include "common/debug.h"1415#include <mutex>16#include <type_traits>1718namespace angle19{2021template <typename T, typename Lockable = std::mutex>22class ConstStrictLockPtr23{24public:25using value_type = T;26using mutex_type = Lockable;2728ConstStrictLockPtr(const T &value, Lockable &mutex) : mLock(mutex), mValue(value) {}29ConstStrictLockPtr(const T &value, Lockable &mutex, std::adopt_lock_t) noexcept30: mLock(mutex, std::adopt_lock), mValue(value)31{}3233ConstStrictLockPtr(ConstStrictLockPtr &&other) noexcept34: mLock(std::move(other.mLock)), mValue(other.mValue)35{}3637ConstStrictLockPtr(const ConstStrictLockPtr &) = delete;38ConstStrictLockPtr &operator=(const ConstStrictLockPtr &) = delete;3940~ConstStrictLockPtr() = default;4142const T *operator->() const { return &mValue; }43const T &operator*() const { return mValue; }4445protected:46std::unique_lock<Lockable> mLock;47T const &mValue;48};4950template <typename T, typename Lockable = std::mutex>51class StrictLockPtr : public ConstStrictLockPtr<T, Lockable>52{53private:54using BaseType = ConstStrictLockPtr<T, Lockable>;5556public:57StrictLockPtr(T &value, Lockable &mutex) : BaseType(value, mutex) {}58StrictLockPtr(T &value, Lockable &mutex, std::adopt_lock_t) noexcept59: BaseType(value, mutex, std::adopt_lock)60{}6162StrictLockPtr(StrictLockPtr &&other) noexcept63: BaseType(std::move(static_cast<BaseType &&>(other)))64{}6566StrictLockPtr(const StrictLockPtr &) = delete;67StrictLockPtr &operator=(const StrictLockPtr &) = delete;6869~StrictLockPtr() = default;7071T *operator->() { return const_cast<T *>(&this->mValue); }72T &operator*() { return const_cast<T &>(this->mValue); }73};7475template <typename SV>76struct SynchronizedValueStrictLockPtr77{78using type = StrictLockPtr<typename SV::value_type, typename SV::mutex_type>;79};8081template <typename SV>82struct SynchronizedValueStrictLockPtr<const SV>83{84using type = ConstStrictLockPtr<typename SV::value_type, typename SV::mutex_type>;85};8687template <typename T, typename Lockable = std::mutex>88class ConstUniqueLockPtr : public std::unique_lock<Lockable>89{90private:91using BaseType = std::unique_lock<Lockable>;9293public:94using value_type = T;95using mutex_type = Lockable;9697ConstUniqueLockPtr(const T &value, Lockable &mutex) : BaseType(mutex), mValue(value) {}98ConstUniqueLockPtr(const T &value, Lockable &mutex, std::adopt_lock_t) noexcept99: BaseType(mutex, std::adopt_lock), mValue(value)100{}101ConstUniqueLockPtr(const T &value, Lockable &mutex, std::defer_lock_t) noexcept102: BaseType(mutex, std::defer_lock), mValue(value)103{}104ConstUniqueLockPtr(const T &value, Lockable &mutex, std::try_to_lock_t) noexcept105: BaseType(mutex, std::try_to_lock), mValue(value)106{}107108ConstUniqueLockPtr(ConstUniqueLockPtr &&other) noexcept109: BaseType(std::move(static_cast<BaseType &&>(other))), mValue(other.mValue)110{}111112ConstUniqueLockPtr(const ConstUniqueLockPtr &) = delete;113ConstUniqueLockPtr &operator=(const ConstUniqueLockPtr &) = delete;114115~ConstUniqueLockPtr() = default;116117const T *operator->() const118{119ASSERT(this->owns_lock());120return &mValue;121}122const T &operator*() const123{124ASSERT(this->owns_lock());125return mValue;126}127128protected:129T const &mValue;130};131132template <typename T, typename Lockable = std::mutex>133class UniqueLockPtr : public ConstUniqueLockPtr<T, Lockable>134{135private:136using BaseType = ConstUniqueLockPtr<T, Lockable>;137138public:139UniqueLockPtr(T &value, Lockable &mutex) : BaseType(value, mutex) {}140UniqueLockPtr(T &value, Lockable &mutex, std::adopt_lock_t) noexcept141: BaseType(value, mutex, std::adopt_lock)142{}143UniqueLockPtr(T &value, Lockable &mutex, std::defer_lock_t) noexcept144: BaseType(value, mutex, std::defer_lock)145{}146UniqueLockPtr(T &value, Lockable &mutex, std::try_to_lock_t) noexcept147: BaseType(value, mutex, std::try_to_lock)148{}149150UniqueLockPtr(UniqueLockPtr &&other) noexcept151: BaseType(std::move(static_cast<BaseType &&>(other)))152{}153154UniqueLockPtr(const UniqueLockPtr &) = delete;155UniqueLockPtr &operator=(const UniqueLockPtr &) = delete;156157~UniqueLockPtr() = default;158159T *operator->()160{161ASSERT(this->owns_lock());162return const_cast<T *>(&this->mValue);163}164T &operator*()165{166ASSERT(this->owns_lock());167return const_cast<T &>(this->mValue);168}169};170171template <typename SV>172struct SynchronizedValueUniqueLockPtr173{174using type = UniqueLockPtr<typename SV::value_type, typename SV::mutex_type>;175};176177template <typename SV>178struct SynchronizedValueUniqueLockPtr<const SV>179{180using type = ConstUniqueLockPtr<typename SV::value_type, typename SV::mutex_type>;181};182183template <typename T, typename Lockable = std::mutex>184class SynchronizedValue185{186public:187using value_type = T;188using mutex_type = Lockable;189190SynchronizedValue() noexcept(std::is_nothrow_default_constructible<T>::value) : mValue() {}191192SynchronizedValue(const T &other) noexcept(std::is_nothrow_copy_constructible<T>::value)193: mValue(other)194{}195196SynchronizedValue(T &&other) noexcept(std::is_nothrow_move_constructible<T>::value)197: mValue(std::move(other))198{}199200template <typename... Args>201SynchronizedValue(Args &&... args) noexcept(noexcept(T(std::forward<Args>(args)...)))202: mValue(std::forward<Args>(args)...)203{}204205SynchronizedValue(const SynchronizedValue &other)206{207std::lock_guard<Lockable> lock(other.mMutex);208mValue = other.mValue;209}210211SynchronizedValue(SynchronizedValue &&other)212{213std::lock_guard<Lockable> lock(other.mMutex);214mValue = std::move(other.mValue);215}216217SynchronizedValue &operator=(const SynchronizedValue &other)218{219if (&other != this)220{221std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);222std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);223std::lock(lock1, lock2);224mValue = other.mValue;225}226return *this;227}228229SynchronizedValue &operator=(SynchronizedValue &&other)230{231if (&other != this)232{233std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);234std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);235std::lock(lock1, lock2);236mValue = std::move(other.mValue);237}238return *this;239}240241SynchronizedValue &operator=(const T &value)242{243{244std::lock_guard<Lockable> lock(mMutex);245mValue = value;246}247return *this;248}249250SynchronizedValue &operator=(T &&value)251{252{253std::lock_guard<Lockable> lock(mMutex);254mValue = std::move(value);255}256return *this;257}258259T get() const260{261std::lock_guard<Lockable> lock(mMutex);262return mValue;263}264265explicit operator T() const { return get(); }266267void swap(SynchronizedValue &other)268{269if (this == &other)270{271return;272}273std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);274std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);275std::lock(lock1, lock2);276std::swap(mValue, other.mValue);277}278279void swap(T &other)280{281std::lock_guard<Lockable> lock(mMutex);282std::swap(mValue, other);283}284285StrictLockPtr<T, Lockable> operator->() { return StrictLockPtr<T, Lockable>(mValue, mMutex); }286ConstStrictLockPtr<T, Lockable> operator->() const287{288return ConstStrictLockPtr<T, Lockable>(mValue, mMutex);289}290291StrictLockPtr<T, Lockable> synchronize() { return StrictLockPtr<T, Lockable>(mValue, mMutex); }292ConstStrictLockPtr<T, Lockable> synchronize() const293{294return ConstStrictLockPtr<T, Lockable>(mValue, mMutex);295}296297UniqueLockPtr<T, Lockable> unique_synchronize()298{299return UniqueLockPtr<T, Lockable>(mValue, mMutex);300}301ConstUniqueLockPtr<T, Lockable> unique_synchronize() const302{303return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex);304}305306UniqueLockPtr<T, Lockable> defer_synchronize() noexcept307{308return UniqueLockPtr<T, Lockable>(mValue, mMutex, std::defer_lock);309}310ConstUniqueLockPtr<T, Lockable> defer_synchronize() const noexcept311{312return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex, std::defer_lock);313}314315UniqueLockPtr<T, Lockable> try_to_synchronize() noexcept316{317return UniqueLockPtr<T, Lockable>(mValue, mMutex, std::try_to_lock);318}319ConstUniqueLockPtr<T, Lockable> try_to_synchronize() const noexcept320{321return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex, std::try_to_lock);322}323324UniqueLockPtr<T, Lockable> adopt_synchronize() noexcept325{326return UniqueLockPtr<T, Lockable>(mValue, mMutex, std::adopt_lock);327}328ConstUniqueLockPtr<T, Lockable> adopt_synchronize() const noexcept329{330return ConstUniqueLockPtr<T, Lockable>(mValue, mMutex, std::adopt_lock);331}332333class DerefValue334{335public:336DerefValue(DerefValue &&other) : mLock(std::move(other.mLock)), mValue(other.mValue) {}337338DerefValue(const DerefValue &) = delete;339DerefValue &operator=(const DerefValue &) = delete;340341operator T &() { return mValue; }342343DerefValue &operator=(const T &other)344{345mValue = other;346return *this;347}348349private:350explicit DerefValue(SynchronizedValue &outer) : mLock(outer.mMutex), mValue(outer.mValue) {}351352std::unique_lock<Lockable> mLock;353T &mValue;354355friend class SynchronizedValue;356};357358class ConstDerefValue359{360public:361ConstDerefValue(ConstDerefValue &&other)362: mLock(std::move(other.mLock)), mValue(other.mValue)363{}364365ConstDerefValue(const ConstDerefValue &) = delete;366ConstDerefValue &operator=(const ConstDerefValue &) = delete;367368operator const T &() { return mValue; }369370private:371explicit ConstDerefValue(const SynchronizedValue &outer)372: mLock(outer.mMutex), mValue(outer.mValue)373{}374375std::unique_lock<Lockable> mLock;376const T &mValue;377378friend class SynchronizedValue;379};380381DerefValue operator*() { return DerefValue(*this); }382ConstDerefValue operator*() const { return ConstDerefValue(*this); }383384template <typename OStream>385void save(OStream &os) const386{387std::lock_guard<Lockable> lock(mMutex);388os << mValue;389}390391template <typename IStream>392void load(IStream &is)393{394std::lock_guard<Lockable> lock(mMutex);395is >> mValue;396}397398bool operator==(const SynchronizedValue &other) const399{400std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);401std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);402std::lock(lock1, lock2);403return mValue == other.mValue;404}405406bool operator!=(const SynchronizedValue &other) const407{408std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);409std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);410std::lock(lock1, lock2);411return mValue != other.mValue;412}413414bool operator<(const SynchronizedValue &other) const415{416std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);417std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);418std::lock(lock1, lock2);419return mValue < other.mValue;420}421422bool operator>(const SynchronizedValue &other) const423{424std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);425std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);426std::lock(lock1, lock2);427return mValue > other.mValue;428}429430bool operator<=(const SynchronizedValue &other) const431{432std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);433std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);434std::lock(lock1, lock2);435return mValue <= other.mValue;436}437438bool operator>=(const SynchronizedValue &other) const439{440std::unique_lock<Lockable> lock1(mMutex, std::defer_lock);441std::unique_lock<Lockable> lock2(other.mMutex, std::defer_lock);442std::lock(lock1, lock2);443return mValue >= other.mValue;444}445446bool operator==(const T &other) const447{448std::lock_guard<Lockable> lock(mMutex);449return mValue == other;450}451452bool operator!=(const T &other) const453{454std::lock_guard<Lockable> lock(mMutex);455return mValue != other;456}457458bool operator<(const T &other) const459{460std::lock_guard<Lockable> lock(mMutex);461return mValue < other;462}463464bool operator>(const T &other) const465{466std::lock_guard<Lockable> lock(mMutex);467return mValue > other;468}469470bool operator<=(const T &other) const471{472std::lock_guard<Lockable> lock(mMutex);473return mValue <= other;474}475476bool operator>=(const T &other) const477{478std::lock_guard<Lockable> lock(mMutex);479return mValue >= other;480}481482private:483T mValue;484mutable Lockable mMutex;485};486487template <typename OStream, typename T, typename L>488inline OStream &operator<<(OStream &os, SynchronizedValue<T, L> const &sv)489{490sv.save(os);491return os;492}493494template <typename IStream, typename T, typename L>495inline IStream &operator>>(IStream &is, SynchronizedValue<T, L> &sv)496{497sv.load(is);498return is;499}500501template <typename T, typename L>502bool operator==(const T &lhs, const SynchronizedValue<T, L> &rhs)503{504return rhs == lhs;505}506507template <typename T, typename L>508bool operator!=(const T &lhs, const SynchronizedValue<T, L> &rhs)509{510return rhs != lhs;511}512513template <typename T, typename L>514bool operator<(const T &lhs, const SynchronizedValue<T, L> &rhs)515{516return rhs < lhs;517}518519template <typename T, typename L>520bool operator>(const T &lhs, const SynchronizedValue<T, L> &rhs)521{522return rhs > lhs;523}524525template <typename T, typename L>526bool operator<=(const T &lhs, const SynchronizedValue<T, L> &rhs)527{528return rhs <= lhs;529}530531template <typename T, typename L>532bool operator>=(const T &lhs, const SynchronizedValue<T, L> &rhs)533{534return rhs >= lhs;535}536537} // namespace angle538539#endif // COMMON_SYNCHRONIZEDVALUE_H_540541542