#pragma once #include #include #include #include #include namespace LV { template class Lockable { public: template Lockable(Args&& ...args) : Obj(std::forward(args)...) {} class ReadLockGuard { public: template ReadLockGuard(T& obj, Args&& ...args) : Lock(std::forward(args)...), Ref(obj) {} const T& operator*() const { assert(Lock.owns_lock()); return Ref; } const T* operator->() const { assert(Lock.owns_lock()); return &Ref; } bool owns_lock() { return Lock.owns_lock(); } operator bool() { return Lock.owns_lock(); } void unlock() { Lock.unlock(); } private: boost::shared_lock Lock; T& Ref; }; class WriteLockGuard { public: template WriteLockGuard(T& obj, Args&& ...args) : Lock(std::forward(args)...), Ref(obj) {} T& operator*() const { assert(Lock.owns_lock()); return Ref; } T* operator->() const { assert(Lock.owns_lock()); return &Ref; } bool owns_lock() { return Lock.owns_lock(); } operator bool() { return Lock.owns_lock(); } void unlock() { Lock.unlock(); } private: std::unique_lock Lock; T& Ref; }; ReadLockGuard lock_read() { return ReadLockGuard(Obj, Mtx); } ReadLockGuard try_lock_read() { return ReadLockGuard(Obj, Mtx, boost::try_to_lock); } template ReadLockGuard try_lock_read(const boost::chrono::time_point& atime) { return ReadLockGuard(Obj, Mtx, atime); } WriteLockGuard lock_write() { return WriteLockGuard(Obj, Mtx); } WriteLockGuard try_lock_write() { return WriteLockGuard(Obj, Mtx, boost::try_to_lock); } template WriteLockGuard try_lock_write(const boost::chrono::time_point& atime) { return WriteLockGuard(Obj, Mtx, atime); } const T& no_lock_readable() { return Obj; } T& no_lock_writeable() { return Obj; } private: T Obj; boost::shared_mutex Mtx; }; class DestroyLock { public: DestroyLock() = default; struct Guard { Guard(DestroyLock &lock) : Lock(lock) { lock.UseCount++; lock.UseCount.notify_all(); } ~Guard() { Lock.UseCount--; Lock.UseCount.notify_all(); } private: DestroyLock &Lock; }; void wait_no_use() { while(int val = UseCount) UseCount.wait(val); } Guard lock() { return Guard(*this); } private: std::atomic UseCount; }; }