dune-fem 2.8.0
Loading...
Searching...
No Matches
singleton.hh
Go to the documentation of this file.
1#ifndef DUNE_FEM_SINGLETON_HH
2#define DUNE_FEM_SINGLETON_HH
3
4//- System includes
5#include <cassert>
6#include <algorithm>
7#include <memory>
8#include <mutex>
9#include <typeindex>
10#include <unordered_map>
11#include <vector>
12
13#include <dune/common/visibility.hh>
14
15namespace Dune
16{
17 namespace Fem
18 {
19 namespace detail
20 {
21 class SingletonStorage
22 {
23 protected:
24 // item to be stored in storage list
25 struct Item { virtual ~Item() {} };
26
27 typedef std::shared_ptr< Item > WeakPointerType;
28 typedef std::unique_ptr< Item > PointerType;
29 typedef std::type_index KeyType;
30
31 //typedef std::pair< std::unordered_map< KeyType, std::shared_ptr< Item > >, std::vector<PointerType> > StorageType;
32
33 struct Storage :
34 public std::pair< std::unordered_map< KeyType, std::shared_ptr< Item > >, std::vector<PointerType> >
35 {
36 Storage() :
37 std::pair< std::unordered_map< KeyType, std::shared_ptr< Item > >, std::vector<PointerType> > (),
38 mutex_()
39 {}
40
41 //typedef std::mutex mutex_t;
42 typedef std::recursive_mutex mutex_t;
43 mutex_t mutex_;
44 };
45
46 typedef Storage StorageType;
47
48 // delete for singletons deleting each singleton object
49 // in reverse order of creation
50 struct SingletonDeleter
51 {
52 void operator()(StorageType* storage) const
53 {
54 // delete singletons in reverse order
55 std::for_each(storage->second.rbegin(), storage->second.rend(),
56 [](PointerType& item) { item.reset(); });
57
58 storage->second.clear();
59 storage->first.clear();
60 }
61 };
62
63 public:
64 typedef std::unique_ptr<StorageType, SingletonDeleter> StoragePointer;
65
66 private:
67 static StoragePointer storage_;
68
69 protected:
70 DUNE_EXPORT static StorageType& getStorage()
71 {
72 if(! storage_ )
73 {
74 // this should happen during the creation of MPIManager
75 // which is the first static variable to accessed
76 storage_.reset( new StorageType() );
77 }
78
79 return *storage_;
80 }
81 };
82 } // end namespace detail
83
86 template< class Object >
87 class Singleton : public detail::SingletonStorage
88 {
89 typedef detail::SingletonStorage BaseType;
90 typedef typename BaseType::StorageType StorageType;
91 typedef typename BaseType::Item Item;
92 typedef typename BaseType::PointerType PointerType;
93 typedef typename BaseType::WeakPointerType WeakPointerType;
94
95 using BaseType::getStorage;
96
97 // item to be created containing the correct object
98 struct ItemWrapper : public Item
99 {
100 Object obj_;
101 template <class... Args>
102 ItemWrapper(Args &&... args) : obj_(std::forward< Args >( args )...)
103 {}
104 };
105 typedef ItemWrapper ItemWrapperType;
106
107 // null delete for shared_ptr hash map
108 struct NullDeleter
109 {
110 void operator()(Item *p) const {}
111 };
112
113 public:
117 template <class... Args>
118 DUNE_EXPORT static Object& instance(Args &&... args)
119 {
120 // capture thread_local reference as static variable to avoid
121 // map search later on, object creation is protected by a mutex lock
122 static thread_local Object& inst = getObject(std::forward< Args >( args )...);
123 return inst;
124 }
125
126 protected:
127 // placing variables as static inside functions only works with gcc
128 static const bool placeStaticVariableInline = false ;
129
132 template <class... Args>
133 DUNE_EXPORT static Object& getObject(Args &&... args)
134 {
135 // this way of creating static variables only works with gcc, not with clang
136 if constexpr ( placeStaticVariableInline )
137 {
138 static Object obj( std::forward< Args >( args )...);
139 return obj;
140 }
141 else
142 {
143 // get storage reference (see base class)
144 // this should exists since we initialize some static
145 // variables inside the MPIManager at program start
146 StorageType& storage = getStorage();
147
148 // this section needs locking to avoid race conditions
149 // unlock is done on destruction of lock_guard
150 std::lock_guard< StorageType::mutex_t > guard( storage.mutex_ );
151
152 // get pointer of singleton objects belonging to hash id
153 auto& ptr = storage.first[ std::type_index(typeid(Object)) ];
154 // if pointer has not been set, create object and set pointer
155 if( ! ptr )
156 {
157 // create object in vector for later correct deletion order
158 storage.second.emplace_back( PointerType(new ItemWrapperType(std::forward< Args >( args )...) ) );
159
160 // create pointer to object in hash map for later use
161 ptr = WeakPointerType( storage.second.back().operator->(), NullDeleter() );
162 }
163
164 // return object reference
165 assert( dynamic_cast< ItemWrapperType* > (ptr.operator->()) );
166 return static_cast< ItemWrapperType& > (*ptr).obj_;
167 }
168 }
169
170 };
171
172 } // namespace Fem
173
174} // namespace Dune
175
176#endif // #ifndef DUNE_FEM_SINGLETONLIST_HH
STL namespace.
Definition: bindguard.hh:11
return singleton instance of given Object type.
Definition: singleton.hh:88
static DUNE_EXPORT Object & instance(Args &&... args)
return singleton instance of given Object type.
Definition: singleton.hh:118
static DUNE_EXPORT Object & getObject(Args &&... args)
return singleton instance of given Object type.
Definition: singleton.hh:133
static const bool placeStaticVariableInline
Definition: singleton.hh:128