Github   Telegram
Loading...
Searching...
No Matches
variable.hpp
1#pragma once
2
3#include <mutex>
4#include <optional>
5#include <shared_mutex> // for shared_lock
6
8
9USERVER_NAMESPACE_BEGIN
10
12namespace concurrent {
13
15template <typename Lock, typename Data>
16class LockedPtr final {
17 public:
18 using Mutex = typename Lock::mutex_type;
19
20 LockedPtr(Mutex& mutex, Data& data) : lock_(mutex), data_(data) {}
21 LockedPtr(Lock&& lock, Data& data) : lock_(std::move(lock)), data_(data) {}
22
23 Data& operator*() & { return data_; }
24 const Data& operator*() const& { return data_; }
25
27 Data& operator*() && { return *GetOnRvalue(); }
28
29 Data* operator->() & { return &data_; }
30 const Data* operator->() const& { return &data_; }
31
33 Data* operator->() && { return GetOnRvalue(); }
34
35 Lock& GetLock() { return lock_; }
36
37 private:
38 const Data* GetOnRvalue() {
39 static_assert(!sizeof(Data),
40 "Don't use temporary LockedPtr, store it to a variable");
41 std::abort();
42 }
43
44 Lock lock_;
45 Data& data_;
46};
47
57template <typename Data, typename Mutex = engine::Mutex>
58class Variable final {
59 public:
60 template <typename... Arg>
61 Variable(Arg&&... arg) : data_(std::forward<Arg>(arg)...) {}
62
63 LockedPtr<std::unique_lock<Mutex>, Data> UniqueLock() {
64 return {mutex_, data_};
65 }
66
67 LockedPtr<std::unique_lock<Mutex>, const Data> UniqueLock() const {
68 return {mutex_, data_};
69 }
70
71 std::optional<LockedPtr<std::unique_lock<Mutex>, const Data>> UniqueLock(
72 std::try_to_lock_t) const {
73 return DoUniqueLock(*this, std::try_to_lock);
74 }
75
76 std::optional<LockedPtr<std::unique_lock<Mutex>, Data>> UniqueLock(
77 std::try_to_lock_t) {
78 return DoUniqueLock(*this, std::try_to_lock);
79 }
80
81 std::optional<LockedPtr<std::unique_lock<Mutex>, const Data>> UniqueLock(
82 std::chrono::milliseconds try_duration) const {
83 return DoUniqueLock(*this, try_duration);
84 }
85
86 std::optional<LockedPtr<std::unique_lock<Mutex>, Data>> UniqueLock(
87 std::chrono::milliseconds try_duration) {
88 return DoUniqueLock(*this, try_duration);
89 }
90
91 LockedPtr<std::shared_lock<Mutex>, const Data> SharedLock() const {
92 return {mutex_, data_};
93 }
94
95 LockedPtr<std::lock_guard<Mutex>, Data> Lock() { return {mutex_, data_}; }
96
97 LockedPtr<std::lock_guard<Mutex>, const Data> Lock() const {
98 return {mutex_, data_};
99 }
100
103 Mutex& GetMutexUnsafe() const { return mutex_; }
104
109 Data& GetDataUnsafe() { return data_; }
110
111 const Data& GetDataUnsafe() const { return data_; }
112
113 private:
114 mutable Mutex mutex_;
115 Data data_;
116
121 template <typename VariableType, typename... StdUniqueLockArgs>
122 static auto DoUniqueLock(VariableType& concurrent_variable,
123 StdUniqueLockArgs&&... args) {
124 std::unique_lock<Mutex> lock(concurrent_variable.mutex_,
125 std::forward<StdUniqueLockArgs>(args)...);
126 return lock ? std::optional{LockedPtr{std::move(lock),
127 concurrent_variable.data_}}
128 : std::nullopt;
129 }
130};
131
132} // namespace concurrent
133
134USERVER_NAMESPACE_END