Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
Singleton.hh
Go to the documentation of this file.
1// MIT License
2//
3// Copyright (c) 2020 Jonathan R. Madsen
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22//
23//
24
25#pragma once
26
27#include <atomic>
28#include <functional>
29#include <memory>
30#include <mutex>
31#include <set>
32#include <thread>
33#include <type_traits>
34
35namespace PTL
36{
37/// \class PTL::Singleton
38/// \brief Singleton object that allows a deleter class to be specified
39///
40template <typename Type,
41 typename PointerT = std::unique_ptr<Type, std::default_delete<Type>>>
43{
44public:
46 using thread_id_t = std::thread::id;
47 using mutex_t = std::recursive_mutex;
48 using auto_lock_t = std::unique_lock<mutex_t>;
49 using pointer = Type*;
50 using list_t = std::set<pointer>;
51 using smart_pointer = PointerT;
52 using deleter_t = std::function<void(PointerT&)>;
53
54 template <bool B, typename T = int>
55 using enable_if_t = typename std::enable_if<B, T>::type;
56
57public:
58 // Constructor and Destructors
59 Singleton();
61 ~Singleton();
62
63 Singleton(const Singleton&) = delete;
64 Singleton(Singleton&&) = delete;
65 Singleton& operator=(const Singleton&) = delete;
67
68public:
69 // public static functions
70 static pointer GetInstance();
72 static thread_id_t GetMasterThreadID() { return f_master_thread(); }
73 static list_t Children() { return f_children(); }
74 static bool IsMaster(pointer ptr) { return ptr == GetRawMasterInstance(); }
75 static bool IsMasterThread();
76 static void Insert(pointer);
77 static void Remove(pointer);
78 static mutex_t& GetMutex() { return f_mutex(); }
79
80public:
81 // public member function
82 void Initialize();
83 void Initialize(pointer);
84 void Destroy();
85 void Reset(pointer);
86 void Reset();
87
88 // since we are overloading delete we overload new
89 void* operator new(size_t)
90 {
91 this_type* ptr = ::new this_type();
92 return static_cast<void*>(ptr);
93 }
94
95 // overload delete so that f_master_instance is guaranteed to be
96 // a nullptr after deletion
97 void operator delete(void* ptr)
98 {
99 this_type* _instance = (this_type*) (ptr);
100 ::delete _instance;
101 if(std::this_thread::get_id() == f_master_thread())
102 f_master_instance() = nullptr;
103 }
104
105protected:
106 friend class Type;
107
108 // instance functions that do not Initialize
109 smart_pointer& GetSmartInstance() { return _local_instance(); }
110 static smart_pointer& GetSmartMasterInstance() { return _master_instance(); }
111
112 // for checking but not allocating
114 {
115 return IsMasterThread() ? f_master_instance() : _local_instance().get();
116 }
117 static pointer GetRawMasterInstance() { return f_master_instance(); }
118
119private:
120 // Private functions
121 static smart_pointer& _local_instance()
122 {
123 static thread_local smart_pointer _instance = smart_pointer();
124 return _instance;
125 }
126
127 static smart_pointer& _master_instance()
128 {
129 static smart_pointer _instance = smart_pointer();
130 return _instance;
131 }
132
133 void* operator new[](std::size_t) noexcept { return nullptr; }
134 void operator delete[](void*) noexcept {}
135
136 template <typename Tp = Type, typename PtrT = PointerT,
137 enable_if_t<(std::is_same<PtrT, std::shared_ptr<Tp>>::value)> = 0>
138 deleter_t& GetDeleter()
139 {
140 static deleter_t _instance = [](PointerT&) {};
141 return _instance;
142 }
143
144 template <typename Tp = Type, typename PtrT = PointerT,
145 enable_if_t<!(std::is_same<PtrT, std::shared_ptr<Tp>>::value)> = 0>
146 deleter_t& GetDeleter()
147 {
148 static deleter_t _instance = [](PointerT& _master) {
149 auto& del = _master.get_deleter();
150 del(_master.get());
151 _master.reset(nullptr);
152 };
153 return _instance;
154 }
155
156private:
157 // Private variables
158 struct persistent_data
159 {
160 thread_id_t m_master_thread = std::this_thread::get_id();
161 mutex_t m_mutex;
162 pointer m_master_instance = nullptr;
163 list_t m_children = {};
164
165 persistent_data() = default;
166 ~persistent_data() = default;
167 persistent_data(const persistent_data&) = delete;
168 persistent_data(persistent_data&&) = delete;
169 persistent_data& operator=(const persistent_data&) = delete;
170 persistent_data& operator=(persistent_data&&) = delete;
171
172 persistent_data(pointer _master, std::thread::id _tid)
173 : m_master_thread(_tid)
174 , m_master_instance(_master)
175 {}
176
177 void reset()
178 {
179 m_master_instance = nullptr;
180 m_children.clear();
181 }
182 };
183
184 bool m_IsMaster = false;
185 static thread_id_t& f_master_thread();
186 static mutex_t& f_mutex();
187 static pointer& f_master_instance();
188 static list_t& f_children();
189
190 static persistent_data& f_persistent_data()
191 {
192 static persistent_data _instance;
193 return _instance;
194 }
195};
196
197//======================================================================================//
198
199template <typename Type, typename PointerT>
201Singleton<Type, PointerT>::f_master_thread()
202{
203 return f_persistent_data().m_master_thread;
204}
205
206//--------------------------------------------------------------------------------------//
207
208template <typename Type, typename PointerT>
210Singleton<Type, PointerT>::f_master_instance()
211{
212 return f_persistent_data().m_master_instance;
213}
214
215//--------------------------------------------------------------------------------------//
216
217template <typename Type, typename PointerT>
219Singleton<Type, PointerT>::f_mutex()
220{
221 return f_persistent_data().m_mutex;
222}
223
224//--------------------------------------------------------------------------------------//
225
226template <typename Type, typename PointerT>
228Singleton<Type, PointerT>::f_children()
229{
230 return f_persistent_data().m_children;
231}
232
233//--------------------------------------------------------------------------------------//
234
235template <typename Type, typename PointerT>
237{
238 Initialize();
239}
240
241//--------------------------------------------------------------------------------------//
242
243template <typename Type, typename PointerT>
245{
246 Initialize(ptr);
247}
248
249//--------------------------------------------------------------------------------------//
250
251template <typename Type, typename PointerT>
253{
254 auto& del = GetDeleter();
255 del(_master_instance());
256}
257
258//--------------------------------------------------------------------------------------//
259
260template <typename Type, typename PointerT>
261void
263{
264 if(!f_master_instance())
265 {
266 f_master_thread() = std::this_thread::get_id();
267 f_master_instance() = new Type();
268 }
269}
270
271//--------------------------------------------------------------------------------------//
272
273template <typename Type, typename PointerT>
274void
276{
277 if(!f_master_instance())
278 {
279 f_master_thread() = std::this_thread::get_id();
280 f_master_instance() = ptr;
281 }
282}
283
284//--------------------------------------------------------------------------------------//
285
286template <typename Type, typename PointerT>
287void
289{
290 if(std::this_thread::get_id() == f_master_thread() && f_master_instance())
291 {
292 delete f_master_instance();
293 f_master_instance() = nullptr;
294 }
295 else
296 {
297 remove(_local_instance().get());
298 }
299}
300
301//--------------------------------------------------------------------------------------//
302
303template <typename Type, typename PointerT>
306{
307 if(std::this_thread::get_id() == f_master_thread())
308 return GetMasterInstance();
309 else if(!_local_instance().get())
310 {
311 _local_instance().reset(new Type());
312 Insert(_local_instance().get());
313 }
314 return _local_instance().get();
315}
316
317//--------------------------------------------------------------------------------------//
318
319template <typename Type, typename PointerT>
322{
323 if(!f_master_instance())
324 {
325 f_master_thread() = std::this_thread::get_id();
326 f_master_instance() = new Type();
327 }
328 return f_master_instance();
329}
330
331//--------------------------------------------------------------------------------------//
332
333template <typename Type, typename PointerT>
334void
336{
337 if(IsMaster(ptr))
338 {
339 if(_master_instance().get())
340 _master_instance().reset();
341 else if(f_master_instance())
342 {
343 auto& del = GetDeleter();
344 del(_master_instance());
345 f_master_instance() = nullptr;
346 }
347 f_persistent_data().reset();
348 }
349 else
350 {
351 _local_instance().reset();
352 }
353}
354
355//--------------------------------------------------------------------------------------//
356
357template <typename Type, typename PointerT>
358void
360{
361 if(IsMasterThread())
362 _master_instance().reset();
363 _local_instance().reset();
364 f_persistent_data().reset();
365}
366
367//--------------------------------------------------------------------------------------//
368
369template <typename Type, typename PointerT>
370bool
372{
373 return std::this_thread::get_id() == f_master_thread();
374}
375
376//--------------------------------------------------------------------------------------//
377
378template <typename Type, typename PointerT>
379void
381{
382 auto_lock_t l(f_mutex());
383 f_children().insert(itr);
384}
385
386//--------------------------------------------------------------------------------------//
387
388template <typename Type, typename PointerT>
389void
391{
392 auto_lock_t l(f_mutex());
393 for(auto litr = f_children().begin(); litr != f_children().end(); ++litr)
394 {
395 if(*litr == itr)
396 {
397 f_children().erase(litr);
398 break;
399 }
400 }
401}
402
403//--------------------------------------------------------------------------------------//
404
405} // namespace PTL
G4ProfileType Type
Singleton object that allows a deleter class to be specified.
Definition: Singleton.hh:43
std::unique_lock< mutex_t > auto_lock_t
Definition: Singleton.hh:48
friend class Type
Definition: Singleton.hh:106
static list_t Children()
Definition: Singleton.hh:73
Type * pointer
Definition: Singleton.hh:49
void Initialize()
Definition: Singleton.hh:262
std::set< pointer > list_t
Definition: Singleton.hh:50
std::function< void(PointerT &)> deleter_t
Definition: Singleton.hh:52
static pointer GetMasterInstance()
Definition: Singleton.hh:321
std::thread::id thread_id_t
Definition: Singleton.hh:46
Singleton(const Singleton &)=delete
Singleton & operator=(const Singleton &)=delete
static bool IsMasterThread()
Definition: Singleton.hh:371
smart_pointer & GetSmartInstance()
Definition: Singleton.hh:109
PointerT smart_pointer
Definition: Singleton.hh:51
static pointer GetRawMasterInstance()
Definition: Singleton.hh:117
Singleton & operator=(Singleton &&)=delete
static pointer GetInstance()
Definition: Singleton.hh:305
static void Remove(pointer)
Definition: Singleton.hh:390
static thread_id_t GetMasterThreadID()
Definition: Singleton.hh:72
static mutex_t & GetMutex()
Definition: Singleton.hh:78
pointer GetRawInstance()
Definition: Singleton.hh:113
static bool IsMaster(pointer ptr)
Definition: Singleton.hh:74
static smart_pointer & GetSmartMasterInstance()
Definition: Singleton.hh:110
typename std::enable_if< B, T >::type enable_if_t
Definition: Singleton.hh:55
Singleton(Singleton &&)=delete
std::recursive_mutex mutex_t
Definition: Singleton.hh:47
void Destroy()
Definition: Singleton.hh:288
Singleton< Type, PointerT > this_type
Definition: Singleton.hh:45
static void Insert(pointer)
Definition: Singleton.hh:380
Definition: AutoLock.hh:255