Photon Engine 2.0.0-beta
A physically based renderer.
Loading...
Searching...
No Matches
TSynchronized.h
Go to the documentation of this file.
1#pragma once
2
4
5#include <Common/assertion.h>
6#include <Common/exceptions.h>
7
8#include <shared_mutex>
9#include <type_traits>
10#include <utility>
11#include <memory>
12
13namespace ph
14{
15
48template<typename T, typename Mutex = std::shared_mutex>
49class TSynchronized final : private INoCopyAndMove
50{
51private:
55 class AutoLockingPtr final : private INoCopyAndMove
56 {
57 public:
58 explicit AutoLockingPtr(TSynchronized& parent)
59 : m_parent(parent)
60 {
61 m_parent.m_mutex.lock();
62 }
63
64 ~AutoLockingPtr()
65 {
66 m_parent.m_mutex.unlock();
67 }
68
69 T* operator -> ()
70 {
71 return std::addressof(m_parent.m_value);
72 }
73
74 T& operator * ()
75 {
76 return m_parent.m_value;
77 }
78
79 private:
80 TSynchronized& m_parent;
81 };
82
86 class AutoConstLockingPtr final : private INoCopyAndMove
87 {
88 public:
89 explicit AutoConstLockingPtr(const TSynchronized& parent)
90 : m_parent(parent)
91 {
92 m_parent.m_mutex.lock_shared();
93 }
94
95 ~AutoConstLockingPtr()
96 {
97 m_parent.m_mutex.unlock_shared();
98 }
99
100 const T* operator -> () const
101 {
102 return std::addressof(m_parent.m_value);
103 }
104
105 const T& operator * () const
106 {
107 return m_parent.m_value;
108 }
109
110 private:
111 const TSynchronized& m_parent;
112 };
113
116 class AutoTryLockingPtr final : private INoCopyAndMove
117 {
118 public:
119 explicit AutoTryLockingPtr(TSynchronized& parent)
120 : m_parent(parent)
121 , m_isLocked(false)
122 {
123 m_isLocked = m_parent.m_mutex.try_lock();
124 }
125
126 ~AutoTryLockingPtr()
127 {
128 if(m_isLocked)
129 {
130 m_parent.m_mutex.unlock();
131 }
132 }
133
134 T* operator -> ()
135 {
136 if(m_isLocked)
137 {
138 return std::addressof(m_parent.m_value);
139 }
140 else
141 {
142 return nullptr;
143 }
144 }
145
146 T& operator * ()
147 {
148 if(m_isLocked)
149 {
150 return m_parent.m_value;
151 }
152 else
153 {
154 throw IllegalOperationException(
155 "Accessing value without successful non-const locking.");
156 }
157 }
158
159 operator bool () const
160 {
161 return m_isLocked;
162 }
163
164 private:
165 TSynchronized& m_parent;
166 bool m_isLocked;
167 };
168
171 class AutoTryConstLockingPtr final : private INoCopyAndMove
172 {
173 public:
174 explicit AutoTryConstLockingPtr(const TSynchronized& parent)
175 : m_parent(parent)
176 , m_isLocked(false)
177 {
178 m_isLocked = m_parent.m_mutex.try_lock_shared();
179 }
180
181 ~AutoTryConstLockingPtr()
182 {
183 if(m_isLocked)
184 {
185 m_parent.m_mutex.unlock_shared();
186 }
187 }
188
189 const T* operator -> () const
190 {
191 if(m_isLocked)
192 {
193 return std::addressof(m_parent.m_value);
194 }
195 else
196 {
197 return nullptr;
198 }
199 }
200
201 const T& operator * () const
202 {
203 if(m_isLocked)
204 {
205 return m_parent.m_value;
206 }
207 else
208 {
209 throw IllegalOperationException(
210 "Accessing value without successful const locking.");
211 }
212 }
213
214 operator bool () const
215 {
216 return m_isLocked;
217 }
218
219 private:
220 const TSynchronized& m_parent;
221 bool m_isLocked;
222 };
223
224public:
225 TSynchronized() = default;
226
227 explicit TSynchronized(const T& value) noexcept(std::is_nothrow_copy_constructible_v<T>)
228 : m_value(value)
229 , m_mutex()
230 {}
231
232 explicit TSynchronized(T&& value) noexcept(std::is_nothrow_move_constructible_v<T>)
233 : m_value(std::move(value))
234 , m_mutex()
235 {}
236
239 const TSynchronized& asConst() const
240 {
241 return *this;
242 }
243
244 AutoLockingPtr lockedPtr()
245 {
246 // Relied on mandatory copy elision
247 return AutoLockingPtr(*this);
248 }
249
250 AutoConstLockingPtr constLockedPtr() const
251 {
252 // Relied on mandatory copy elision
253 return AutoConstLockingPtr(*this);
254 }
255
264 template<typename LockedFunc>
265 void locked(LockedFunc func)
266 {
267 static_assert(std::is_invocable_v<LockedFunc, T&>,
268 "LockedFunc must take (T&).");
269
270 AutoLockingPtr lockedPtr(*this);
271 func(*lockedPtr);
272 }
273
282 template<typename ConstLockedFunc>
283 void constLocked(ConstLockedFunc func) const
284 {
285 static_assert(std::is_invocable_v<ConstLockedFunc, const T&>,
286 "ConstLockedFunc must take (const T&).");
287
288 AutoConstLockingPtr lockedPtr(*this);
289 func(*lockedPtr);
290 }
291
292 AutoTryLockingPtr tryLock()
293 {
294 // Relied on mandatory copy elision
295 return AutoTryLockingPtr(*this);
296 }
297
298 AutoTryConstLockingPtr tryConstLock() const
299 {
300 // Relied on mandatory copy elision
301 return AutoTryConstLockingPtr(*this);
302 }
303
307 T makeCopy() const
308 {
309 AutoConstLockingPtr lockedPtr(*this);
310 return *lockedPtr;
311 }
312
320 T& unsafeGetReference()
321 {
322 return m_value;
323 }
324
325 const T& unsafeGetReference() const
326 {
327 return m_value;
328 }
330
334 TSynchronized& operator = (const T& rhsValue)
335 {
336 PH_ASSERT(&m_value != &rhsValue);
337
338 AutoLockingPtr lockedPtr(*this);
339 *lockedPtr = rhsValue;
340
341 return *this;
342 }
343
347 TSynchronized& operator = (T&& rhsValue)
348 {
349 PH_ASSERT(&m_value != &rhsValue);
350
351 AutoLockingPtr lockedPtr(*this);
352 *lockedPtr = std::move(rhsValue);
353
354 return *this;
355 }
356
359 AutoLockingPtr operator -> ()
360 {
361 // Relied on mandatory copy elision
362 return AutoLockingPtr(*this);
363 }
364
367 AutoConstLockingPtr operator -> () const
368 {
369 // Relied on mandatory copy elision
370 return AutoConstLockingPtr(*this);
371 }
372
373private:
374 T m_value;
375 mutable Mutex m_mutex;
376};
377
378}// end namespace ph
The root for all renderer implementations.
Definition EEngineProject.h:6
Definition TAABB2D.h:96