1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
/*************************************************************************
* Copyright (C) 2004 by Olivier Galizzi *
* olivier.galizzi@imag.fr *
* Copyright (C) 2004 by Janek Kozicki *
* cosurgi@berlios.de *
* *
* This program is free software; it is licensed under the terms of the *
* GNU General Public License v2 or later. See file LICENSE for details. *
*************************************************************************/
#pragma once
#include<map>
#include<string>
#include<list>
#include<iostream>
#include<cstdio>
#ifndef __GXX_EXPERIMENTAL_CXX0X__
# include<boost/shared_ptr.hpp>
using boost::shared_ptr;
#else
# include<memory>
using std::shared_ptr;
#endif
#include<yade/lib/base/Singleton.hpp>
#include<boost/preprocessor.hpp>
#include "DynLibManager.hpp"
/*! define the following macro to enable experimenta boost::serialization support
Slows the compilation down about 2×.
Python wrapper defines O.saveXML('file.xml') to try it out.
Loading is not yet implemented (should be easy)
*/
#include<boost/version.hpp>
#include<boost/archive/binary_oarchive.hpp>
#include<boost/archive/binary_iarchive.hpp>
#include<boost/archive/xml_oarchive.hpp>
#include<boost/archive/xml_iarchive.hpp>
#include<boost/serialization/export.hpp> // must come after all supported archive types
#include<boost/serialization/base_object.hpp>
#include<boost/serialization/shared_ptr.hpp>
#include<boost/serialization/list.hpp>
#include<boost/serialization/vector.hpp>
#include<boost/serialization/map.hpp>
#include<boost/serialization/nvp.hpp>
#define REGISTER_FACTORABLE(name) \
inline shared_ptr< Factorable > CreateShared##name() \
{ \
return shared_ptr< name > ( new name ); \
} \
inline Factorable* Create##name() \
{ \
return new name; \
} \
inline void * CreatePureCustom##name() \
{ \
return new name; \
} \
const bool registered##name __attribute__ ((unused)) = \
ClassFactory::instance().registerFactorable( #name , \
Create##name , \
CreateShared##name , \
CreatePureCustom##name);
class Factorable;
/*! \brief The class factory of Yade used for serialization purpose and also as a dynamic library loader.
All classes that call the macro REGISTER_FACTORABLE in their header are registered inside the factory
so it is possible to ask the factory to create an instance of that class. This is automatic because the
macro should be outside the class definition, so it is called automatically when the class is loaded by
the program or when a dynamic library is loaded.
This ClassFactory also acts as a dynamic library loader : when you ask for an instance, either the class
already exists inside the factory and a new instance is created, or the class doesn't exist inside the
factory and the ClassFactory will look on the hard drive to know if your class exists inside a dynamic library.
If so the library is loaded and a new instance of the class can be created.
\note ClassFactory is a singleton so you can't create an instance of it because its constructor is private.
You should instead use ClassFactory::instance().createShared("Rigidbody") for example.
*/
class ClassFactory : public Singleton<ClassFactory>
{
private :
/// Pointer on a function that create an instance of a serializable class an return a shared pointer on it
typedef shared_ptr<Factorable> ( *CreateSharedFactorableFnPtr )();
/// Pointer on a function that create an instance of a serializable class an return a C pointer on it
typedef Factorable* ( *CreateFactorableFnPtr )();
/// Pointer on a function that create an instance of a custom class (i.e. not serializable) and return a void C pointer on it
typedef void* ( *CreatePureCustomFnPtr )();
/// Description of a class that is stored inside the factory.
struct FactorableCreators
{
CreateFactorableFnPtr create; /// Used to create a C pointer on the class (if serializable)
CreateSharedFactorableFnPtr createShared; /// Used to create a shared pointer on the class (if serializable)
CreatePureCustomFnPtr createPureCustom; /// Used to create a void C pointer on the class
FactorableCreators() {};
FactorableCreators( CreateFactorableFnPtr c, CreateSharedFactorableFnPtr cs,
CreatePureCustomFnPtr cpc)
{
create = c;
createShared = cs;
createPureCustom = cpc;
};
};
/// Type of a Stl map used to map the registered class name with their FactorableCreators
typedef std::map< std::string , FactorableCreators > FactorableCreatorsMap;
/// The internal dynamic library manager used to load dynamic libraries when an instance of a non loaded class is ask
DynLibManager dlm;
/// Map that contains the name of the registered class and their description
FactorableCreatorsMap map;
ClassFactory() { if(getenv("YADE_DEBUG")) fprintf(stderr,"Constructing ClassFactory.\n"); }
ClassFactory(const ClassFactory&);
ClassFactory& operator=(const ClassFactory&);
virtual ~ClassFactory() {};
DECLARE_LOGGER;
public :
/*! This method is used to register a Factorable class into the factory. It is called only from macro REGISTER_CLASS_TO_FACTORY
\param name the name of the class
\param create a pointer to a function that is able to return a C pointer on the given class
\param createPureCustom a pointer to a function that is able to return a void C pointer on the given class
\param verify a pointer to a function that is able to return the type_info of the given class
\param type type of the class (SERIALIZABLE or CUSTOM)
\param f is true is the class is a fundamental one (Vector3, Quaternion)
\return true if registration is succesfull
*/
bool registerFactorable( std::string name , CreateFactorableFnPtr create,
CreateSharedFactorableFnPtr createShared, CreatePureCustomFnPtr createPureCustom);
/// Create a shared pointer on a serializable class of the given name
shared_ptr<Factorable> createShared( std::string name );
/// Create a C pointer on a serializable class of the given name
Factorable* createPure( std::string name );
/// Create a void C pointer on a class of the given name
void * createPureCustom( std::string name );
/*! Mainly used by the method findType for serialization purpose. Tells if a given type is a serilializable class
\param tp type info of the type to test
\param fundamental is true if the given type is fundamental (Vector3,Quaternion ...)
*/
bool isFactorable(const type_info& tp,bool& fundamental);
bool load(const string& fullFileName);
std::string lastError();
void registerPluginClasses(const char* fileAndClasses[]);
list<string> pluginClasses;
virtual string getClassName() const { return "Factorable"; };
virtual string getBaseClassName(int ) const { return "";};
FRIEND_SINGLETON(ClassFactory);
};
/*! Macro defining what classes can be found in this plugin -- must always be used in the respective .cpp file.
* A function registerThisPluginClasses_FirstPluginName is generated at every occurence. The identifier should
* be unique and avoids use of __COUNTER__ which didn't appear in gcc until 4.3.
*/
#if BOOST_VERSION>=104200
#define _YADE_PLUGIN_BOOST_REGISTER(x,y,z) BOOST_CLASS_EXPORT_IMPLEMENT(z); BOOST_SERIALIZATION_FACTORY_0(z);
#else
#define _YADE_PLUGIN_BOOST_REGISTER(x,y,z) BOOST_CLASS_EXPORT(z); BOOST_SERIALIZATION_FACTORY_0(z);
#endif
// the __attribute__((constructor(priority))) construct not supported before gcc 4.3
// it will only produce warning from log4cxx if not used
#if __GNUC__ == 4 && __GNUC_MINOR__ >=3
#define YADE_CTOR_PRIORITY(p) (p)
#else
#define YADE_CTOR_PRIORITY(p)
#endif
#define _PLUGIN_CHECK_REPEAT(x,y,z) void z::must_use_both_YADE_CLASS_BASE_DOC_ATTRS_and_YADE_PLUGIN(){}
#define _YADE_PLUGIN_REPEAT(x,y,z) BOOST_PP_STRINGIZE(z),
// priority 500 is greater than priority for log4cxx initialization (in core/main/pyboot.cpp); therefore lo5cxx will be initialized before plugins are registered
#define YADE_PLUGIN(plugins) namespace{ __attribute__((constructor)) void BOOST_PP_CAT(registerThisPluginClasses_,BOOST_PP_SEQ_HEAD(plugins)) (void){ const char* info[]={__FILE__ , BOOST_PP_SEQ_FOR_EACH(_YADE_PLUGIN_REPEAT,~,plugins) NULL}; ClassFactory::instance().registerPluginClasses(info);} } BOOST_PP_SEQ_FOR_EACH(_YADE_PLUGIN_BOOST_REGISTER,~,plugins)
// use later: BOOST_PP_SEQ_FOR_EACH(_PLUGIN_CHECK_REPEAT,~,plugins)
|