1 #pragma once
2 
3 #include <mutex>
4 #include <shared_mutex>
5 #include <type_traits>
6 
7 namespace chatterino {
8 
9 template <typename T, typename LockType = std::unique_lock<std::shared_mutex>>
10 class AccessGuard
11 {
12 public:
AccessGuard(T & element,std::shared_mutex & mutex)13     AccessGuard(T &element, std::shared_mutex &mutex)
14         : element_(&element)
15         , lock_(mutex)
16     {
17     }
18 
AccessGuard(AccessGuard<T,LockType> && other)19     AccessGuard(AccessGuard<T, LockType> &&other)
20         : element_(other.element_)
21         , lock_(std::move(other.lock_))
22     {
23     }
24 
operator =(AccessGuard<T,LockType> && other)25     AccessGuard<T, LockType> &operator=(AccessGuard<T, LockType> &&other)
26     {
27         this->element_ = other.element_;
28         this->lock_ = std::move(other.lock_);
29 
30         return *this;
31     }
32 
operator ->() const33     T *operator->() const
34     {
35         return this->element_;
36     }
37 
operator *() const38     T &operator*() const
39     {
40         return *this->element_;
41     }
42 
43 private:
44     T *element_{};
45     LockType lock_;
46 };
47 
48 template <typename T>
49 using SharedAccessGuard =
50     AccessGuard<const T, std::shared_lock<std::shared_mutex>>;
51 
52 template <typename T>
53 class UniqueAccess
54 {
55 public:
UniqueAccess()56     UniqueAccess()
57         : element_(T())
58     {
59     }
60 
UniqueAccess(const T & element)61     UniqueAccess(const T &element)
62         : element_(element)
63     {
64     }
65 
UniqueAccess(T && element)66     UniqueAccess(T &&element)
67         : element_(std::move(element))
68     {
69     }
70 
operator =(const T & element)71     UniqueAccess<T> &operator=(const T &element)
72     {
73         this->element_ = element;
74         return *this;
75     }
76 
operator =(T && element)77     UniqueAccess<T> &operator=(T &&element)
78     {
79         this->element_ = std::move(element);
80         return *this;
81     }
82 
access() const83     AccessGuard<T> access() const
84     {
85         return AccessGuard<T>(this->element_, this->mutex_);
86     }
87 
88     template <typename X = T,
89               typename = std::enable_if_t<!std::is_const<X>::value>>
accessConst() const90     SharedAccessGuard<const X> accessConst() const
91     {
92         return SharedAccessGuard<const T>(this->element_, this->mutex_);
93     }
94 
95 private:
96     mutable T element_;
97     mutable std::shared_mutex mutex_;
98 };
99 
100 }  // namespace chatterino
101