CsLibGuarded  1.4.1
cs_shared_guarded.h
1 /***********************************************************************
2 *
3 * Copyright (c) 2016-2024 Ansel Sermersheim
4 *
5 * This file is part of CsLibGuarded.
6 *
7 * CsLibGuarded is free software, released under the BSD 2-Clause license.
8 * For license details refer to LICENSE provided with this project.
9 *
10 * CsLibGuarded is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 *
14 * https://opensource.org/licenses/BSD-2-Clause
15 *
16 ***********************************************************************/
17 
18 #ifndef CSLIBGUARDED_SHARED_GUARDED_H
19 #define CSLIBGUARDED_SHARED_GUARDED_H
20 
21 #include <memory>
22 #include <mutex>
23 #include <shared_mutex>
24 
25 namespace libguarded
26 {
27 
28 // 13 comment line(s) omitted
41 template <typename T, typename M = std::shared_timed_mutex, typename L = std::shared_lock<M>>
42 class shared_guarded
43 {
44  private:
45  class deleter;
46  class shared_deleter;
47 
48  public:
49  using handle = std::unique_ptr<T, deleter>;
50  using shared_handle = std::unique_ptr<const T, shared_deleter>;
51 
52  template <typename... Us>
53  shared_guarded(Us &&... data);
54 
55  // exclusive access
56  [[nodiscard]] handle lock();
57  [[nodiscard]] handle try_lock();
58 
59  template <class Duration>
60  [[nodiscard]] handle try_lock_for(const Duration &duration);
61 
62  template <class TimePoint>
63  [[nodiscard]] handle try_lock_until(const TimePoint &timepoint);
64 
65  // shared access, note "shared" in method names
66  [[nodiscard]] shared_handle lock_shared() const;
67  [[nodiscard]] shared_handle try_lock_shared() const;
68 
69  template <class Duration>
70  [[nodiscard]] shared_handle try_lock_shared_for(const Duration &duration) const;
71 
72  template <class TimePoint>
73  [[nodiscard]] shared_handle try_lock_shared_until(const TimePoint &timepoint) const;
74 
75  private:
76  T m_obj;
77  mutable M m_mutex;
78 };
79 
80 template <typename T, typename M, typename L>
81 class shared_guarded<T, M, L>::deleter
82 {
83  public:
84  using pointer = T *;
85 
86  deleter() = default;
87  deleter(std::unique_lock<M> lock);
88 
89  void operator()(T *ptr);
90 
91  private:
92  std::unique_lock<M> m_lock;
93 };
94 
95 template <typename T, typename M, typename L>
96 shared_guarded<T, M, L>::deleter::deleter(std::unique_lock<M> lock)
97  : m_lock(std::move(lock))
98 {
99 }
100 
101 template <typename T, typename M, typename L>
102 void shared_guarded<T, M, L>::deleter::operator()(T *)
103 {
104  if (m_lock.owns_lock()) {
105  m_lock.unlock();
106  }
107 }
108 
109 template <typename T, typename M, typename L>
110 class shared_guarded<T, M, L>::shared_deleter
111 {
112 public:
113  using pointer = const T *;
114 
115  shared_deleter() = default;
116  shared_deleter(L lock);
117 
118  void operator()(const T *ptr);
119 
120 private:
121  L m_lock;
122 };
123 
124 template <typename T, typename M, typename L>
125 shared_guarded<T, M, L>::shared_deleter::shared_deleter(L lock)
126  : m_lock(std::move(lock))
127 {
128 }
129 
130 template <typename T, typename M, typename L>
131 void shared_guarded<T, M, L>::shared_deleter::operator()(const T *)
132 {
133  if (m_lock.owns_lock()) {
134  m_lock.unlock();
135  }
136 }
137 
138 template <typename T, typename M, typename L>
139 template <typename... Us>
140 shared_guarded<T, M, L>::shared_guarded(Us &&... data)
141  : m_obj(std::forward<Us>(data)...)
142 {
143 }
144 
145 template <typename T, typename M, typename L>
146 auto shared_guarded<T, M, L>::lock() -> handle
147 {
148  std::unique_lock<M> lock(m_mutex);
149  return handle(&m_obj, deleter(std::move(lock)));
150 }
151 
152 template <typename T, typename M, typename L>
153 auto shared_guarded<T, M, L>::try_lock() -> handle
154 {
155  std::unique_lock<M> lock(m_mutex, std::try_to_lock);
156 
157  if (lock.owns_lock()) {
158  return handle(&m_obj, deleter(std::move(lock)));
159  } else {
160  return handle(nullptr, deleter(std::move(lock)));
161  }
162 }
163 
164 template <typename T, typename M, typename L>
165 template <typename Duration>
166 auto shared_guarded<T, M, L>::try_lock_for(const Duration &duration) -> handle
167 {
168  std::unique_lock<M> lock(m_mutex, duration);
169 
170  if (lock.owns_lock()) {
171  return handle(&m_obj, deleter(std::move(lock)));
172  } else {
173  return handle(nullptr, deleter(std::move(lock)));
174  }
175 }
176 
177 template <typename T, typename M, typename L>
178 template <typename TimePoint>
179 auto shared_guarded<T, M, L>::try_lock_until(const TimePoint &timepoint) -> handle
180 {
181  std::unique_lock<M> lock(m_mutex, timepoint);
182 
183  if (lock.owns_lock()) {
184  return handle(&m_obj, deleter(std::move(lock)));
185  } else {
186  return handle(nullptr, deleter(std::move(lock)));
187  }
188 }
189 
190 template <typename T, typename M, typename L>
191 auto shared_guarded<T, M, L>::lock_shared() const -> shared_handle
192 {
193  L lock(m_mutex);
194  return shared_handle(&m_obj, shared_deleter(std::move(lock)));
195 }
196 
197 template <typename T, typename M, typename L>
198 auto shared_guarded<T, M, L>::try_lock_shared() const -> shared_handle
199 {
200  L lock(m_mutex, std::try_to_lock);
201 
202  if (lock.owns_lock()) {
203  return shared_handle(&m_obj, shared_deleter(std::move(lock)));
204  } else {
205  return shared_handle(nullptr, shared_deleter(std::move(lock)));
206  }
207 }
208 
209 template <typename T, typename M, typename L>
210 template <typename Duration>
211 auto shared_guarded<T, M, L>::try_lock_shared_for(const Duration &d) const -> shared_handle
212 {
213  L lock(m_mutex, d);
214 
215  if (lock.owns_lock()) {
216  return shared_handle(&m_obj, shared_deleter(std::move(lock)));
217  } else {
218  return shared_handle(nullptr, shared_deleter(std::move(lock)));
219  }
220 }
221 
222 template <typename T, typename M, typename L>
223 template <typename TimePoint>
224 auto shared_guarded<T, M, L>::try_lock_shared_until(const TimePoint &tp) const -> shared_handle
225 {
226  L lock(m_mutex, tp);
227 
228  if (lock.owns_lock()) {
229  return shared_handle(&m_obj, shared_deleter(std::move(lock)));
230  } else {
231  return shared_handle(nullptr, shared_deleter(std::move(lock)));
232  }
233 }
234 
235 } // namespace libguarded
236 
237 #endif