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 <iostream>
39 #include <map>
40 #include <string>
41 #include <sstream>
42 #include <memory>
43 #include <functional>
44 
45 #ifdef NEKTAR_USE_THREAD_SAFETY
46 #include <boost/thread/shared_mutex.hpp>
47 #include <boost/thread/locks.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),
120  m_desc(pDesc)
121  {
122  }
123 
124  /// Function used to create instance of class.
126  /// Description of class for use in listing available classes.
127  std::string m_desc;
128  };
129 
130  /// Factory map between key and module data.
131  typedef std::map<tKey, ModuleEntry, tPredicator> TMapFactory;
132 
133 public:
134  NekFactory() = default;
135 
136  /**
137  * @brief Create an instance of the class referred to by \c idKey.
138  *
139  * Searches the factory's map for the given key and returns a shared
140  * base class pointer to a new instance of the associated class.
141  * @param idKey Key of class to create.
142  * @param x Parameter to pass to class constructor.
143  * @returns Base class pointer to new instance.
144  */
145  tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
146  {
147 #ifdef NEKTAR_USE_THREAD_SAFETY
148  ReadLock vReadLock(m_mutex);
149 #endif
150 
151  // Now try and find the key in the map.
152  auto it = getMapFactory()->find(idKey);
153 
154  // If successful, check the CreatorFunction is defined and
155  // create a new instance of the class.
156  if (it != getMapFactory()->end())
157  {
158  ModuleEntry *tmp = &(it->second);
159 #ifdef NEKTAR_USE_THREAD_SAFETY
160  vReadLock.unlock();
161 #endif
162 
163  if (tmp->m_func)
164  {
165  try
166  {
167  return tmp->m_func(args...);
168  }
169  catch (const std::string& s)
170  {
171  std::stringstream errstr;
172  errstr << "Unable to create module: " << idKey << "\n";
173  errstr << s;
174  NEKERROR(ErrorUtil::efatal, errstr.str());
175  }
176  }
177  }
178 
179  // If we get this far, the key doesn't exist, so throw an error.
180  std::stringstream errstr;
181  errstr << "No such module: " << idKey << std::endl;
182  PrintAvailableClasses(errstr);
183  NEKERROR(ErrorUtil::efatal, errstr.str());
184  return tBaseSharedPtr();
185  }
186 
187 
188  /**
189  * @brief Register a class with the factory.
190  *
191  * This function is called by each class in a static context (prior
192  * to the execution of main()) and creates an entry for the class
193  * in the factory's map.
194  * @param idKey Key used to reference the class.
195  * @param classCreator Function to call to create an instance
196  * of this class.
197  * @param pDesc Optional description of class.
198  * @returns The given key \c idKey.
199  */
200  tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator,
201  std::string pDesc = "")
202  {
203 #ifdef NEKTAR_USE_THREAD_SAFETY
204  WriteLock vWriteLock(m_mutex);
205 #endif
206 
207  ModuleEntry e(classCreator, pDesc);
208  getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e));
209  return idKey;
210  }
211 
212 
213  /**
214  * @brief Checks if a particular module is available.
215  */
216  bool ModuleExists(tKey idKey)
217  {
218 #ifdef NEKTAR_USE_THREAD_SAFETY
219  ReadLock vReadLock(m_mutex);
220 #endif
221 
222  // Now try and find the key in the map.
223  auto it = getMapFactory()->find(idKey);
224 
225  if (it != getMapFactory()->end())
226  {
227  return true;
228  }
229  return false;
230  }
231 
232 
233  /**
234  * @brief Prints the available classes to stdout.
235  */
236  void PrintAvailableClasses(std::ostream& pOut = std::cout)
237  {
238 #ifdef NEKTAR_USE_THREAD_SAFETY
239  ReadLock vReadLock(m_mutex);
240 #endif
241 
242  pOut << std::endl << "Available classes: " << std::endl;
243  for (auto &it : *getMapFactory())
244  {
245  pOut << " " << it.first;
246  if (it.second.m_desc != "")
247  {
248  pOut << ":" << std::endl << " "
249  << it.second.m_desc << std::endl;
250  }
251  else
252  {
253  pOut << std::endl;
254  }
255  }
256  }
257 
258 
259  /**
260  * @brief Retrieves a key, given a description
261  */
262  tKey GetKey(std::string pDesc)
263  {
264 #ifdef NEKTAR_USE_THREAD_SAFETY
265  ReadLock vReadLock(m_mutex);
266 #endif
267 
268  for (auto &it : *getMapFactory())
269  {
270  if (it.second.m_desc == pDesc)
271  {
272  return it.first;
273  }
274  }
275  std::string errstr = "Module '" + pDesc + "' is not known.";
276  ASSERTL0(false, errstr);
277  }
278 
279 
280  /**
281  * @brief Returns the description of a class
282  */
283  std::string GetClassDescription(tKey idKey)
284  {
285 #ifdef NEKTAR_USE_THREAD_SAFETY
286  ReadLock vReadLock(m_mutex);
287 #endif
288 
289  // Now try and find the key in the map.
290  auto it = getMapFactory()->find(idKey);
291 
292  std::stringstream errstr;
293  errstr << "No such module: " << idKey << std::endl;
294  ASSERTL0 (it != getMapFactory()->end(), errstr.str());
295  return it->second.m_desc;
296  }
297 
298 protected:
299  /**
300  * @brief Ensure the factory's map is created.
301  * @returns The factory's map.
302  */
304  {
305  return &mMapFactory;
306  }
307 
308 private:
309  NekFactory(const NekFactory& rhs);
311 
313 
314 #ifdef NEKTAR_USE_THREAD_SAFETY
315  boost::shared_mutex m_mutex;
316 #endif
317 
318 };
319 
320 }
321 }
322 
323 #endif
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
#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:200
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:131
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:145
tKey GetKey(std::string pDesc)
Retrieves a key, given a description.
Definition: NekFactory.hpp:262
std::less< tKey > tPredicator
Comparison predicator of key.
Definition: NekFactory.hpp:108
TMapFactory * getMapFactory()
Ensure the factory's map is created.
Definition: NekFactory.hpp:303
NekFactory & operator=(const NekFactory &rhs)
void PrintAvailableClasses(std::ostream &pOut=std::cout)
Prints the available classes to stdout.
Definition: NekFactory.hpp:236
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:216
std::string GetClassDescription(tKey idKey)
Returns the description of a class.
Definition: NekFactory.hpp:283
boost::shared_lock< boost::shared_mutex > ReadLock
Definition: Thread.h:323
boost::unique_lock< boost::shared_mutex > WriteLock
Definition: Thread.h:322
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
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:127
CreatorFunction m_func
Function used to create instance of class.
Definition: NekFactory.hpp:125