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
52namespace Nektar
53{
54namespace LibUtilities
55{
56
57#ifdef NEKTAR_USE_THREAD_SAFETY
58// Generate parameter typenames with default type of 'none'
59typedef boost::unique_lock<boost::shared_mutex> WriteLock;
60typedef 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 */
101template <typename tKey, // reference tag (e.g. string, int)
102 typename tBase, // base class
103 typename... tParam>
105{
106public:
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.
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
132public:
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 args 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 Returns the description of a class
256 */
257 std::string GetClassDescription(tKey idKey)
258 {
259#ifdef NEKTAR_USE_THREAD_SAFETY
260 ReadLock vReadLock(m_mutex);
261#endif
262
263 // Now try and find the key in the map.
264 auto it = getMapFactory()->find(idKey);
265
266 std::stringstream errstr;
267 errstr << "No such module: " << idKey << std::endl;
268 ASSERTL0(it != getMapFactory()->end(), errstr.str());
269 return it->second.m_desc;
270 }
271
272protected:
273 /**
274 * @brief Ensure the factory's map is created.
275 * @returns The factory's map.
276 */
278 {
279 return &mMapFactory;
280 }
281
282private:
283 NekFactory(const NekFactory &rhs) = delete;
284 NekFactory &operator=(const NekFactory &rhs) = delete;
285
287
288#ifdef NEKTAR_USE_THREAD_SAFETY
289 boost::shared_mutex m_mutex;
290#endif
291};
292
293} // namespace LibUtilities
294} // namespace Nektar
295
296#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
TMapFactory * getMapFactory()
Ensure the factory's map is created.
Definition: NekFactory.hpp:277
NekFactory(const NekFactory &rhs)=delete
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
NekFactory & operator=(const NekFactory &rhs)=delete
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
std::less< tKey > tPredicator
Comparison predicator of key.
Definition: NekFactory.hpp:108
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:257
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