Nektar++
NekFactory.hpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: NekFactory.hpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: Factory pattern class for Nektar
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
36 // Primary definition and generator for specialised object factories.
37 #ifndef BOOST_PP_IS_ITERATING
38 
39  #ifndef NEKTAR_LIB_UTILITIES_BASIC_UTILS_NEK_FACTORY_HPP
40  #define NEKTAR_LIB_UTILITIES_BASIC_UTILS_NEK_FACTORY_HPP
41 
42  #include <boost/preprocessor/repetition.hpp>
43  #include <boost/preprocessor/arithmetic/sub.hpp>
44  #include <boost/preprocessor/punctuation/comma_if.hpp>
45  #include <boost/preprocessor/iteration/iterate.hpp>
46  #include <boost/thread/shared_mutex.hpp>
47  #include <boost/thread/locks.hpp>
48 
49  #include <boost/shared_ptr.hpp>
50 
51  #include <iostream>
52  #include <map>
53  #include <string>
54 
56 
57  #ifndef MAX_PARAM
58  #define MAX_PARAM 5 // default maximum number of parameters to support
59  #endif
60 
61 namespace Nektar
62 {
63  namespace LibUtilities
64  {
65  // For unused template parameters.
66  struct none {};
67 
68  // Generate parameter typenames with default type of 'none'
69  #define FACTORY_print(z, n, data) BOOST_PP_CAT(data, n) = none
70  typedef boost::unique_lock<boost::shared_mutex> WriteLock;
71  typedef boost::shared_lock<boost::shared_mutex> ReadLock;
72 
73  /**
74  * @class NekFactory
75  * \brief Provides a generic Factory class.
76  *
77  * Implements a generic object factory. Class-types which use a
78  * potentially arbitrary number of parameters may be used with
79  * specialised forms of the NekFactory. An upper
80  * limit on the number of parameters is imposed by the MAX_PARAM
81  * preprocessor definition in the NekFactory.hpp file. The
82  * specialisations are generated at compile type using Boost
83  * preprocessor by through repeated inclusion of the NekFactory.hpp
84  * file.
85  *
86  * To allow a class to be instantiated by the factory, the
87  * following are required in each class definition (in the case of
88  * a single parameter):
89  * \code
90  * static [baseclass]* create([paramtype1] &P) {
91  * return new [derivedclass](P);
92  * }
93  * static std::string className;
94  * \endcode
95  * and outside the class definition in the implementation:
96  * \code
97  * std::string [derivedclass]::className
98  * = Factory<std::string,[baseclass],[paramtype1]>::
99  * RegisterCreatorFunction("[derivedclass]",
100  * [derivedclass]::create,"Description");
101  * \endcode
102  * The assignment of the static variable className is done through the
103  * call to RegisterCreatorFunction, which registers the class with the
104  * factory prior to the start of the main() routine.
105  *
106  * To create an instance of a derived class, for instance:
107  * \code
108  * [baseclass]* var_name =
109  * Factory<std::string,[baseclass],[paramtype1]>
110  * ::CreateInstance("[derivedclass]",Param1);
111  * \endcode
112  */
113  template <typename tKey, // reference tag (e.g. string, int)
114  typename tBase, // base class
115  BOOST_PP_ENUM(MAX_PARAM, FACTORY_print, typename tParam) >
117  {
118  public:
119  /// Description datatype
120  typedef std::string tDescription;
121  /// Comparison predicator of key
122  typedef std::less<tKey> tPredicator;
123  /// Shared pointer to an object of baseclass type.
124  typedef boost::shared_ptr<tBase> tBaseSharedPtr;
125  /// CreatorFunction type which takes parameter and returns base
126  /// class shared pointer.
127  typedef tBaseSharedPtr (*CreatorFunction) (BOOST_PP_ENUM_PARAMS(MAX_PARAM, tParam));
128 
129  /// Define a struct to hold the information about a module.
130  struct ModuleEntry
131  {
132  ModuleEntry(CreatorFunction pFunc, const tDescription pDesc)
133  : m_func(pFunc),
134  m_desc(pDesc)
135  {
136  }
137 
138  /// Function used to create instance of class.
140  /// Description of class for use in listing available classes.
141  tDescription m_desc;
142  };
143 
144  /// Factory map between key and module data.
145  typedef std::map<tKey, ModuleEntry, tPredicator> TMapFactory;
146  /// Iterator for factory map
148 
149 
150  public:
152 
153  /**
154  * @brief Create an instance of the class referred to by \c idKey.
155  *
156  * Searches the factory's map for the given key and returns a shared
157  * base class pointer to a new instance of the associated class.
158  * @param idKey Key of class to create.
159  * @param x Parameter to pass to class constructor.
160  * @returns Base class pointer to new instance.
161  */
162  tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(MAX_PARAM)
163  BOOST_PP_ENUM_BINARY_PARAMS(MAX_PARAM, tParam, x))
164  {
165 
166  ReadLock vReadLock(m_mutex);
167 
168  // Now try and find the key in the map.
169  TMapFactoryIterator it = getMapFactory()->find(idKey);
170 
171  // If successful, check the CreatorFunction is defined and
172  // create a new instance of the class.
173  if (it != getMapFactory()->end())
174  {
175  ModuleEntry *tmp = &(it->second);
176  vReadLock.unlock();
177 
178  if (tmp->m_func)
179  {
180  try
181  {
182  return tmp->m_func(BOOST_PP_ENUM_PARAMS(MAX_PARAM, x));
183  }
184  catch (const std::string& s)
185  {
186  std::stringstream errstr;
187  errstr << "Unable to create module: " << idKey << "\n";
188  errstr << s;
189  ASSERTL0(false, errstr.str());
190  }
191  }
192  }
193 
194  // If we get this far, the key doesn't exist, so throw an error.
195  std::stringstream errstr;
196  errstr << "No such module: " << idKey << std::endl;
197  PrintAvailableClasses(errstr);
198  ASSERTL0(false, errstr.str());
199  return tBaseSharedPtr();
200  }
201 
202 
203  /**
204  * @brief Register a class with the factory.
205  *
206  * This function is called by each class in a static context (prior
207  * to the execution of main()) and creates an entry for the class
208  * in the factory's map.
209  * @param idKey Key used to reference the class.
210  * @param classCreator Function to call to create an instance
211  * of this class.
212  * @param pDesc Optional description of class.
213  * @returns The given key \c idKey.
214  */
215  tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator,
216  tDescription pDesc = "")
217  {
218  WriteLock vWriteLock(m_mutex);
219 
220  ModuleEntry e(classCreator, pDesc);
221  getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e));
222  return idKey;
223  }
224 
225 
226  /**
227  * @brief Checks if a particular module is available.
228  */
229  bool ModuleExists(tKey idKey)
230  {
231  ReadLock vReadLock(m_mutex);
232 
233  // Now try and find the key in the map.
234  TMapFactoryIterator it = getMapFactory()->find(idKey);
235 
236  if (it != getMapFactory()->end())
237  {
238  return true;
239  }
240  return false;
241  }
242 
243 
244  /**
245  * @brief Prints the available classes to stdout.
246  */
247  void PrintAvailableClasses(std::ostream& pOut = std::cout)
248  {
249  ReadLock vReadLock(m_mutex);
250 
251  pOut << std::endl << "Available classes: " << std::endl;
252  TMapFactoryIterator it;
253  for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
254  {
255  pOut << std::endl << "Available classes: " << std::endl;
256  TMapFactoryIterator it;
257  for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
258  {
259  pOut << " " << it->first;
260  if (it->second.m_desc != "")
261  {
262  pOut << ":" << std::endl << " "
263  << it->second.m_desc << std::endl;
264  }
265  else
266  {
267  pOut << std::endl;
268  }
269  }
270  }
271  }
272 
273 
274  /**
275  * @brief Retrieves a key, given a description
276  */
277  tKey GetKey(tDescription pDesc)
278  {
279  ReadLock vReadLock(m_mutex);
280 
281  TMapFactoryIterator it;
282  for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
283  {
284  if (it->second.m_desc == pDesc)
285  {
286  return it->first;
287  }
288  }
289  std::string errstr = "Module '"
290  + boost::lexical_cast<std::string>(pDesc)
291  + "' is not known.";
292  ASSERTL0(false, errstr);
293  }
294 
295 
296  /**
297  * @brief Returns the description of a class
298  */
299  std::string GetClassDescription(tKey idKey)
300  {
301  ReadLock vReadLock(m_mutex);
302 
303  // Now try and find the key in the map.
304  TMapFactoryIterator it = getMapFactory()->find(idKey);
305 
306  std::stringstream errstr;
307  errstr << "No such module: " << idKey << std::endl;
308  ASSERTL0 (it != getMapFactory()->end(), errstr.str());
309  return it->second.m_desc;
310  }
311 
312  protected:
313  /**
314  * @brief Ensure the factory's map is created.
315  * @returns The factory's map.
316  */
317  TMapFactory* getMapFactory()
318  {
319  return &mMapFactory;
320  }
321 
322  private:
323  NekFactory(const NekFactory& rhs);
324  NekFactory& operator=(const NekFactory& rhs);
325 
326  TMapFactory mMapFactory;
327 
328  boost::shared_mutex m_mutex;
329 
330  };
331 
332  #undef FACTORY_print
333 
334  #define BOOST_PP_ITERATION_LIMITS (0, MAX_PARAM-1)
335  #define BOOST_PP_FILENAME_1 "LibUtilities/BasicUtils/NekFactory.hpp"
336  #include BOOST_PP_ITERATE()
337 
338  }
339 }
340 
341  #endif // end NEKTAR_LIB_UTILITIES_BASIC_UTILS_NEK_FACTORY_HPP
342  #undef MAX_PARAM
343 
344 // Specialisations for the different numbers of parameters.
345 #else
346  // Define the number of parameters
347  #define n BOOST_PP_ITERATION()
348  // Define macro for printing the non-required template parameters
349  #define FACTORY_print(z, n, data) data
350  #include <boost/thread/shared_mutex.hpp>
351  #include <boost/thread/locks.hpp>
352 
353 typedef boost::unique_lock<boost::shared_mutex> WriteLock;
354 typedef boost::shared_lock<boost::shared_mutex> ReadLock;
355 
356  template < typename tKey,
357  typename tBase BOOST_PP_COMMA_IF(n)
358  BOOST_PP_ENUM_PARAMS(n, typename tParam) >
359  class NekFactory< tKey, tBase,
360  BOOST_PP_ENUM_PARAMS(n, tParam)BOOST_PP_COMMA_IF(n)
361  BOOST_PP_ENUM(BOOST_PP_SUB(MAX_PARAM,n), FACTORY_print, none) >
362  {
363  public:
364  typedef std::string tDescription;
365  typedef std::less<tKey> tPredicator;
366  typedef boost::shared_ptr<tBase> tBaseSharedPtr;
367  typedef tBaseSharedPtr (*CreatorFunction) (BOOST_PP_ENUM_PARAMS(n, tParam));
368 
369  struct ModuleEntry
370  {
371  ModuleEntry(CreatorFunction pFunc, const tDescription pDesc)
372  : m_func(pFunc),
373  m_desc(pDesc)
374  {
375  }
376  CreatorFunction m_func;
377  tDescription m_desc;
378  };
379  typedef std::map<tKey, ModuleEntry, tPredicator> TMapFactory;
380  typedef typename TMapFactory::iterator TMapFactoryIterator;
381 
382  NekFactory() : m_mutex() {}
383 
384  tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(n)
385  BOOST_PP_ENUM_BINARY_PARAMS(n, tParam, x))
386  {
387  ReadLock vReadLock(m_mutex);
388 
389  TMapFactoryIterator it = getMapFactory()->find(idKey);
390  if (it != getMapFactory()->end())
391  {
392  ModuleEntry *tmp = &(it->second);
393  vReadLock.unlock();
394 
395  if (tmp->m_func)
396  {
397  try
398  {
399  return tmp->m_func(BOOST_PP_ENUM_PARAMS(n, x));
400  }
401  catch (const std::string& s)
402  {
403  std::stringstream errstr;
404  errstr << "Unable to create module: " << idKey << "\n";
405  errstr << s;
406  ASSERTL0(false, errstr.str());
407  }
408  }
409  }
410  std::stringstream errstr;
411  errstr << "No such module: " << idKey << std::endl;
412  PrintAvailableClasses(errstr);
413  ASSERTL0(false, errstr.str());
414  return tBaseSharedPtr();
415  }
416 
417  tKey RegisterCreatorFunction(tKey idKey,
418  CreatorFunction classCreator,
419  tDescription pDesc = "") {
420  WriteLock vWriteLock(m_mutex);
421 
422  ModuleEntry e(classCreator, pDesc);
423  getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e));
424  return idKey;
425  }
426 
427  bool ModuleExists(tKey idKey)
428  {
429  ReadLock vReadLock(m_mutex);
430 
431  // Now try and find the key in the map.
432  TMapFactoryIterator it = getMapFactory()->find(idKey);
433 
434  if (it != getMapFactory()->end())
435  {
436  return true;
437  }
438  return false;
439  }
440 
441  void PrintAvailableClasses(std::ostream& pOut = std::cout)
442  {
443  ReadLock vReadLock(m_mutex);
444 
445  pOut << std::endl << "Available classes: " << std::endl;
446  TMapFactoryIterator it;
447  for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
448  {
449  pOut << " " << it->first;
450  if (it->second.m_desc != "")
451  {
452  pOut << ":" << std::endl << " "
453  << it->second.m_desc << std::endl;
454  }
455  else
456  {
457  pOut << std::endl;
458  }
459  }
460  }
461 
462  tKey GetKey(tDescription pDesc)
463  {
464  ReadLock vReadLock(m_mutex);
465 
466  TMapFactoryIterator it;
467  for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
468  {
469  if (it->second.m_desc == pDesc)
470  {
471  return it->first;
472  }
473  }
474  std::string errstr = "Module '"
475  + boost::lexical_cast<std::string>(pDesc)
476  + "' is not known.";
477  ASSERTL0(false, errstr);
478  }
479 
480  std::string GetClassDescription(tKey idKey)
481  {
482  ReadLock vReadLock(m_mutex);
483 
484  // Now try and find the key in the map.
485  TMapFactoryIterator it = getMapFactory()->find(idKey);
486 
487  std::stringstream errstr;
488  errstr << "No such module: " << idKey << std::endl;
489  ASSERTL0 (it != getMapFactory()->end(), errstr.str());
490  return it->second.m_desc;
491  }
492 
493  protected:
494  TMapFactory * getMapFactory() {
495  return &mMapFactory;
496  }
497 
498  private:
499  NekFactory(const NekFactory& rhs);
500  NekFactory& operator=(const NekFactory& rhs);
501 
502  TMapFactory mMapFactory;
503  boost::shared_mutex m_mutex;
504 
505  };
506  #undef n
507  #undef FACTORY_print
508 
509 #endif
510 
boost::unique_lock< boost::shared_mutex > WriteLock
Definition: NekFactory.hpp:70
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:161
ModuleEntry(CreatorFunction pFunc, const tDescription pDesc)
Definition: NekFactory.hpp:132
void PrintAvailableClasses(std::ostream &pOut=std::cout)
Prints the available classes to stdout.
Definition: NekFactory.hpp:247
tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(MAX_PARAM) BOOST_PP_ENUM_BINARY_PARAMS(MAX_PARAM, tParam, x))
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:162
std::string GetClassDescription(tKey idKey)
Returns the description of a class.
Definition: NekFactory.hpp:299
CreatorFunction m_func
Function used to create instance of class.
Definition: NekFactory.hpp:139
TMapFactory * getMapFactory()
Ensure the factory's map is created.
Definition: NekFactory.hpp:317
#define MAX_PARAM
Definition: NekFactory.hpp:58
#define FACTORY_print(z, n, data)
Definition: NekFactory.hpp:69
Define a struct to hold the information about a module.
Definition: NekFactory.hpp:130
boost::shared_ptr< tBase > tBaseSharedPtr
Shared pointer to an object of baseclass type.
Definition: NekFactory.hpp:124
TMapFactory::iterator TMapFactoryIterator
Iterator for factory map.
Definition: NekFactory.hpp:147
std::less< tKey > tPredicator
Comparison predicator of key.
Definition: NekFactory.hpp:122
bool ModuleExists(tKey idKey)
Checks if a particular module is available.
Definition: NekFactory.hpp:229
std::string tDescription
Description datatype.
Definition: NekFactory.hpp:120
boost::shared_lock< boost::shared_mutex > ReadLock
Definition: NekFactory.hpp:71
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs typedef NekMatrix< LhsDataType, StandardMatrixTag >::iterator iterator
tKey GetKey(tDescription pDesc)
Retrieves a key, given a description.
Definition: NekFactory.hpp:277
tBaseSharedPtr(* CreatorFunction)(BOOST_PP_ENUM_PARAMS(MAX_PARAM, tParam))
CreatorFunction type which takes parameter and returns base class shared pointer. ...
Definition: NekFactory.hpp:127
NekFactory & operator=(const NekFactory &rhs)
std::map< tKey, ModuleEntry, tPredicator > TMapFactory
Factory map between key and module data.
Definition: NekFactory.hpp:145
tDescription m_desc
Description of class for use in listing available classes.
Definition: NekFactory.hpp:141
Provides a generic Factory class.
Definition: NekFactory.hpp:116
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, tDescription pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:215