tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SynchronizedValue.h (15221B)


      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_