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 
19 namespace 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
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.80.0 (May 14, 22:30, 2024)