Scarab  v3.9.4
Project 8 C++ Utility Library
indexed_factory.hh
Go to the documentation of this file.
1 /*
2  * indexed_factory.hh
3  *
4  * created on: Oct 4, 2019
5  * Author: N.S. Oblath
6  *
7  * This factory has the same functionality as is found in factory.hh plus the option of choosing the index type.
8  *
9  * Note on registrar lifespan: when a registrar is deleted, it un-registers itself from the factory.
10  * This is because the registrar itself is used to create objects, and the act of registering
11  * stores a pointer in the factory. The factory does _not_ assume ownership of the registrar.
12  * Therefore the registrar needs to exist for as long as it might be needed.
13  */
14 
15 #ifndef SCARAB_INDEXED_FACTORY_HH_
16 #define SCARAB_INDEXED_FACTORY_HH_
17 
18 #include "singleton.hh"
19 
20 #include "error.hh"
21 #include "logger.hh"
22 
23 #include <map>
24 #include <string>
25 #include <utility>
26 
27 namespace scarab
28 {
29  LOGGER( slog_ind_fact, "indexed_factory" );
30 
31  //********************
32  // Class definitions
33  //********************
34 
35  template< class XIndexType, class XBaseType, typename ... XArgs >
37 
38  // base_registrar
39 
40  template< class XBaseType, typename ... XArgs >
42  {
43  public:
45  virtual ~base_registrar() {}
46 
47  virtual XBaseType* create( XArgs ... args ) const = 0;
48 
49  };
50 
51  // registrar
52 
53  template< class XIndexType, class XBaseType, class XDerivedType, typename ... XArgs >
54  class indexed_registrar : public base_registrar< XBaseType, XArgs... >
55  {
56  public:
57  indexed_registrar( const XIndexType& a_index );
58  virtual ~indexed_registrar();
59 
60  void register_class() const;
61 
62  XBaseType* create( XArgs ... args ) const;
63 
64  protected:
65  XIndexType f_index;
66  };
67 
68  // indexed_factory
69 
70  template< class XIndexType, class XBaseType, typename ... XArgs >
71  class indexed_factory : public singleton< indexed_factory< XIndexType, XBaseType, XArgs... > >
72  {
73  public:
74  typedef std::map< XIndexType, const base_registrar< XBaseType, XArgs... >* > FactoryMap;
75  typedef typename FactoryMap::value_type FactoryEntry;
76  typedef typename FactoryMap::iterator FactoryIt;
77  typedef typename FactoryMap::const_iterator FactoryCIt;
78 
79  public:
80  XBaseType* create( const XIndexType& a_index, XArgs ... args );
81  XBaseType* create( const FactoryCIt& iter, XArgs ... args );
82 
83  void register_class( const XIndexType& a_index, const base_registrar< XBaseType, XArgs... >* base_registrar );
84  bool has_class( const XIndexType& a_index ) const;
85  void remove_class( const XIndexType& a_index );
86 
87  const base_registrar< XBaseType, XArgs... >* get_registrar( const XIndexType& a_index ) const;
88 
89  FactoryCIt begin() const;
90  FactoryCIt end() const;
91 
92  protected:
94  mutable std::mutex f_factory_mutex;
95 
96  protected:
99  ~indexed_factory();
100  };
101 
102 
103  //*****************************************
104  // Partial specialization for empty XArgs
105  //*****************************************
106 
107  template< class XBaseType >
108  class base_registrar< XBaseType, void >
109  {
110  public:
112  virtual ~base_registrar() {}
113 
114  virtual XBaseType* create() const = 0;
115 
116  };
117 
118  template< class XIndexType, class XBaseType, class XDerivedType >
119  class indexed_registrar< XIndexType, XBaseType, XDerivedType, void > : public base_registrar< XBaseType >
120  {
121  public:
122  indexed_registrar( const XIndexType& a_index );
123  virtual ~indexed_registrar();
124 
125  void register_class() const;
126 
127  XBaseType* create() const;
128 
129  protected:
130  XIndexType f_index;
131  };
132 
133 
134  template< class XIndexType, class XBaseType >
135  class indexed_factory< XIndexType, XBaseType, void > : public singleton< indexed_factory< XIndexType, XBaseType > >
136  {
137  public:
138  typedef std::map< XIndexType, const base_registrar< XBaseType >* > FactoryMap;
139  typedef typename FactoryMap::value_type FactoryEntry;
140  typedef typename FactoryMap::iterator FactoryIt;
141  typedef typename FactoryMap::const_iterator FactoryCIt;
142 
143  public:
144  XBaseType* create( const XIndexType& a_index );
145  XBaseType* create( const FactoryCIt& iter );
146 
147  void register_class( const XIndexType& a_index, const base_registrar< XBaseType >* base_registrar );
148  bool has_class( const XIndexType& a_index ) const;
149  void remove_class( const XIndexType& a_index );
150 
151  const base_registrar< XBaseType >* get_registrar( const XIndexType& a_index ) const;
152 
153  FactoryCIt begin() const;
154  FactoryCIt end() const;
155 
156  protected:
157  FactoryMap* fMap;
158  std::mutex f_factory_mutex;
159 
160  protected:
162  indexed_factory();
163  ~indexed_factory();
164  };
165 
166 
167  //******************
168  // Implementations
169  //******************
170 
171  // indexed_factory
172 
173  template< class XIndexType, class XBaseType, typename ... XArgs >
175  {
176  std::unique_lock< std::mutex > t_lock( this->f_factory_mutex );
177  return iter->second->create( args... );
178  }
179 
180  template< class XIndexType, class XBaseType, typename ... XArgs >
181  XBaseType* indexed_factory< XIndexType, XBaseType, XArgs... >::create( const XIndexType& a_index, XArgs ... args )
182  {
183  //std::cout << "this factory (" << this << ") has " << fMap->size() << " entries" << std::endl;
184  //for( FactoryCIt iter = fMap->begin(); iter != fMap->end(); ++iter )
185  //{
186  // std::cout << "this factory has: " << iter->first << " at " << iter->second << std::endl;
187  //}
188  std::unique_lock< std::mutex > t_lock( this->f_factory_mutex );
189  FactoryCIt it = fMap->find( a_index );
190  if( it == fMap->end() )
191  {
192  LERROR( slog_ind_fact, "Did not find indexed_factory for <" << a_index << ">." );
193  return nullptr;
194  }
195 
196  return it->second->create( args... );
197  }
198 
199  template< class XIndexType, class XBaseType, typename ... XArgs >
201  {
202  // A local (static) logger is created inside this function to avoid static initialization order problems
203  LOGGER( slog_ind_factory_reg, "indexed_factory-register");
204 
205  std::unique_lock< std::mutex > t_lock( this->f_factory_mutex );
206  FactoryCIt it = fMap->find(a_index);
207  if (it != fMap->end())
208  {
209  throw error() << "Already have indexed_factory registered for <" << a_index << ">.";
210  }
211  fMap->insert(std::pair< XIndexType, const base_registrar< XBaseType, XArgs... >* >(a_index, a_registrar));
212  LDEBUG( slog_ind_factory_reg, "Registered a indexed_factory for class " << a_index << " at " << (*fMap)[ a_index ] << ", indexed_factory #" << fMap->size()-1 << " for " << this );
213  }
214 
215  template< class XIndexType, class XBaseType, typename ... XArgs >
217  {
218  return fMap->find( a_index ) != fMap->end();
219  }
220 
221  template< class XIndexType, class XBaseType, typename ... XArgs >
223  {
224  LDEBUG( slog_ind_fact, "Removing indexed_factory for class " << a_index << " from " << this );
225  FactoryIt iter = fMap->find( a_index );
226  if( iter != fMap->end() ) fMap->erase( iter );
227  return;
228  }
229 
230  template< class XIndexType, class XBaseType, typename ... XArgs >
231  const base_registrar< XBaseType, XArgs... >* indexed_factory< XIndexType, XBaseType, XArgs... >::get_registrar( const XIndexType& a_index ) const
232  {
233  return fMap->at( a_index );
234  }
235 
236  template< class XIndexType, class XBaseType, typename ... XArgs >
238  fMap(new FactoryMap()),
239  f_factory_mutex()
240  {}
241 
242  template< class XIndexType, class XBaseType, typename ... XArgs >
244  {
245  delete fMap;
246  }
247 
248  template< class XIndexType, class XBaseType, typename ... XArgs >
250  {
251  std::unique_lock< std::mutex > t_lock( this->f_factory_mutex );
252  return fMap->begin();
253  }
254 
255  template< class XIndexType, class XBaseType, typename ... XArgs >
257  {
258  std::unique_lock< std::mutex > t_lock( this->f_factory_mutex );
259  return fMap->end();
260  }
261 
262  // registrar
263 
264  template< class XIndexType, class XBaseType, class XDerivedType, typename ... XArgs >
266  base_registrar< XBaseType, XArgs... >(),
267  f_index( a_index )
268  {
269  register_class();
270  }
271 
272  template< class XIndexType, class XBaseType, class XDerivedType, typename ... XArgs >
274  {
276  }
277 
278  template< class XIndexType, class XBaseType, class XDerivedType, typename ... XArgs >
280  {
282  return;
283  }
284 
285  template< class XIndexType, class XBaseType, class XDerivedType, typename ... XArgs >
287  {
288  return dynamic_cast< XBaseType* >( new XDerivedType( args... ) );
289  }
290 
291 
292  //*******************************************
293  // Implementations (partial specialization)
294  //*******************************************
295 
296  // indexed_factory
297 
298  template< class XIndexType, class XBaseType >
300  {
301  std::unique_lock< std::mutex > t_lock( this->f_factory_mutex );
302  return iter->second->create();
303  }
304 
305  template< class XIndexType, class XBaseType >
306  XBaseType* indexed_factory< XIndexType, XBaseType, void >::create( const XIndexType& a_index )
307  {
308  //std::cout << "this indexed_factory (" << this << ") has " << fMap->size() << " entries" << std::endl;
309  //for( FactoryCIt iter = fMap->begin(); iter != fMap->end(); ++iter )
310  //{
311  // std::cout << "this indexed_factory has: " << iter->first << " at " << iter->second << std::endl;
312  //}
313  std::unique_lock< std::mutex > t_lock( this->f_factory_mutex );
314  FactoryCIt it = fMap->find( a_index );
315  if( it == fMap->end() )
316  {
317  LERROR( slog_ind_fact, "Did not find indexed_factory for <" << a_index << ">." );
318  return nullptr;
319  }
320 
321  return it->second->create();
322  }
323 
324  template< class XIndexType, class XBaseType >
326  {
327  // A local (static) logger is created inside this function to avoid static initialization order problems
328  LOGGER( slog_ind_factory_reg, "indexed_factory-register");
329 
330  std::unique_lock< std::mutex > t_lock( this->f_factory_mutex );
331  FactoryCIt it = fMap->find(a_index);
332  if (it != fMap->end())
333  {
334  throw error() << "Already have indexed_factory registered for <" << a_index << ">.";
335  return;
336  }
337  fMap->insert(std::pair< std::string, const base_registrar< XIndexType, XBaseType >* >(a_index, a_registrar));
338  LDEBUG( slog_ind_factory_reg, "Registered a indexed_factory for class " << a_index << ", indexed_factory #" << fMap->size()-1 << " for " << this );
339  }
340 
341  template< class XIndexType, class XBaseType >
342  bool indexed_factory< XIndexType, XBaseType, void >::has_class(const XIndexType& a_index ) const
343  {
344  return fMap->find( a_index ) != fMap->end();
345  }
346 
347  template< class XIndexType, class XBaseType >
349  {
350  LDEBUG( slog_ind_fact, "Removing indexed_factory for class " << a_index << " from " << this );
351  FactoryIt iter = fMap->find( a_index );
352  if( iter != fMap->end() ) fMap->erase( iter );
353  return;
354  }
355 
356  template< class XIndexType, class XBaseType >
358  {
359  return fMap->at( a_index );
360  }
361 
362  template< class XIndexType, class XBaseType >
364  fMap(new FactoryMap()),
365  f_factory_mutex()
366  {}
367 
368  template< class XIndexType, class XBaseType >
370  {
371  delete fMap;
372  }
373 
374  template< class XIndexType, class XBaseType >
376  {
377  std::unique_lock< std::mutex > t_lock( this->f_factory_mutex );
378  return fMap->begin();
379  }
380 
381  template< class XIndexType, class XBaseType >
383  {
384  std::unique_lock< std::mutex > t_lock( this->f_factory_mutex );
385  return fMap->end();
386  }
387 
388  // registrar
389 
390  template< class XIndexType, class XBaseType, class XDerivedType >
392  base_registrar< XBaseType >(),
393  f_index( a_index )
394  {
395  register_class();
396  }
397 
398  template< class XIndexType, class XBaseType, class XDerivedType >
400  {
402  }
403 
404  template< class XIndexType, class XBaseType, class XDerivedType >
406  {
408  return;
409  }
410 
411  template< class XIndexType, class XBaseType, class XDerivedType >
413  {
414  return dynamic_cast< XBaseType* >( new XDerivedType() );
415  }
416 
417 } /* namespace scarab */
418 #endif /* SCARAB_INDEXED_FACTORY_HH_ */
const base_registrar< XBaseType, XArgs... > * get_registrar(const XIndexType &a_index) const
std::map< XIndexType, const base_registrar< XBaseType, XArgs... > *> FactoryMap
XBaseType * create(XArgs ... args) const
void register_class(const XIndexType &a_index, const base_registrar< XBaseType, XArgs... > *base_registrar)
XBaseType * create(const XIndexType &a_index, XArgs ... args)
LOGGER(mtlog, "authentication")
FactoryMap::value_type FactoryEntry
static indexed_factory< XIndexType, XBaseType, XArgs... > * get_instance()
Definition: singleton.hh:80
#define LERROR(...)
Definition: logger.hh:394
Base class that turns a class into a singleton.
Definition: singleton.hh:43
std::map< XIndexType, const base_registrar< XBaseType > *> FactoryMap
Contains the logger class and macros, based on Kasper&#39;s KLogger class.
FactoryCIt end() const
#define LDEBUG(...)
Definition: logger.hh:389
void remove_class(const XIndexType &a_index)
FactoryMap::iterator FactoryIt
indexed_registrar(const XIndexType &a_index)
virtual XBaseType * create(XArgs ... args) const =0
bool has_class(const XIndexType &a_index) const
FactoryMap::const_iterator FactoryCIt
#define allow_singleton_access(class_name)
Definition: singleton.hh:24
FactoryCIt begin() const