DUNE-FEM (unstable)

singleton.hh
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#include <iostream>
13
15#ifdef USING_DUNE_PYTHON
16#include <dune/python/pybind11/pybind11.h>
17#endif
18
19namespace Dune
20{
21 namespace Fem
22 {
23 namespace detail
24 {
25 class SingletonStorage
26 {
27 public:
28 // item to be stored in storage list
29 struct Item { virtual ~Item() {} };
30
31 typedef std::shared_ptr< Item > WeakPointerType;
32 typedef std::unique_ptr< Item > PointerType;
33 typedef std::type_index KeyType;
34
35 //typedef std::pair< std::unordered_map< KeyType, std::shared_ptr< Item > >, std::vector<PointerType> > StorageType;
36
37 struct Storage :
38 public std::pair< std::unordered_map< KeyType, std::shared_ptr< Item > >, std::vector<PointerType> >
39 {
40 Storage() :
41 std::pair< std::unordered_map< KeyType, std::shared_ptr< Item > >, std::vector<PointerType> > (),
42 mutex_()
43 {}
44
45 //typedef std::mutex mutex_t;
46 typedef std::recursive_mutex mutex_t;
47 mutex_t mutex_;
48 };
49
50 typedef Storage StorageType;
51
52 // delete for singletons deleting each singleton object
53 // in reverse order of creation
54 struct SingletonDeleter
55 {
56 void operator()(StorageType* storage) const
57 {
58 // delete singletons in reverse order
59 std::for_each(storage->second.rbegin(), storage->second.rend(), [](PointerType& item) { item.reset(); });
60
61 storage->second.clear();
62 storage->first.clear();
63 }
64 };
65
66 typedef std::shared_ptr<StorageType> StoragePointer;
67
68 static StoragePointer storage_;
69
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#ifndef USING_DUNE_PYTHON
77 storage_.reset( new StorageType(), SingletonDeleter() );
78#else
79 storage_ = pybind11::cast< StoragePointer >(
80 pybind11::module::import( "dune.fem._fem" ).attr( "_singleton" ) );
81#endif
82 }
83
84 return *storage_;
85 }
86 };
87 } // end namespace detail
88
91 template< class Object >
92 class Singleton : public detail::SingletonStorage
93 {
94 typedef detail::SingletonStorage BaseType;
95 typedef typename BaseType::StorageType StorageType;
96 typedef typename BaseType::Item Item;
97 typedef typename BaseType::PointerType PointerType;
98 typedef typename BaseType::WeakPointerType WeakPointerType;
99
100 using BaseType::getStorage;
101
102 // item to be created containing the correct object
103 struct ItemWrapper : public Item
104 {
105 Object obj_;
106 template <class... Args>
107 ItemWrapper(Args &&... args) : obj_(std::forward< Args >( args )...)
108 {}
109 };
110 typedef ItemWrapper ItemWrapperType;
111
112 // null delete for shared_ptr hash map
113 struct NullDeleter
114 {
115 void operator()(Item *p) const {}
116 };
117
118 public:
122 template <class... Args>
123 DUNE_EXPORT static Object& instance(Args &&... args)
124 {
125 // capture thread_local reference as static variable to avoid
126 // map search later on, object creation is protected by a mutex lock
127 static thread_local Object& inst = getObject(std::forward< Args >( args )...);
128 return inst;
129 }
130
131 protected:
132 // placing variables as static inside functions only works with gcc
133 static const bool placeStaticVariableInline = false ;
134
137 template <class... Args>
138 DUNE_EXPORT static Object& getObject(Args &&... args)
139 {
140 // this way of creating static variables only works with gcc, not with clang
141 if constexpr ( placeStaticVariableInline )
142 {
143 static Object obj( std::forward< Args >( args )...);
144 return obj;
145 }
146 else
147 {
148 // get storage reference (see base class)
149 // this should exists since we initialize some static
150 // variables inside the MPIManager at program start
151 StorageType& storage = getStorage();
152
153 // this section needs locking to avoid race conditions
154 // unlock is done on destruction of lock_guard
155 std::lock_guard< StorageType::mutex_t > guard( storage.mutex_ );
156
157 // get pointer of singleton objects belonging to hash id
158 auto& ptr = storage.first[ std::type_index(typeid(Object)) ];
159 // if pointer has not been set, create object and set pointer
160 if( ! ptr )
161 {
162 // create object in vector for later correct deletion order
163 storage.second.emplace_back( PointerType(new ItemWrapperType(std::forward< Args >( args )...) ) );
164
165 // create pointer to object in hash map for later use
166 ptr = WeakPointerType( storage.second.back().operator->(), NullDeleter() );
167 }
168
169 // return object reference
170 assert( dynamic_cast< ItemWrapperType* > (ptr.operator->()) );
171 return static_cast< ItemWrapperType& > (*ptr).obj_;
172 }
173 }
174
175 };
176
177 } // namespace Fem
178
179} // namespace Dune
180
181#endif // #ifndef DUNE_FEM_SINGLETONLIST_HH
return singleton instance of given Object type.
Definition: singleton.hh:93
static DUNE_EXPORT Object & instance(Args &&... args)
return singleton instance of given Object type.
Definition: singleton.hh:123
static DUNE_EXPORT Object & getObject(Args &&... args)
return singleton instance of given Object type.
Definition: singleton.hh:138
Dune namespace.
Definition: alignedallocator.hh:13
STL namespace.
Definition of macros controlling symbol visibility at the ABI level.
#define DUNE_EXPORT
Export a symbol as part of the public ABI.
Definition: visibility.hh:20
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 21, 23:30, 2024)