#pragma once #include #include class Spinlock { public: void lock(); void unlock(); bool try_lock(); bool is_locked() const { return m_lock.load() != 0; } private: Atomic m_lock { 0 }; }; class ScopeLock { public: ScopeLock(Spinlock& lock); ~ScopeLock(); ScopeLock(const ScopeLock&) = delete; ScopeLock(ScopeLock&&) = delete; Spinlock& take_over() { m_taken_over = true; return m_lock; } private: Spinlock& m_lock; bool m_taken_over { false }; }; class SafeScopeLock { public: SafeScopeLock(Spinlock& lock); ~SafeScopeLock(); SafeScopeLock(const SafeScopeLock&) = delete; SafeScopeLock(SafeScopeLock&&) = delete; bool did_succeed() const { return m_success; } private: Spinlock& m_lock; bool m_success { false }; }; template class LockedValue { struct LockedValueGuard { LockedValueGuard(LockedValue& value_ref) : m_value_ref(&value_ref) { } LockedValueGuard(const LockedValueGuard& other) = delete; LockedValueGuard(LockedValueGuard&& other) { m_value_ref = other.m_value_ref; other.m_value_ref = nullptr; } ~LockedValueGuard() { if (m_value_ref) m_value_ref->m_lock.unlock(); } T& ref() { expect(m_value_ref, "LockedValueGuard::ref() called on a moved LockedValueGuard"); return m_value_ref->m_value; } void set(const T& other) { ref() = other; } T* operator->() { return &ref(); } T& operator*() { return ref(); } private: LockedValue* m_value_ref; }; public: LockedValue() : m_value() { } LockedValue(T value) : m_value(value) { } LockedValueGuard lock() { m_lock.lock(); return { *this }; } Option try_lock() { if (m_lock.try_lock()) { return { *this }; } return {}; } private: T m_value; Spinlock m_lock; };