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 
44 #ifdef NEKTAR_USE_THREAD_SAFETY
45 #include <boost/thread/shared_mutex.hpp>
46 #include <boost/thread/locks.hpp>
47 #endif
48 
50 
51 namespace Nektar
52 {
53 namespace LibUtilities
54 {
55 
56 #ifdef NEKTAR_USE_THREAD_SAFETY
57 // Generate parameter typenames with default type of 'none'
58 typedef boost::unique_lock<boost::shared_mutex> WriteLock;
59 typedef boost::shared_lock<boost::shared_mutex> ReadLock;
60 #endif
61 
62 /**
63  * @class NekFactory
64  *
65  * @brief Provides a generic Factory class.
66  *
67  * Implements a generic object factory. Class-types which use an arbitrary
68  * number of parameters may be used via C++ variadic templating.
69  *
70  * To allow a class to be instantiated by the factory, the following are
71  * required in each class definition (in the case of a single parameter):
72  *
73  * \code
74  * static [baseclass]* create([paramtype1] &P) {
75  * return new [derivedclass](P);
76  * }
77  * static std::string className;
78  * \endcode
79  *
80  * and outside the class definition in the implementation:
81  *
82  * \code
83  * std::string [derivedclass]::className
84  * = Factory<std::string,[baseclass],[paramtype1]>::
85  * RegisterCreatorFunction("[derivedclass]",
86  * [derivedclass]::create,"Description");
87  * \endcode
88  *
89  * The assignment of the static variable className is done through the call to
90  * RegisterCreatorFunction, which registers the class with the factory prior to
91  * the start of the main() routine.
92  *
93  * To create an instance of a derived class, for instance:
94  * \code
95  * [baseclass]* var_name =
96  * Factory<std::string,[baseclass],[paramtype1]>
97  * ::CreateInstance("[derivedclass]",Param1);
98  * \endcode
99  */
100 template <typename tKey, // reference tag (e.g. string, int)
101  typename tBase, // base class
102  typename... tParam>
104 {
105 public:
106  /// Comparison predicator of key
107  typedef std::less<tKey> tPredicator;
108  /// Shared pointer to an object of baseclass type.
109  typedef std::shared_ptr<tBase> tBaseSharedPtr;
110  /// CreatorFunction type which takes parameter and returns base class shared
111  /// pointer.
112  typedef tBaseSharedPtr (*CreatorFunction) (tParam...);
113 
114  /// Define a struct to hold the information about a module.
115  struct ModuleEntry
116  {
117  ModuleEntry(CreatorFunction pFunc, const std::string pDesc)
118  : m_func(pFunc),
119  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  /**
188  * @brief Register a class with the factory.
189  *
190  * This function is called by each class in a static context (prior
191  * to the execution of main()) and creates an entry for the class
192  * in the factory's map.
193  * @param idKey Key used to reference the class.
194  * @param classCreator Function to call to create an instance
195  * of this class.
196  * @param pDesc Optional description of class.
197  * @returns The given key \c idKey.
198  */
199  tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator,
200  std::string pDesc = "")
201  {
202 #ifdef NEKTAR_USE_THREAD_SAFETY
203  WriteLock vWriteLock(m_mutex);
204 #endif
205 
206  ModuleEntry e(classCreator, pDesc);
207  getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e));
208  return idKey;
209  }
210 
211 
212  /**
213  * @brief Checks if a particular module is available.
214  */
215  bool ModuleExists(tKey idKey)
216  {
217 #ifdef NEKTAR_USE_THREAD_SAFETY
218  ReadLock vReadLock(m_mutex);
219 #endif
220 
221  // Now try and find the key in the map.
222  auto it = getMapFactory()->find(idKey);
223 
224  if (it != getMapFactory()->end())
225  {
226  return true;
227  }
228  return false;
229  }
230 
231 
232  /**
233  * @brief Prints the available classes to stdout.
234  */
235  void PrintAvailableClasses(std::ostream& pOut = std::cout)
236  {
237 #ifdef NEKTAR_USE_THREAD_SAFETY
238  ReadLock vReadLock(m_mutex);
239 #endif
240 
241  pOut << std::endl << "Available classes: " << std::endl;
242  for (auto &it : *getMapFactory())
243  {
244  pOut << " " << it.first;
245  if (it.second.m_desc != "")
246  {
247  pOut << ":" << std::endl << " "
248  << it.second.m_desc << std::endl;
249  }
250  else
251  {
252  pOut << std::endl;
253  }
254  }
255  }
256 
257 
258  /**
259  * @brief Retrieves a key, given a description
260  */
261  tKey GetKey(std::string pDesc)
262  {
263 #ifdef NEKTAR_USE_THREAD_SAFETY
264  ReadLock vReadLock(m_mutex);
265 #endif
266 
267  for (auto &it : *getMapFactory())
268  {
269  if (it.second.m_desc == pDesc)
270  {
271  return it.first;
272  }
273  }
274  std::string errstr = "Module '" + pDesc + "' is not known.";
275  ASSERTL0(false, errstr);
276  }
277 
278 
279  /**
280  * @brief Returns the description of a class
281  */
282  std::string GetClassDescription(tKey idKey)
283  {
284 #ifdef NEKTAR_USE_THREAD_SAFETY
285  ReadLock vReadLock(m_mutex);
286 #endif
287 
288  // Now try and find the key in the map.
289  auto it = getMapFactory()->find(idKey);
290 
291  std::stringstream errstr;
292  errstr << "No such module: " << idKey << std::endl;
293  ASSERTL0 (it != getMapFactory()->end(), errstr.str());
294  return it->second.m_desc;
295  }
296 
297 protected:
298  /**
299  * @brief Ensure the factory's map is created.
300  * @returns The factory's map.
301  */
302  TMapFactory* getMapFactory()
303  {
304  return &mMapFactory;
305  }
306 
307 private:
308  NekFactory(const NekFactory& rhs);
309  NekFactory& operator=(const NekFactory& rhs);
310 
311  TMapFactory mMapFactory;
312 
313 #ifdef NEKTAR_USE_THREAD_SAFETY
314  boost::shared_mutex m_mutex;
315 #endif
316 
317 };
318 
319 }
320 }
321 
322 #endif
std::shared_ptr< tBase > tBaseSharedPtr
Shared pointer to an object of baseclass type.
Definition: NekFactory.hpp:109
#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 mod...
Definition: ErrorUtil.hpp:209
ModuleEntry(CreatorFunction pFunc, const std::string pDesc)
Definition: NekFactory.hpp:117
std::map< tKey, ModuleEntry, tPredicator > TMapFactory
Factory map between key and module data.
Definition: NekFactory.hpp:130
tBaseSharedPtr(* CreatorFunction)(tParam...)
CreatorFunction type which takes parameter and returns base class shared pointer. ...
Definition: NekFactory.hpp:112
std::string m_desc
Description of class for use in listing available classes.
Definition: NekFactory.hpp:126
void PrintAvailableClasses(std::ostream &pOut=std::cout)
Prints the available classes to stdout.
Definition: NekFactory.hpp:235
Define a struct to hold the information about a module.
Definition: NekFactory.hpp:115
boost::shared_lock< boost::shared_mutex > ReadLock
Definition: Thread.h:323
tKey GetKey(std::string pDesc)
Retrieves a key, given a description.
Definition: NekFactory.hpp:261
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
NekFactory & operator=(const NekFactory &rhs)
std::less< tKey > tPredicator
Comparison predicator of key.
Definition: NekFactory.hpp:107
bool ModuleExists(tKey idKey)
Checks if a particular module is available.
Definition: NekFactory.hpp:215
boost::unique_lock< boost::shared_mutex > WriteLock
Definition: Thread.h:322
TMapFactory * getMapFactory()
Ensure the factory&#39;s map is created.
Definition: NekFactory.hpp:302
std::string GetClassDescription(tKey idKey)
Returns the description of a class.
Definition: NekFactory.hpp:282
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs
CreatorFunction m_func
Function used to create instance of class.
Definition: NekFactory.hpp:124
Provides a generic Factory class.
Definition: NekFactory.hpp:103