1#pragma once
2
3#include <utility>
4
5namespace sead
6{
7template <typename T>
8class ScopedLock
9{
10public:
11 explicit ScopedLock(T* lock) : mLocked(lock) { mLocked->lock(); }
12
13 ScopedLock(const ScopedLock& other) = delete;
14 ScopedLock& operator=(const ScopedLock& other) = delete;
15
16 ScopedLock(ScopedLock&& other) noexcept { *this = std::move(other); }
17 ScopedLock& operator=(ScopedLock&& other) noexcept
18 {
19 if (this == &other)
20 return *this;
21
22 mLocked = other.mLocked;
23 mEngaged = std::exchange(obj&: other.mEngaged, new_value: false);
24 return *this;
25 }
26
27 virtual ~ScopedLock()
28 {
29 if (mEngaged)
30 mLocked->unlock();
31 }
32
33protected:
34 bool mEngaged = true;
35 T* mLocked;
36};
37
38template <typename T>
39[[nodiscard]] inline ScopedLock<T> makeScopedLock(T& lock)
40{
41 return ScopedLock<T>{&lock};
42}
43
44template <typename T>
45class ConditionalScopedLock
46{
47public:
48 ConditionalScopedLock(T* lock, bool do_lock)
49 {
50 if (!do_lock)
51 return;
52 mLocked = lock;
53 mLocked->lock();
54 }
55
56 ConditionalScopedLock(const ConditionalScopedLock& other) = delete;
57 ConditionalScopedLock& operator=(const ConditionalScopedLock& other) = delete;
58
59 ConditionalScopedLock(ConditionalScopedLock&& other) noexcept { *this = std::move(other); }
60 ConditionalScopedLock& operator=(ConditionalScopedLock&& other) noexcept
61 {
62 if (this == &other)
63 return *this;
64
65 mLocked = other.mLocked;
66 mEngaged = std::exchange(obj&: other.mEngaged, new_value: false);
67 return *this;
68 }
69
70 virtual ~ConditionalScopedLock()
71 {
72 if (mEngaged && mLocked)
73 mLocked->unlock();
74 }
75
76protected:
77 bool mEngaged = true;
78 T* mLocked = nullptr;
79};
80
81template <typename T>
82[[nodiscard]] inline ConditionalScopedLock<T> makeScopedLock(T& lock, bool do_lock)
83{
84 return ConditionalScopedLock<T>(&lock, do_lock);
85}
86} // namespace sead
87