CsLibGuarded  1.4.1
cs_plain_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_PLAIN_GUARDED_H
19 #define CSLIBGUARDED_PLAIN_GUARDED_H
20 
21 #include <memory>
22 #include <mutex>
23 
24 namespace libguarded
25 {
26 
27 // 14 comment line(s) omitted
41 template <typename T, typename M = std::mutex>
42 class plain_guarded
43 {
44  private:
45  class deleter;
46  class const_deleter;
47 
48  public:
49  using handle = std::unique_ptr<T, deleter>;
50  using const_handle = std::unique_ptr<const T, const_deleter>;
51 
52  // 5 comment line(s) omitted
57  template <typename... Us>
58  plain_guarded(Us &&... data);
59 
60  // 6 comment line(s) omitted
66  [[nodiscard]] handle lock();
67  [[nodiscard]] const_handle lock() const;
68 
69  // 7 comment line(s) omitted
76  [[nodiscard]] handle try_lock();
77  [[nodiscard]] const_handle try_lock() const;
78 
79  // 14 comment line(s) omitted
93  template <class Duration>
94  [[nodiscard]] handle try_lock_for(const Duration &duration);
95  template <class Duration>
96  [[nodiscard]] const_handle try_lock_for(const Duration &duration) const;
97 
98  // 13 comment line(s) omitted
111  template <class TimePoint>
112  [[nodiscard]] handle try_lock_until(const TimePoint &timepoint);
113  template <class TimePoint>
114  [[nodiscard]] const_handle try_lock_until(const TimePoint &timepoint) const;
115 
116  private:
117  T m_obj;
118  mutable M m_mutex;
119 };
120 
121 template <typename T, typename M>
122 class plain_guarded<T, M>::deleter
123 {
124  public:
125  using pointer = T *;
126 
127  deleter() = default;
128  deleter(std::unique_lock<M> lock);
129 
130  void operator()(T *ptr);
131 
132  private:
133  std::unique_lock<M> m_lock;
134 };
135 
136 template <typename T, typename M>
137 plain_guarded<T, M>::deleter::deleter(std::unique_lock<M> lock)
138  : m_lock(std::move(lock))
139 {
140 }
141 
142 template <typename T, typename M>
143 void plain_guarded<T, M>::deleter::operator()(T *)
144 {
145  if (m_lock.owns_lock()) {
146  m_lock.unlock();
147  }
148 }
149 
150 template <typename T, typename M>
151 class plain_guarded<T, M>::const_deleter
152 {
153  public:
154  using pointer = const T *;
155 
156  const_deleter() = default;
157  const_deleter(std::unique_lock<M> lock);
158 
159  void operator()(const T *ptr);
160 
161  private:
162  std::unique_lock<M> m_lock;
163 };
164 
165 template <typename T, typename M>
166 plain_guarded<T, M>::const_deleter::const_deleter(std::unique_lock<M> lock)
167  : m_lock(std::move(lock))
168 {
169 }
170 
171 template <typename T, typename M>
172 void plain_guarded<T, M>::const_deleter::operator()(const T *)
173 {
174  if (m_lock.owns_lock()) {
175  m_lock.unlock();
176  }
177 }
178 
179 template <typename T, typename M>
180 template <typename... Us>
181 plain_guarded<T, M>::plain_guarded(Us &&... data)
182  : m_obj(std::forward<Us>(data)...)
183 {
184 }
185 
186 template <typename T, typename M>
187 auto plain_guarded<T, M>::lock() -> handle
188 {
189  std::unique_lock<M> lock(m_mutex);
190  return handle(&m_obj, deleter(std::move(lock)));
191 }
192 
193 template <typename T, typename M>
194 auto plain_guarded<T, M>::lock() const -> const_handle
195 {
196  std::unique_lock<M> lock(m_mutex);
197  return const_handle(&m_obj, const_deleter(std::move(lock)));
198 }
199 
200 template <typename T, typename M>
201 auto plain_guarded<T, M>::try_lock() -> handle
202 {
203  std::unique_lock<M> lock(m_mutex, std::try_to_lock);
204 
205  if (lock.owns_lock()) {
206  return handle(&m_obj, deleter(std::move(lock)));
207  } else {
208  return handle(nullptr, deleter(std::move(lock)));
209  }
210 }
211 
212 template <typename T, typename M>
213 auto plain_guarded<T, M>::try_lock() const -> const_handle
214 {
215  std::unique_lock<M> lock(m_mutex, std::try_to_lock);
216 
217  if (lock.owns_lock()) {
218  return const_handle(&m_obj, const_deleter(std::move(lock)));
219  } else {
220  return const_handle(nullptr, const_deleter(std::move(lock)));
221  }
222 }
223 
224 template <typename T, typename M>
225 template <typename Duration>
226 auto plain_guarded<T, M>::try_lock_for(const Duration &d) -> handle
227 {
228  std::unique_lock<M> lock(m_mutex, d);
229 
230  if (lock.owns_lock()) {
231  return handle(&m_obj, deleter(std::move(lock)));
232  } else {
233  return handle(nullptr, deleter(std::move(lock)));
234  }
235 }
236 
237 template <typename T, typename M>
238 template <typename Duration>
239 auto plain_guarded<T, M>::try_lock_for(const Duration &d) const -> const_handle
240 {
241  std::unique_lock<M> lock(m_mutex, d);
242 
243  if (lock.owns_lock()) {
244  return const_handle(&m_obj, const_deleter(std::move(lock)));
245  } else {
246  return const_handle(nullptr, const_deleter(std::move(lock)));
247  }
248 }
249 
250 template <typename T, typename M>
251 template <typename TimePoint>
252 auto plain_guarded<T, M>::try_lock_until(const TimePoint &tp) -> handle
253 {
254  std::unique_lock<M> lock(m_mutex, tp);
255 
256  if (lock.owns_lock()) {
257  return handle(&m_obj, deleter(std::move(lock)));
258  } else {
259  return handle(nullptr, deleter(std::move(lock)));
260  }
261 }
262 
263 template <typename T, typename M>
264 template <typename TimePoint>
265 auto plain_guarded<T, M>::try_lock_until(const TimePoint &tp) const -> const_handle
266 {
267  std::unique_lock<M> lock(m_mutex, tp);
268 
269  if (lock.owns_lock()) {
270  return const_handle(&m_obj, const_deleter(std::move(lock)));
271  } else {
272  return const_handle(nullptr, const_deleter(std::move(lock)));
273  }
274 }
275 
276 template <typename T, typename M = std::mutex>
277 using guarded [[deprecated("renamed to plain_guarded")]] = plain_guarded<T, M>;
278 
279 } // namespace libguarded
280 
281 #endif