source: src/CodePatterns/Factory.hpp@ 084729c

Action_Thermostats Add_AtomRandomPerturbation Add_RotateAroundBondAction Add_SelectAtomByNameAction Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_ChronosMutex Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids_IntegrationTest JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since 084729c was 084729c, checked in by Frederik Heber <heber@…>, 8 years ago

Squashed 'ThirdParty/CodePatterns/' content from commit c1e1041

git-subtree-dir: ThirdParty/CodePatterns
git-subtree-split: c1e10418c454f98be2f43d93167642b0008428fc

  • Property mode set to 100644
File size: 14.1 KB
Line 
1/*
2 * Factory.hpp
3 *
4 * Created on: Jan 3, 2011
5 * Author: heber
6 */
7
8#ifndef FACTORY_HPP_
9#define FACTORY_HPP_
10
11// include config.h
12#ifdef HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16#include <map>
17#include <typeinfo>
18
19#include "CodePatterns/Assert.hpp"
20
21#include "CodePatterns/Creator.hpp"
22
23class FactoryTest;
24
25/**
26 * This template produces the generic factory pattern.
27 *
28 * <h1> Factory Howto </h1>
29 * <h2> Introduction </h2>
30 *
31 * A factory is a class that instantiates other types. In order to be able to
32 * do so the following prerequisites must be met:
33 * -# there is a list of types the factory should be able to produce
34 * -# they all must be derived from a common class (e.g. an interface) which is
35 * the type references from the factory will be returned as.
36 *
37 * The reason for the last one is that it is not possible -- except by an ugly
38 * static_cast -- to retrieve the particular type and if nonetheless needed,
39 * factory is probably the wrong pattern). After all what a factory does is
40 * hiding the specifics of a certain subtype, e.g. to control a motor it is not
41 * necessary to know how fast it goes and what it precisely does, you just need
42 * need the throttle as a control and some kind of rpm feedback. This control
43 * and feedback would be abstracted into the interface class.
44 *
45 * <h2>How to make a class Factory</h2>
46 *
47 * If you want to make a class a Factory you can use the following sequence of
48 * steps.
49 *
50 * Before we begin, we assume the following types to represent ...
51 * - Abstract_Interface_Class: the aforementioned common interface of all
52 * particular types the factory should produce.
53 * - Abstract_Encapsulation_Class: we need to connect the interface class (which
54 * must not be a template) with the types to put into the factory. Hence, we
55 * need this (templated) class that encapsulates each possible type as its
56 * template argument while deriving from (and implementing) the abstract
57 * interface as well.
58 * - MyFactory: Your specific factory that spills out references to
59 * Abstract_Interface_Class that are embodied by
60 * Abstract_Encapsulation_Class instances.
61 *
62 * For present code, have a look at RandomNumberDistributionFactory.def,
63 * RandomNumberDistribution_Encapsulation.hpp and
64 * RandomNumberDistributionFactory.hpp.
65 *
66 * @attention{
67 * One last \b warning before we begin: Your types should reside in a distinct
68 * (and not the global) namespace, otherwise you may get strange errors such
69 * as
70 * \verbatim
71 * /usr/include/boost/preprocessor/iteration/detail/local.hpp:34: error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> class stub’
72 * /usr/include/boost/preprocessor/iteration/detail/local.hpp:34: error: expected a type, got ‘(FactoryTypeList::ListOfKnownTypes)0u’
73 * \endverbatim
74 * i.e. he cannot discern between the enumerated types and the true types due.
75 * @remarks But having your particular types in their own name space is always
76 * a good idea.
77 * }
78 *
79 * Now beginning, first remember that all we need is a list of already present
80 * types, i.e. implemented classes. The rest is the stuff below which is all
81 * you need (and although it looks like quite a lot, it is actually not).
82 *
83 * Then, do the following steps:
84 * - create a file "RandomNumberDistributionFactory.def" containing only
85 * preprocessor defines as follows:
86 * @code
87 * #ifndef RANDOMNUMBERDISTRIBUTIONFACTORY_DEF_
88 * #define RANDOMNUMBERDISTRIBUTIONFACTORY_DEF_
89 *
90 * #define type_seq (uniform_smallint)(uniform_int)
91 * #define Abstract_Interface_Class RandomNumberDistribution
92 * #define Abstract_Encapsulation_Class RandomNumberDistribution_Encapsulation
93 * #define type_name_space boost::
94 * #undef type_suffix
95 *
96 * #endif //RANDOMNUMBERDISTRIBUTIONFACTORY_DEF_
97 * @endcode
98 * where \a type_seq is the list of types, each element in round brackets,
99 * \a Abstract_Interface_Class is the class name of the abstract base class
100 * which a reference to the factory spills out, and
101 * \a Abstract_Encapsulation_Class is the class name of the (templated)
102 * encapsulation class of each type. Optionally, these types may reside in
103 * some other name_space, define this one via \a type_name_space (with suffixes
104 * double colons!). If you need something appended to each type, such as "<>"
105 * then add in \a type_suffix. Note that the first two and the last line are
106 * just to avoid double inclusion, also the define made therein is used for
107 * the following step ...
108 * - create the undefine file "RandomNumberDistributionFactory.undef" which
109 * undefines all the previously made definitions to allow for more factories
110 * created without the danger of the various defines getting in the way of
111 * each other:
112 * @code
113 * #ifdef RANDOMNUMBERDISTRIBUTIONFACTORY_DEF_
114 *
115 * #undef type_seq
116 * #undef type_seq_size
117 * #undef Abstract_Interface_Class
118 * #undef Abstract_Encapsulation_Class
119 * #undef type_name_space
120 * #undef type_suffix
121 *
122 * #undef RANDOMNUMBERDISTRIBUTIONFACTORY_DEF_
123 * #endif
124 * @endcode
125 * - Create the encapsulation of the desired types, listed in type_seq via a
126 * templated class:
127 * @code
128 * #include "Creator.hpp" // the creator wrapper
129 * #include "RandomNumberDistribution.hpp" // the abstract interface class
130 * template <class type>
131 * class RandomNumberDistribution_Encapsulation :
132 * public RandomNumberDistribution, // inherit from abstract interface
133 * public Creator< // and creator wrapper that has to know about ...
134 * RandomNumberDistribution, // .. the abstract interface as well ..
135 * RandomNumberDistribution_Encapsulation<type> // .. and the
136 * // encapsulation class we right now define
137 * >
138 * {
139 * public:
140 * // ... some interface functions here with template implementation ...
141 * // i.e. those defined as virtual functions in the abstract interface
142 *
143 * RandomNumberDistribution_Encapsulation() {} // constructor
144 * virtual ~RandomNumberDistribution_Encapsulation() {} // virtual destructor
145 * private:
146 * type encapsulated_type; // the instance of the type to encapsulate
147 * };
148 * @endcode
149 * - in the header of your factory put these before any declaration:
150 * @code
151 * // has to be appear BEFORE Factory.hpp is included!
152 * #include "RandomNumberDistributionFactory.def"
153 * #include "CodePatterns/FactoryTypeList.hpp"
154 * #include "RandomNumberDistributionFactory.undef"
155 * #include "CodePatterns/Factory.hpp"
156 * @endcode
157 * Then declare your factory by inheriting from Factory<Abstract_Interface_Class>
158 * @code
159 * class RandomNumberDistributionFactory :
160 * public Factory<RandomNumberDistribution>
161 * {
162 * RandomNumberDistributionFactory();
163 * virtual ~RandomNumberDistributionFactory();
164 * };
165 * #include "RandomNumberDistributionFactory.undef"
166 * @endcode
167 * where the last includes undefines the defines made in the first step and
168 * assures that another factory can be created without any old defines
169 * getting in the way.
170 * @note FactoryTypeList.hpp is necessary as we can't have a forward
171 * declaration of an enum which we need in the header of Factory<T>.
172 * Hence, there is an extra class the wraps the enum which we inherit.
173 * - finally implement the factory by:
174 * @code
175 * #include "RandomNumberDistribution_Encapsulation.hpp"
176 * #include "RandomNumberDistributionFactory.hpp"
177 * // has to be included BEFORE Factory_impl.hpp!
178 * #include "RandomNumberDistributionFactory.def"
179 * #include "CodePatterns/Factory_impl.hpp"
180 *
181 * RandomNumberDistributionFactory::RandomNumberDistributionFactory() {}
182 * RandomNumberDistributionFactory::~RandomNumberDistributionFactory() {}
183 *
184 * CONSTRUCT_SINGLETON(RandomNumberDistributionFactory)
185 * CONSTRUCT_FACTORY(RandomNumberDistribution)
186 *
187 * #include "RandomNumberDistributionFactory.undef"
188 * @endcode
189 *
190 * That's all.
191 */
192template <class T>
193class Factory : public FactoryTypeList<T>
194{
195public:
196 /** Constructor of class Factory.
197 *
198 */
199 Factory()
200 {
201 FillEnumTable();
202 FillPrototypeTable();
203 }
204
205 /** (virtual) Destructor of class Factory.
206 *
207 */
208 virtual ~Factory()
209 {
210 // clear out factories map to allow boost::shared_ptr to do their work (i.e. to release mem)
211 // this is necessary as factory is an object
212 enums.clear();
213 names.clear();
214 for (typename InstanceTable::iterator iter = PrototypeTable.begin();
215 !PrototypeTable.empty();
216 iter = PrototypeTable.begin()) {
217 delete (iter->second);
218 PrototypeTable.erase(iter);
219 }
220 PrototypeTable.clear();
221 }
222
223
224 /** Enumeration of all types known to this factory
225 */
226 typedef enum FactoryTypeList<T>::ListOfKnownTypes TypeList;
227
228 /** Setter for currenttype to produce.
229 *
230 * @param instance_name name of type
231 */
232 void setCurrentType(const std::string instance_name)
233 {
234 ASSERT(enums.count(instance_name) != 0,
235 "Factory<"+toString(typeid(T).name())+">::setCurrentType() - type "+instance_name+" is not registered.");
236 currenttype = enums[instance_name];
237 }
238
239 /** Setter for currenttype to produce.
240 *
241 * @param instance_type enumeration index of type
242 */
243 void setCurrentType(TypeList instance_type)
244 {
245 ASSERT(names.count(instance_type) != 0,
246 "Factory<"+toString(typeid(T).name())+">::setCurrentType() - enum type "+toString(instance_type)+" is not registered.");
247 currenttype = instance_type;
248 }
249
250 /** Getter for currenttype to produce.
251 *
252 * @return name of currenttype
253 */
254 const std::string & getCurrentTypeName() const
255 {
256 return names[currenttype];
257 }
258
259 /** Getter for currenttype to produce.
260 *
261 * @return enumeration index of currenttype
262 */
263 TypeList getCurrentTypeEnum() const
264 {
265 return currenttype;
266 }
267
268 /** Getter for desired type of product.
269 *
270 * @param enumeration index of product
271 * @return reference to copy of product
272 */
273 T* getProduct(TypeList instance_type) const
274 {
275 ASSERT(names.count(instance_type) != 0,
276 "Factory<"+toString(typeid(T).name())+">::getProduct() - enum type "+toString(instance_type)+" is not registered.");
277 return PrototypeTable[instance_type]->create();
278 }
279
280 /** Getter for desired type of product.
281 *
282 * @param name of product
283 * @return reference to copy of product
284 */
285 T* getProduct(const std::string instance_name) const
286 {
287 ASSERT(enums.count(instance_name) != 0,
288 "Factory<"+toString(typeid(T).name())+">::getProduct() - type name "+instance_name+" is not registered.");
289 return PrototypeTable[ enums[instance_name] ]->create();
290 }
291
292 /** Getter for desired type of product.
293 *
294 * @param type_info object of the desired type
295 * @return reference to copy of current type product or NULL if type mismatch
296 */
297 T* getProduct(const std::type_info &instance_type_info) const
298 {
299 ASSERT(types.count(instance_type_info.name()) != 0,
300 "Factory<"+toString(typeid(T).name())+">::getProduct() - type info name "+instance_type_info.name()+" is not registered.");
301 return PrototypeTable[ types[instance_type_info.name()] ]->create();
302 }
303
304 /** Getter for current type of product.
305 *
306 * @return reference to copy of current type product
307 */
308 T* getProduct() const
309 {
310 return PrototypeTable[currenttype]->create();
311 }
312
313 /** Getter for the name of the desired type of product.
314 *
315 * @return name of distribution
316 */
317 const std::string &getName(TypeList instance_type) const
318 {
319 ASSERT(names.count(instance_type) != 0,
320 "Factory<"+toString(typeid(T).name())+">::getName() - enum type "+toString(instance_type)+" is not registered.");
321 return names[instance_type];
322 }
323
324 /** Getter for the enumeration index of the desired type of product.
325 *
326 * @return enum of distribution
327 */
328 TypeList getEnum(const std::string instance_name) const
329 {
330 ASSERT(enums.count(instance_name) != 0,
331 "Factory<"+toString(typeid(T).name())+">::getEnum() - type name "+instance_name+" is not registered.");
332 return enums[instance_name];
333 }
334
335
336protected:
337
338 /** Creates instances of all possible distribution types
339 * and stores them in \a DistributionPrototypeTable.
340 */
341 void FillPrototypeTable();
342
343 /** Create association for enums to strings and vice versa
344 * and stores them in \a distributions tables.
345 */
346 void FillEnumTable();
347
348 typedef std::map<
349 std::string,
350 TypeList
351 > TypeMap;
352 typedef std::map<
353 std::string,
354 TypeList
355 > EnumMap;
356 typedef std::map<
357 TypeList,
358 ICreator<T> *
359 > InstanceTable;
360 typedef std::map<
361 TypeList,
362 std::string
363 > NameMap;
364
365 static TypeList currenttype;
366 static TypeMap types;
367 static EnumMap enums;
368 static InstanceTable PrototypeTable;
369 static NameMap names;
370};
371
372template <class T> typename Factory<T>::TypeList Factory<T>::currenttype = (typename Factory<T>::TypeList)0;
373template <class T> typename Factory<T>::TypeMap Factory<T>::types;
374template <class T> typename Factory<T>::EnumMap Factory<T>::enums;
375template <class T> typename Factory<T>::NameMap Factory<T>::names;
376template <class T> typename Factory<T>::InstanceTable Factory<T>::PrototypeTable;
377
378/**
379 * This define allows simple instantiation of the necessary factory functions
380 * at a chosen place.
381 */
382#define CONSTRUCT_FACTORY(InstanceType) \
383 template Factory<InstanceType>::Factory(); \
384 template Factory<InstanceType>::~Factory(); \
385 template void Factory<InstanceType>::setCurrentType(const std::string instance_name); \
386 template void Factory<InstanceType>::setCurrentType(TypeList instance_type); \
387 template const std::string & Factory<InstanceType>::getCurrentTypeName() const; \
388 template Factory<InstanceType>::TypeList Factory<InstanceType>::getCurrentTypeEnum() const; \
389 template InstanceType* Factory<InstanceType>::getProduct(TypeList instance_type) const; \
390 template InstanceType* Factory<InstanceType>::getProduct(const std::string instance_name) const; \
391 template const std::string &Factory<InstanceType>::getName(TypeList instance_type) const; \
392 template Factory<InstanceType>::TypeList Factory<InstanceType>::getEnum(const std::string instance_name) const;
393
394#endif /* FACTORY_HPP_ */
Note: See TracBrowser for help on using the repository browser.