1 #ifndef DUNE_FEM_SINGLETONLIST_HH
2 #define DUNE_FEM_SINGLETONLIST_HH
3 
4 //- System includes
5 #include <cassert>
6 #include <vector>
7 #include <string>
8 #include <list>
9 #include <iostream>
10 #include <type_traits>
11 #include <utility>
12 
13 //- dune-fem includes
14 #include <dune/fem/misc/threads/threadmanager.hh>
15 #include <dune/fem/storage/singleton.hh>
16 
17 namespace Dune
18 {
19 
20   namespace Fem
21   {
22 
23     template< class Key, class Object >
24     struct DefaultSingletonFactory
25     {
createObjectDune::Fem::DefaultSingletonFactory26       static Object *createObject ( const Key &key )
27       {
28         return new Object( key );
29       }
30 
deleteObjectDune::Fem::DefaultSingletonFactory31       static void deleteObject ( Object *object )
32       {
33         delete object;
34       }
35     };
36 
37 
38     /** \class SingletonList
39      *  \ingroup HelperClasses
40      *  \brief Singleton list for key/object pairs
41      *
42      *  A singleton list guarantees that for any valid key at most one object is
43      *  created.
44      *
45      *  \param  Key      type of keys
46      *  \param  Object   type of objects
47      *  \param  Factory  factory class creating objects from keys. The default
48      *                   just passes the key to the object's constructor.
49      */
50     template< class Key, class Object,
51               class Factory = DefaultSingletonFactory< Key, Object > >
52     class SingletonList
53     {
54       typedef SingletonList< Key, Object, Factory > ThisType;
55 
56     public:
57       typedef Key KeyType;
58       typedef Object ObjectType;
59       typedef Factory FactoryType;
60 
61       typedef std :: pair< ObjectType * , unsigned int * > ValueType;
62       typedef std :: pair< KeyType, ValueType > ListObjType;
63 
64       struct Deleter
65       {
operator ()Dune::Fem::SingletonList::Deleter66         void operator() ( ObjectType *p ) const { ThisType::removeObject( *p ); }
67       };
68 
69     private:
70       typedef std :: list< ListObjType > ListType;
71       typedef typename ListType :: iterator ListIteratorType;
72 
73       class SingletonListStorage;
74 
75     public:
76       SingletonList () = delete;
77       SingletonList ( const ThisType& ) = delete;
78 
79       //! list that store pairs of key/object pointers
80       //! singleton list
singletonList()81       static ListType &singletonList ()
82       {
83         //static SingletonListStorage s;
84         SingletonListStorage& s = Singleton< SingletonListStorage >::instance();
85 
86         //! list that store pairs of key/object pointers
87         return s.singletonList();
88       }
89 
90       //! return reference to the object for given key.
91       //! If the object does not exist, then it is created first, otherwise the
92       //! reference counter is increased.
93       template< class... Args >
getObject(const KeyType & key,Args &&...args)94       static auto getObject( const KeyType &key, Args &&... args )
95         -> std::enable_if_t< std::is_same< decltype( FactoryType::createObject( key, std::forward< Args >( args )... ) ), ObjectType * >::value, ObjectType & >
96       {
97         // make sure this method is only called in single thread mode
98         assert( Fem :: ThreadManager :: singleThreadMode() );
99 
100         ValueType objValue = getObjFromList( key );
101 
102         // if object exists, increase reference count and return it
103         if( objValue.first )
104         {
105           ++( *(objValue.second) );
106           return *(objValue.first);
107         }
108 
109         // object does not exist. Create it with reference count of 1
110         ObjectType *object = FactoryType::createObject( key, std::forward< Args >( args )... );
111         assert( object );
112         ValueType value( object, new unsigned int( 1 ) );
113         ListObjType tmp( key, value );
114         singletonList().push_back( tmp );
115         return *object;
116       }
117 
118       //! decrease ref counter for this object,
119       //! if ref counter is zero, object is deleted
removeObject(const ObjectType & object)120       inline static void removeObject ( const ObjectType &object )
121       {
122         // make sure this method is only called in single thread mode
123         assert( Fem :: ThreadManager :: singleThreadMode() );
124 
125         ListIteratorType end = singletonList().end();
126         for( ListIteratorType it = singletonList().begin(); it != end; ++it )
127         {
128           if( (*it).second.first == &object )
129           {
130             eraseItem( it );
131             return;
132           }
133         }
134 
135         std :: cerr << "Object could not be deleted, "
136                     << "because it is not in the list anymore!" << std :: endl;
137       }
138 
139       // return pair < Object * , refCounter *>
getObjFromList(const KeyType & key)140       inline static ValueType getObjFromList( const KeyType &key )
141       {
142         ListIteratorType endit = singletonList().end();
143         for(ListIteratorType it = singletonList().begin(); it!=endit; ++it)
144         {
145           if( (*it).first == key )
146           {
147             return (*it).second;
148           }
149         }
150         return ValueType( (ObjectType *)0, (unsigned int *)0 );
151       }
152 
153     protected:
eraseItem(ListIteratorType & it)154       static void eraseItem( ListIteratorType &it )
155       {
156         ValueType value = (*it).second;
157         unsigned int &refCount = *(value.second);
158 
159         assert( refCount > 0 );
160         if( (--refCount) == 0 )
161           deleteItem( it );
162       }
163 
164     private:
deleteItem(ListIteratorType & it)165       static void deleteItem(ListIteratorType & it)
166       {
167         ValueType val = (*it).second;
168         // remove from list
169         singletonList().erase( it );
170         // delete objects
171         FactoryType :: deleteObject( val.first );
172         delete val.second;
173       }
174     }; // end SingletonList
175 
176 
177     template< class Key, class Object, class Factory >
178     class SingletonList< Key, Object, Factory > :: SingletonListStorage
179     {
180       typedef SingletonListStorage ThisType;
181 
182     protected:
183       ListType singletonList_;
184 
185     public:
SingletonListStorage()186       inline SingletonListStorage ()
187       : singletonList_()
188       {}
189 
~SingletonListStorage()190       inline ~SingletonListStorage ()
191       {
192         while( !singletonList().empty() )
193           deleteItem( singletonList().begin() );
194       }
195 
singletonList()196       ListType &singletonList ()
197       {
198         return singletonList_;
199       }
200 
deleteItem(const ListIteratorType & it)201       void deleteItem ( const ListIteratorType &it )
202       {
203         ValueType val = (*it).second;
204         // remove from list
205         singletonList().erase( it );
206         // delete objects
207         FactoryType :: deleteObject( val.first );
208         delete val.second;
209       }
210     };
211 
212   } // namespace Fem
213 
214 } // namespace Dune
215 
216 #endif //  #ifndef DUNE_FEM_SINGLETONLIST_HH
217