#pragma once #include #include template struct TCommonLockOps { static inline void Acquire(T* t) noexcept { t->Acquire(); } static inline void Release(T* t) noexcept { t->Release(); } }; template struct TTryLockOps: public TCommonLockOps { static inline bool TryAcquire(T* t) noexcept { return t->TryAcquire(); } }; // must be used with great care template struct TInverseLockOps: public TOps { template static inline void Acquire(T* t) noexcept { TOps::Release(t); } template static inline void Release(T* t) noexcept { TOps::Acquire(t); } }; template > class TGuard: public TNonCopyable { public: inline TGuard(const T& t) noexcept { Init(&t); } inline TGuard(const T* t) noexcept { Init(t); } inline TGuard(TGuard&& g) noexcept : T_(g.T_) { g.T_ = nullptr; } inline ~TGuard() { Release(); } inline void Release() noexcept { if (WasAcquired()) { TOps::Release(T_); T_ = nullptr; } } explicit inline operator bool() const noexcept { return WasAcquired(); } inline bool WasAcquired() const noexcept { return T_ != nullptr; } inline T* GetMutex() const noexcept { return T_; } private: inline void Init(const T* t) noexcept { T_ = const_cast(t); TOps::Acquire(T_); } private: T* T_; }; /* * { * auto guard = Guard(Lock_); * some code under guard * } */ template static inline TGuard Guard(const T& t) { return {&t}; } /* * with_lock (Lock_) { * some code under guard * } */ #define with_lock(X) \ if (auto Y_GENERATE_UNIQUE_ID(__guard) = ::Guard(X); false) { \ } else /* * auto guard = Guard(Lock_); * ... some code under lock * { * auto unguard = Unguard(guard); * ... some code not under lock * } * ... some code under lock */ template > using TInverseGuard = TGuard>; template static inline TInverseGuard Unguard(const TGuard& guard) { return {guard.GetMutex()}; } template static inline TInverseGuard Unguard(const T& mutex) { return {&mutex}; } template > class TTryGuard: public TNonCopyable { public: inline TTryGuard(const T& t) noexcept { Init(&t); } inline TTryGuard(const T* t) noexcept { Init(t); } inline TTryGuard(TTryGuard&& g) noexcept : T_(g.T_) { g.T_ = nullptr; } inline ~TTryGuard() { Release(); } inline void Release() noexcept { if (WasAcquired()) { TOps::Release(T_); T_ = nullptr; } } inline bool WasAcquired() const noexcept { return T_ != nullptr; } explicit inline operator bool() const noexcept { return WasAcquired(); } private: inline void Init(const T* t) noexcept { T_ = nullptr; T* tMutable = const_cast(t); if (TOps::TryAcquire(tMutable)) { T_ = tMutable; } } private: T* T_; };