configuration/include/factory.h

00001 /********************************************************************************
00002  *  FARSA - Total99                                                             *
00003  *  Copyright (C) 2008-2011 Tomassino Ferrauto <t_ferrauto@yahoo.it>            *
00004  *                                                                              *
00005  *  This program is free software; you can redistribute it and/or modify        *
00006  *  it under the terms of the GNU General Public License as published by        *
00007  *  the Free Software Foundation; either version 2 of the License, or           *
00008  *  (at your option) any later version.                                         *
00009  *                                                                              *
00010  *  This program is distributed in the hope that it will be useful,             *
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00013  *  GNU General Public License for more details.                                *
00014  *                                                                              *
00015  *  You should have received a copy of the GNU General Public License           *
00016  *  along with this program; if not, write to the Free Software                 *
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00018  ********************************************************************************/
00019 
00020 #ifndef FACTORY_H
00021 #define FACTORY_H
00022 
00023 #include "configurationconfig.h"
00024 #include "parametersettable.h"
00025 #include <QString>
00026 #include <QStringList>
00027 #include <QMap>
00028 #include <QList>
00029 #include <QVector>
00030 #include <typeinfo>
00031 #include <memory>
00032 
00033 namespace farsa {
00034 
00035 class RealFactory;
00036 class ParameterSettableCreator;
00037 
00058 class FARSA_CONF_API Factory {
00059 public:
00065     static Factory& getInstance();
00066 
00075     static ConfigurationParameters& getTypeDescriptions();
00076 
00080     ~Factory();
00081 
00100     template <class NewClass>
00101     void registerClass(QString className, QString parentClassName);
00102 
00120     QStringList getAllSubclasses(QString className, int levelToStop = -1, bool noAbstractClasses = false);
00121 
00129     bool isAbstract(QString className);
00130 
00131 private:
00138     void cleanupMapsForReRegistration(QString className);
00139 
00146     template <class T, class U>
00147     class Conversion
00148     {
00149         // Type1 and Type2 have surely two different sizes
00150         typedef char Type1;
00151         class Type2
00152         {
00153             char dummy[2];
00154         };
00155         static Type1 Test(U);
00156         static Type2 Test(...);
00157         static T MakeT();
00158     public:
00159         enum { exists = sizeof(Test(MakeT())) == sizeof(Type1) };
00160     };
00161 
00168     template<bool canBeCreated, class H>
00169     class RegisterClassHelper {
00170     public:
00171         RegisterClassHelper(Factory* factory, QString className, QString parentClassName);
00172     };
00173 
00179     Factory();
00180 
00187     Factory(const Factory &other);
00188 
00195     Factory& operator=(const Factory &other);
00196 
00200     QMap<QString, ParameterSettableCreator*> m_classMap;
00201 
00205     QMap<QString, QString> m_parentsMap;
00206     
00210     QMap<QString, QStringList> m_childrenMap;
00211 
00216     friend class RealFactory;
00217 };
00218 
00219 } // end namespace farsa
00220 
00221 // Implementation of template functions
00222 #include "configurationparameters.h"
00223 #include "realfactory.h"
00224 
00225 namespace farsa {
00226 
00227 // This namespace contains helper code. We put it in an inner namespace to avoid polluting the farsa namespace
00228 namespace __Factory_internal {
00229     // this local template check if a class is Abstract
00230     // it's is needed because for register a complete hierarchy it's necessary
00231     // also to check if a class is abstract so it can be possible to register also
00232     // abstract class
00233     template<class T>
00234     struct checkClass {
00235         // Inspired by boost/type_traits/is_abstract.hpp
00236         // Deduction fails if T is void, function type,
00237         // reference type (14.8.2/2)or an abstract class type
00238         // according to review status issue #337
00239         template<class U>
00240         static char check_sig(U (*)[1]);
00241         template<class U>
00242         static short check_sig(...);
00243         static const bool isAbstract = (sizeof(check_sig<T>(0))!=sizeof(char));
00244         // correspond to !isAbstract
00245         static const bool canBeCreated = (sizeof(check_sig<T>(0))==sizeof(char));
00246     };
00247 }
00248 
00249 template <class H>
00250 class Factory::RegisterClassHelper<true, H> {
00251 public:
00252     RegisterClassHelper(Factory* factory, QString className, QString parentClassName) {
00253         factory->cleanupMapsForReRegistration(className);
00254         factory->m_classMap[className] = new ParameterSettableCreatorT<H, Conversion<H *, ParameterSettableInConstructor *>::exists>();
00255         factory->m_parentsMap[className] = parentClassName;
00256         factory->m_childrenMap[parentClassName].append( className );
00257         H::describe( className );
00258     };
00259 };
00260 
00261 template <class H>
00262 class Factory::RegisterClassHelper<false, H> {
00263 public:
00264     RegisterClassHelper(Factory* factory, QString className, QString parentClassName) {
00265         factory->cleanupMapsForReRegistration(className);
00266         factory->m_parentsMap[className] = parentClassName;
00267         factory->m_childrenMap[parentClassName].append( className );
00268     };
00269 };
00270 
00271 template <class NewClass>
00272 void Factory::registerClass(QString className, QString parentClassName)
00273 {
00274     RegisterClassHelper<__Factory_internal::checkClass<NewClass>::canBeCreated, NewClass> registerHelper(this, className, parentClassName );
00275 }
00276 
00277 } // end namespace farsa
00278 
00279 #endif