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 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Factory pattern class for Nektar
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #ifndef NEKTAR_LIBUTILITIES_BASICUTILS_NEKFACTORY
36 #define NEKTAR_LIBUTILITIES_BASICUTILS_NEKFACTORY
37 
38 #include <functional>
39 #include <iostream>
40 #include <map>
41 #include <memory>
42 #include <sstream>
43 #include <string>
44 
45 #ifdef NEKTAR_USE_THREAD_SAFETY
46 #include <boost/thread/locks.hpp>
47 #include <boost/thread/shared_mutex.hpp>
48 #endif
49 
51 
52 namespace Nektar
53 {
54 namespace LibUtilities
55 {
56 
57 #ifdef NEKTAR_USE_THREAD_SAFETY
58 // Generate parameter typenames with default type of 'none'
59 typedef boost::unique_lock<boost::shared_mutex> WriteLock;
60 typedef boost::shared_lock<boost::shared_mutex> ReadLock;
61 #endif
62 
63 /**
64  * @class NekFactory
65  *
66  * @brief Provides a generic Factory class.
67  *
68  * Implements a generic object factory. Class-types which use an arbitrary
69  * number of parameters may be used via C++ variadic templating.
70  *
71  * To allow a class to be instantiated by the factory, the following are
72  * required in each class definition (in the case of a single parameter):
73  *
74  * \code
75  * static [baseclass]* create([paramtype1] &P) {
76  * return new [derivedclass](P);
77  * }
78  * static std::string className;
79  * \endcode
80  *
81  * and outside the class definition in the implementation:
82  *
83  * \code
84  * std::string [derivedclass]::className
85  * = Factory<std::string,[baseclass],[paramtype1]>::
86  * RegisterCreatorFunction("[derivedclass]",
87  * [derivedclass]::create,"Description");
88  * \endcode
89  *
90  * The assignment of the static variable className is done through the call to
91  * RegisterCreatorFunction, which registers the class with the factory prior to
92  * the start of the main() routine.
93  *
94  * To create an instance of a derived class, for instance:
95  * \code
96  * [baseclass]* var_name =
97  * Factory<std::string,[baseclass],[paramtype1]>
98  * ::CreateInstance("[derivedclass]",Param1);
99  * \endcode
100  */
101 template <typename tKey, // reference tag (e.g. string, int)
102  typename tBase, // base class
103  typename... tParam>
105 {
106 public:
107  /// Comparison predicator of key
108  typedef std::less<tKey> tPredicator;
109  /// Shared pointer to an object of baseclass type.
110  typedef std::shared_ptr<tBase> tBaseSharedPtr;
111  /// CreatorFunction type which takes parameter and returns base class shared
112  /// pointer.
113  typedef std::function<tBaseSharedPtr(tParam...)> CreatorFunction;
114 
115  /// Define a struct to hold the information about a module.
116  struct ModuleEntry
117  {
118  ModuleEntry(CreatorFunction pFunc, const std::string pDesc)
119  : m_func(pFunc), m_desc(pDesc)
120  {
121  }
122 
123  /// Function used to create instance of class.
125  /// Description of class for use in listing available classes.
126  std::string m_desc;
127  };
128 
129  /// Factory map between key and module data.
130  typedef std::map<tKey, ModuleEntry, tPredicator> TMapFactory;
131 
132 public:
133  NekFactory() = default;
134 
135  /**
136  * @brief Create an instance of the class referred to by \c idKey.
137  *
138  * Searches the factory's map for the given key and returns a shared
139  * base class pointer to a new instance of the associated class.
140  * @param idKey Key of class to create.
141  * @param x Parameter to pass to class constructor.
142  * @returns Base class pointer to new instance.
143  */
144  tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
145  {
146 #ifdef NEKTAR_USE_THREAD_SAFETY
147  ReadLock vReadLock(m_mutex);
148 #endif
149 
150  // Now try and find the key in the map.
151  auto it = getMapFactory()->find(idKey);
152 
153  // If successful, check the CreatorFunction is defined and
154  // create a new instance of the class.
155  if (it != getMapFactory()->end())
156  {
157  ModuleEntry *tmp = &(it->second);
158 #ifdef NEKTAR_USE_THREAD_SAFETY
159  vReadLock.unlock();
160 #endif
161 
162  if (tmp->m_func)
163  {
164  try
165  {
166  return tmp->m_func(args...);
167  }
168  catch (const std::string &s)
169  {
170  std::stringstream errstr;
171  errstr << "Unable to create module: " << idKey << "\n";
172  errstr << s;
173  NEKERROR(ErrorUtil::efatal, errstr.str());
174  }
175  }
176  }
177 
178  // If we get this far, the key doesn't exist, so throw an error.
179  std::stringstream errstr;
180  errstr << "No such module: " << idKey << std::endl;
181  PrintAvailableClasses(errstr);
182  NEKERROR(ErrorUtil::efatal, errstr.str());
183  return tBaseSharedPtr();
184  }
185 
186  /**
187  * @brief Register a class with the factory.
188  *
189  * This function is called by each class in a static context (prior
190  * to the execution of main()) and creates an entry for the class
191  * in the factory's map.
192  * @param idKey Key used to reference the class.
193  * @param classCreator Function to call to create an instance
194  * of this class.
195  * @param pDesc Optional description of class.
196  * @returns The given key \c idKey.
197  */
198  tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator,
199  std::string pDesc = "")
200  {
201 #ifdef NEKTAR_USE_THREAD_SAFETY
202  WriteLock vWriteLock(m_mutex);
203 #endif
204 
205  ModuleEntry e(classCreator, pDesc);
206  getMapFactory()->insert(std::pair<tKey, ModuleEntry>(idKey, e));
207  return idKey;
208  }
209 
210  /**
211  * @brief Checks if a particular module is available.
212  */
213  bool ModuleExists(tKey idKey)
214  {
215 #ifdef NEKTAR_USE_THREAD_SAFETY
216  ReadLock vReadLock(m_mutex);
217 #endif
218 
219  // Now try and find the key in the map.
220  auto it = getMapFactory()->find(idKey);
221 
222  if (it != getMapFactory()->end())
223  {
224  return true;
225  }
226  return false;
227  }
228 
229  /**
230  * @brief Prints the available classes to stdout.
231  */
232  void PrintAvailableClasses(std::ostream &pOut = std::cout)
233  {
234 #ifdef NEKTAR_USE_THREAD_SAFETY
235  ReadLock vReadLock(m_mutex);
236 #endif
237 
238  pOut << std::endl << "Available classes: " << std::endl;
239  for (auto &it : *getMapFactory())
240  {
241  pOut << " " << it.first;
242  if (it.second.m_desc != "")
243  {
244  pOut << ":" << std::endl
245  << " " << it.second.m_desc << std::endl;
246  }
247  else
248  {
249  pOut << std::endl;
250  }
251  }
252  }
253 
254  /**
255  * @brief Retrieves a key, given a description
256  */
257  tKey GetKey(std::string pDesc)
258  {
259 #ifdef NEKTAR_USE_THREAD_SAFETY
260  ReadLock vReadLock(m_mutex);
261 #endif
262 
263  for (auto &it : *getMapFactory())
264  {
265  if (it.second.m_desc == pDesc)
266  {
267  return it.first;
268  }
269  }
270  std::string errstr = "Module '" + pDesc + "' is not known.";
271  ASSERTL0(false, errstr);
272  }
273 
274  /**
275  * @brief Returns the description of a class
276  */
277  std::string GetClassDescription(tKey idKey)
278  {
279 #ifdef NEKTAR_USE_THREAD_SAFETY
280  ReadLock vReadLock(m_mutex);
281 #endif
282 
283  // Now try and find the key in the map.
284  auto 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);
305 
307 
308 #ifdef NEKTAR_USE_THREAD_SAFETY
309  boost::shared_mutex m_mutex;
310 #endif
311 };
312 
313 } // namespace LibUtilities
314 } // namespace Nektar
315 
316 #endif
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
Provides a generic Factory class.
Definition: NekFactory.hpp:105
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
NekFactory(const NekFactory &rhs)
std::shared_ptr< tBase > tBaseSharedPtr
Shared pointer to an object of baseclass type.
Definition: NekFactory.hpp:110
std::map< tKey, ModuleEntry, tPredicator > TMapFactory
Factory map between key and module data.
Definition: NekFactory.hpp:130
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
tKey GetKey(std::string pDesc)
Retrieves a key, given a description.
Definition: NekFactory.hpp:257
std::less< tKey > tPredicator
Comparison predicator of key.
Definition: NekFactory.hpp:108
TMapFactory * getMapFactory()
Ensure the factory's map is created.
Definition: NekFactory.hpp:297
NekFactory & operator=(const NekFactory &rhs)
void PrintAvailableClasses(std::ostream &pOut=std::cout)
Prints the available classes to stdout.
Definition: NekFactory.hpp:232
std::function< tBaseSharedPtr(tParam...)> CreatorFunction
CreatorFunction type which takes parameter and returns base class shared pointer.
Definition: NekFactory.hpp:113
bool ModuleExists(tKey idKey)
Checks if a particular module is available.
Definition: NekFactory.hpp:213
std::string GetClassDescription(tKey idKey)
Returns the description of a class.
Definition: NekFactory.hpp:277
boost::shared_lock< boost::shared_mutex > ReadLock
Definition: Thread.h:380
boost::unique_lock< boost::shared_mutex > WriteLock
Definition: Thread.h:379
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
Define a struct to hold the information about a module.
Definition: NekFactory.hpp:117
ModuleEntry(CreatorFunction pFunc, const std::string pDesc)
Definition: NekFactory.hpp:118
std::string m_desc
Description of class for use in listing available classes.
Definition: NekFactory.hpp:126
CreatorFunction m_func
Function used to create instance of class.
Definition: NekFactory.hpp:124