Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 
47  #include <boost/shared_ptr.hpp>
48 
49  #include <iostream>
50  #include <map>
51  #include <string>
52 
54 
55  #ifndef MAX_PARAM
56  #define MAX_PARAM 5 // default maximum number of parameters to support
57  #endif
58 
59 namespace Nektar
60 {
61  namespace LibUtilities
62  {
63  // For unused template parameters.
64  struct none {};
65 
66  // Generate parameter typenames with default type of 'none'
67  #define FACTORY_print(z, n, data) BOOST_PP_CAT(data, n) = none
68 
69  /**
70  * @class NekFactory
71  * \brief Provides a generic Factory class.
72  *
73  * Implements a generic object factory. Class-types which use a
74  * potentially arbitrary number of parameters may be used with
75  * specialised forms of the NekFactory. An upper
76  * limit on the number of parameters is imposed by the MAX_PARAM
77  * preprocessor definition in the NekFactory.hpp file. The
78  * specialisations are generated at compile type using Boost
79  * preprocessor by through repeated inclusion of the NekFactory.hpp
80  * file.
81  *
82  * To allow a class to be instantiated by the factory, the
83  * following are required in each class definition (in the case of
84  * a single parameter):
85  * \code
86  * static [baseclass]* create([paramtype1] &P) {
87  * return new [derivedclass](P);
88  * }
89  * static std::string className;
90  * \endcode
91  * and outside the class definition in the implementation:
92  * \code
93  * std::string [derivedclass]::className
94  * = Factory<std::string,[baseclass],[paramtype1]>::
95  * RegisterCreatorFunction("[derivedclass]",
96  * [derivedclass]::create,"Description");
97  * \endcode
98  * The assignment of the static variable className is done through the
99  * call to RegisterCreatorFunction, which registers the class with the
100  * factory prior to the start of the main() routine.
101  *
102  * To create an instance of a derived class, for instance:
103  * \code
104  * [baseclass]* var_name =
105  * Factory<std::string,[baseclass],[paramtype1]>
106  * ::CreateInstance("[derivedclass]",Param1);
107  * \endcode
108  */
109  template <typename tKey, // reference tag (e.g. string, int)
110  typename tBase, // base class
111  BOOST_PP_ENUM(MAX_PARAM, FACTORY_print, typename tParam) >
113  {
114  public:
115  /// Description datatype
116  typedef std::string tDescription;
117  /// Comparison predicator of key
118  typedef std::less<tKey> tPredicator;
119  /// Shared pointer to an object of baseclass type.
120  typedef boost::shared_ptr<tBase> tBaseSharedPtr;
121  /// CreatorFunction type which takes parameter and returns base
122  /// class shared pointer.
123  typedef tBaseSharedPtr (*CreatorFunction) (BOOST_PP_ENUM_PARAMS(MAX_PARAM, tParam));
124 
125  /// Define a struct to hold the information about a module.
126  struct ModuleEntry
127  {
129  : m_func(pFunc),
130  m_desc(pDesc)
131  {
132  }
133 
134  /// Function used to create instance of class.
136  /// Description of class for use in listing available classes.
138  };
139 
140  /// Factory map between key and module data.
141  typedef std::map<tKey, ModuleEntry, tPredicator> TMapFactory;
142  /// Iterator for factory map
144 
145 
146  public:
148 
149  /**
150  * @brief Create an instance of the class referred to by \c idKey.
151  *
152  * Searches the factory's map for the given key and returns a shared
153  * base class pointer to a new instance of the associated class.
154  * @param idKey Key of class to create.
155  * @param x Parameter to pass to class constructor.
156  * @returns Base class pointer to new instance.
157  */
158  tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(MAX_PARAM)
159  BOOST_PP_ENUM_BINARY_PARAMS(MAX_PARAM, tParam, x))
160  {
161  // Now try and find the key in the map.
162  TMapFactoryIterator it = getMapFactory()->find(idKey);
163 
164  // If successful, check the CreatorFunction is defined and
165  // create a new instance of the class.
166  if (it != getMapFactory()->end())
167  {
168  if (it->second.m_func)
169  {
170  try
171  {
172  return it->second.m_func(BOOST_PP_ENUM_PARAMS(MAX_PARAM, x));
173  }
174  catch (const std::string& s)
175  {
176  std::stringstream errstr;
177  errstr << "Unable to create module: " << idKey << "\n";
178  errstr << s;
179  ASSERTL0(false, errstr.str());
180  }
181  }
182  }
183 
184  // If we get this far, the key doesn't exist, so throw an error.
185  std::stringstream errstr;
186  errstr << "No such module: " << idKey << std::endl;
187  PrintAvailableClasses(errstr);
188  ASSERTL0(false, errstr.str());
189  return tBaseSharedPtr();
190  }
191 
192 
193  /**
194  * @brief Register a class with the factory.
195  *
196  * This function is called by each class in a static context (prior
197  * to the execution of main()) and creates an entry for the class
198  * in the factory's map.
199  * @param idKey Key used to reference the class.
200  * @param classCreator Function to call to create an instance
201  * of this class.
202  * @param pDesc Optional description of class.
203  * @returns The given key \c idKey.
204  */
205  tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator,
206  tDescription pDesc = "")
207  {
208  ModuleEntry e(classCreator, pDesc);
209  getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e));
210  return idKey;
211  }
212 
213 
214  /**
215  * @brief Checks if a particular module is available.
216  */
217  bool ModuleExists(tKey idKey)
218  {
219  // Now try and find the key in the map.
220  TMapFactoryIterator it = getMapFactory()->find(idKey);
221 
222  if (it != getMapFactory()->end())
223  {
224  return true;
225  }
226  return false;
227  }
228 
229 
230  /**
231  * @brief Prints the available classes to stdout.
232  */
233  void PrintAvailableClasses(std::ostream& pOut = std::cout)
234  {
235  pOut << std::endl << "Available classes: " << std::endl;
237  for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
238  {
239  pOut << std::endl << "Available classes: " << std::endl;
241  for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
242  {
243  pOut << " " << it->first;
244  if (it->second.m_desc != "")
245  {
246  pOut << ":" << std::endl << " "
247  << it->second.m_desc << std::endl;
248  }
249  else
250  {
251  pOut << std::endl;
252  }
253  }
254  }
255  }
256 
257 
258  /**
259  * @brief Retrieves a key, given a description
260  */
261  tKey GetKey(tDescription pDesc)
262  {
264  for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
265  {
266  if (it->second.m_desc == pDesc)
267  {
268  return it->first;
269  }
270  }
271  std::string errstr = "Module '"
272  + boost::lexical_cast<std::string>(pDesc)
273  + "' is not known.";
274  ASSERTL0(false, errstr);
275  }
276 
277 
278  /**
279  * @brief Returns the description of a class
280  */
281  std::string GetClassDescription(tKey idKey)
282  {
283  // Now try and find the key in the map.
284  TMapFactoryIterator it = getMapFactory()->find(idKey);
285 
286  std::stringstream errstr;
287  errstr << "No such module: " << idKey << std::endl;
288  ASSERTL0 (it != getMapFactory()->end(), errstr.str());
289  return it->second.m_desc;
290  }
291 
292  protected:
293  /**
294  * @brief Ensure the factory's map is created.
295  * @returns The factory's map.
296  */
298  {
299  return &mMapFactory;
300  }
301 
302  private:
303  NekFactory(const NekFactory& rhs);
304  NekFactory& operator=(const NekFactory& rhs);
305 
307 
308  };
309 
310  #undef FACTORY_print
311 
312  #define BOOST_PP_ITERATION_LIMITS (0, MAX_PARAM-1)
313  #define BOOST_PP_FILENAME_1 "LibUtilities/BasicUtils/NekFactory.hpp"
314  #include BOOST_PP_ITERATE()
315 
316  }
317 }
318 
319  #endif // end NEKTAR_LIB_UTILITIES_BASIC_UTILS_NEK_FACTORY_HPP
320  #undef MAX_PARAM
321 
322 // Specialisations for the different numbers of parameters.
323 #else
324  // Define the number of parameters
325  #define n BOOST_PP_ITERATION()
326  // Define macro for printing the non-required template parameters
327  #define FACTORY_print(z, n, data) data
328 
329  template < typename tKey,
330  typename tBase BOOST_PP_COMMA_IF(n)
331  BOOST_PP_ENUM_PARAMS(n, typename tParam) >
332  class NekFactory< tKey, tBase,
333  BOOST_PP_ENUM_PARAMS(n, tParam)BOOST_PP_COMMA_IF(n)
334  BOOST_PP_ENUM(BOOST_PP_SUB(MAX_PARAM,n), FACTORY_print, none) >
335  {
336  public:
337  typedef std::string tDescription;
338  typedef std::less<tKey> tPredicator;
339  typedef boost::shared_ptr<tBase> tBaseSharedPtr;
340  typedef tBaseSharedPtr (*CreatorFunction) (BOOST_PP_ENUM_PARAMS(n, tParam));
341 
342  struct ModuleEntry
343  {
344  ModuleEntry(CreatorFunction pFunc, const tDescription pDesc)
345  : m_func(pFunc),
346  m_desc(pDesc)
347  {
348  }
349  CreatorFunction m_func;
350  tDescription m_desc;
351  };
352  typedef std::map<tKey, ModuleEntry, tPredicator> TMapFactory;
353  typedef typename TMapFactory::iterator TMapFactoryIterator;
354 
355  NekFactory() {}
356 
357  tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(n)
358  BOOST_PP_ENUM_BINARY_PARAMS(n, tParam, x))
359  {
360  TMapFactoryIterator it = getMapFactory()->find(idKey);
361  if (it != getMapFactory()->end())
362  {
363  if (it->second.m_func)
364  {
365  try
366  {
367  return it->second.m_func(BOOST_PP_ENUM_PARAMS(n, x));
368  }
369  catch (const std::string& s)
370  {
371  std::stringstream errstr;
372  errstr << "Unable to create module: " << idKey << "\n";
373  errstr << s;
374  ASSERTL0(false, errstr.str());
375  }
376  }
377  }
378  std::stringstream errstr;
379  errstr << "No such module: " << idKey << std::endl;
380  PrintAvailableClasses(errstr);
381  ASSERTL0(false, errstr.str());
382  return tBaseSharedPtr();
383  }
384 
385  tKey RegisterCreatorFunction(tKey idKey,
386  CreatorFunction classCreator,
387  tDescription pDesc = "") {
388  ModuleEntry e(classCreator, pDesc);
389  getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e));
390  return idKey;
391  }
392 
393  bool ModuleExists(tKey idKey)
394  {
395  // Now try and find the key in the map.
396  TMapFactoryIterator it = getMapFactory()->find(idKey);
397 
398  if (it != getMapFactory()->end())
399  {
400  return true;
401  }
402  return false;
403  }
404 
405  void PrintAvailableClasses(std::ostream& pOut = std::cout)
406  {
407  pOut << std::endl << "Available classes: " << std::endl;
408  TMapFactoryIterator it;
409  for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
410  {
411  pOut << " " << it->first;
412  if (it->second.m_desc != "")
413  {
414  pOut << ":" << std::endl << " "
415  << it->second.m_desc << std::endl;
416  }
417  else
418  {
419  pOut << std::endl;
420  }
421  }
422  }
423 
424  tKey GetKey(tDescription pDesc)
425  {
426  TMapFactoryIterator it;
427  for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
428  {
429  if (it->second.m_desc == pDesc)
430  {
431  return it->first;
432  }
433  }
434  std::string errstr = "Module '"
435  + boost::lexical_cast<std::string>(pDesc)
436  + "' is not known.";
437  ASSERTL0(false, errstr);
438  }
439 
440  std::string GetClassDescription(tKey idKey)
441  {
442  // Now try and find the key in the map.
443  TMapFactoryIterator it = getMapFactory()->find(idKey);
444 
445  std::stringstream errstr;
446  errstr << "No such module: " << idKey << std::endl;
447  ASSERTL0 (it != getMapFactory()->end(), errstr.str());
448  return it->second.m_desc;
449  }
450 
451  protected:
452  TMapFactory * getMapFactory() {
453  return &mMapFactory;
454  }
455 
456  private:
457  NekFactory(const NekFactory& rhs);
458  NekFactory& operator=(const NekFactory& rhs);
459 
460  TMapFactory mMapFactory;
461  };
462  #undef n
463  #undef FACTORY_print
464 
465 #endif
466