factory.h
1 /********************************************************************************
2  * FARSA - Total99 *
3  * Copyright (C) 2008-2011 Tomassino Ferrauto <t_ferrauto@yahoo.it> *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
18  ********************************************************************************/
19 
20 #ifndef FACTORY_H
21 #define FACTORY_H
22 
23 #include "configurationconfig.h"
24 #include "parametersettable.h"
25 #include <QString>
26 #include <QStringList>
27 #include <QMap>
28 #include <QList>
29 #include <QVector>
30 #include <typeinfo>
31 #include <memory>
32 
33 namespace farsa {
34 
35 class RealFactory;
36 class ParameterSettableCreator;
37 
58 class FARSA_CONF_API Factory {
59 public:
65  static Factory& getInstance();
66 
75  static ConfigurationParameters& getTypeDescriptions();
76 
80  ~Factory();
81 
100  template <class NewClass>
101  void registerClass(QString className, QString parentClassName);
102 
120  QStringList getAllSubclasses(QString className, int levelToStop = -1, bool noAbstractClasses = false);
121 
129  bool isAbstract(QString className);
130 
131 private:
138  void cleanupMapsForReRegistration(QString className);
139 
146  template <class T, class U>
147  class Conversion
148  {
149  // Type1 and Type2 have surely two different sizes
150  typedef char Type1;
151  class Type2
152  {
153  char dummy[2];
154  };
155  static Type1 Test(U);
156  static Type2 Test(...);
157  static T MakeT();
158  public:
159  enum { exists = sizeof(Test(MakeT())) == sizeof(Type1) };
160  };
161 
168  template<bool canBeCreated, class H>
169  class RegisterClassHelper {
170  public:
171  RegisterClassHelper(Factory* factory, QString className, QString parentClassName);
172  };
173 
179  Factory();
180 
187  Factory(const Factory &other);
188 
195  Factory& operator=(const Factory &other);
196 
200  QMap<QString, ParameterSettableCreator*> m_classMap;
201 
205  QMap<QString, QString> m_parentsMap;
206 
210  QMap<QString, QStringList> m_childrenMap;
211 
216  friend class RealFactory;
217 };
218 
219 } // end namespace farsa
220 
221 // Implementation of template functions
222 #include "configurationparameters.h"
223 #include "realfactory.h"
224 
225 namespace farsa {
226 
227 // This namespace contains helper code. We put it in an inner namespace to avoid polluting the farsa namespace
228 namespace __Factory_internal {
229  // this local template check if a class is Abstract
230  // it's is needed because for register a complete hierarchy it's necessary
231  // also to check if a class is abstract so it can be possible to register also
232  // abstract class
233  template<class T>
234  struct checkClass {
235  // Inspired by boost/type_traits/is_abstract.hpp
236  // Deduction fails if T is void, function type,
237  // reference type (14.8.2/2)or an abstract class type
238  // according to review status issue #337
239  template<class U>
240  static char check_sig(U (*)[1]);
241  template<class U>
242  static short check_sig(...);
243  static const bool isAbstract = (sizeof(check_sig<T>(0))!=sizeof(char));
244  // correspond to !isAbstract
245  static const bool canBeCreated = (sizeof(check_sig<T>(0))==sizeof(char));
246  };
247 }
248 
249 template <class H>
250 class Factory::RegisterClassHelper<true, H> {
251 public:
252  RegisterClassHelper(Factory* factory, QString className, QString parentClassName) {
253  factory->cleanupMapsForReRegistration(className);
255  factory->m_parentsMap[className] = parentClassName;
256  factory->m_childrenMap[parentClassName].append( className );
257  H::describe( className );
258  };
259 };
260 
261 template <class H>
262 class Factory::RegisterClassHelper<false, H> {
263 public:
264  RegisterClassHelper(Factory* factory, QString className, QString parentClassName) {
265  factory->cleanupMapsForReRegistration(className);
266  factory->m_parentsMap[className] = parentClassName;
267  factory->m_childrenMap[parentClassName].append( className );
268  };
269 };
270 
271 template <class NewClass>
272 void Factory::registerClass(QString className, QString parentClassName)
273 {
274  RegisterClassHelper<__Factory_internal::checkClass<NewClass>::canBeCreated, NewClass> registerHelper(this, className, parentClassName );
275 }
276 
277 } // end namespace farsa
278 
279 #endif