Hydra 0.20
|
00001 00002 /* 00003 * Copyright (c) 2010 Aleksander B. Demko 00004 * This source code is distributed under the MIT license. 00005 * See the accompanying file LICENSE.MIT.txt for details. 00006 */ 00007 00008 #ifndef __INCLUDED_HYDRA_REGiSTRY_H__ 00009 #define __INCLUDED_HYDRA_REGiSTRY_H__ 00010 00011 #include <memory> 00012 00013 #include <hydra/TR1.h> 00014 00015 #include <QDebug> 00016 00017 namespace hydra 00018 { 00019 template <class BASE, class SUB> BASE* loadfunc_impl(void) { return new SUB(); } 00020 template <class BASE> class Registry; 00021 template <class SUB> class Register; 00022 } 00023 00024 /** 00025 * This allows you to setup a load-time registering plugin system 00026 * that registers objects for any purpose. 00027 * 00028 * You typically make a BASE class for your plugins. In that base class, you: 00029 * - typedef Registry<ThatBase> registry_type 00030 * - static registry_type registry 00031 * - make sure your dtor is virtual 00032 * 00033 * The Regisiter objects will then use BASE::registry to add types. 00034 * You can then inspect and instatiate registered objects via 00035 * the members of BASE::registry 00036 * 00037 * @author Aleksander Demko 00038 */ 00039 template <class BASE> class hydra::Registry 00040 { 00041 public: 00042 typedef BASE base_type; 00043 typedef BASE* (*loadfunc_t)(void); 00044 template <class SUB> BASE* loadfunc_impl(void) { return new SUB(); } 00045 00046 class payload_t { 00047 public: 00048 loadfunc_t loader; 00049 const char *name; /// a name, might be null 00050 public: 00051 payload_t(loadfunc_t _loader, const char *_name = 0) : loader(_loader), name(_name) { } 00052 }; 00053 00054 public: 00055 //Registry(void) { qDebug() << __FUNCTION__; } 00056 //Registry<BASE> & instance(Registry<BASE> & *ptr); 00057 00058 void appendFunc(loadfunc_t func, const char *name = 0) { instance(); dm_funcs->push_back(payload_t(func,name)); } 00059 00060 // none of the following methods are const as they all call instance() 00061 00062 /** 00063 * Returns the number of currently registered types in this registry. 00064 * 00065 * @author Aleksander Demko 00066 */ 00067 size_t size(void) { instance(); return dm_funcs->size(); } 00068 00069 /** 00070 * Instatite the registered type. 00071 * 00072 * @author Aleksander Demko 00073 */ 00074 std::shared_ptr<BASE> create(size_t index) { instance(); return std::shared_ptr<BASE>((*dm_funcs)[index].loader()); } 00075 /** 00076 * Returns the set name of the given registered type. 00077 * Might be null if it was never set. 00078 * 00079 * @author Aleksander Demko 00080 */ 00081 const char * name(size_t index) { instance(); return (*dm_funcs)[index].name; } 00082 00083 private: 00084 // makes sure dm_funcs is not null 00085 void instance(void); 00086 00087 private: 00088 // this is a pointer rather than direct for cleaner start up initialization 00089 // resolution (ie. we can control it somewhat) 00090 // also, auto_ptr since we still want initilization/destruction 00091 // at ctor/dtor time 00092 std::auto_ptr<std::vector<payload_t> > dm_funcs; 00093 }; 00094 00095 /*template <class BASE> 00096 hydra::Registry<BASE> & hydra::Registry<BASE>::instance(Registry<BASE> & *ptr) 00097 { 00098 if (ptr == 0) 00099 ptr = new Registry<BASE>(); 00100 return *ptr; 00101 }*/ 00102 00103 template <class BASE> 00104 void hydra::Registry<BASE>::instance(void) 00105 { 00106 //qDebug() << __FUNCTION__ << (dm_funcs !=0); 00107 if (!dm_funcs.get()) 00108 dm_funcs.reset(new std::vector<payload_t>); 00109 } 00110 00111 /** 00112 * This is the helper class that does the actual registration. 00113 * 00114 * Embeed a static-global instance of one of these per-object 00115 * to be registered. The constructor will then registery the type 00116 * SUB with the registry. 00117 * 00118 * The type SUB should have a registry_type typedef and a register 00119 * variable. You should implement this via a common BASE class 00120 * (see Registry) 00121 * 00122 * @author Aleksander Demko 00123 */ 00124 template <class SUB> class hydra::Register 00125 { 00126 public: 00127 /** 00128 * Registering constructor. 00129 * 00130 * @author Aleksander Demko 00131 */ 00132 Register(void) 00133 { 00134 //if (!SUB::registry) 00135 //SUB::registry = new typename SUB::registry_type; 00136 SUB::registry.appendFunc(&hydra::loadfunc_impl<typename SUB::registry_type::base_type, SUB>); 00137 } 00138 /** 00139 * Registering constructor, with a name. 00140 * 00141 * @author Aleksander Demko 00142 */ 00143 Register(const char *name) 00144 { 00145 SUB::registry.appendFunc(&hydra::loadfunc_impl<typename SUB::registry_type::base_type, SUB>, name); 00146 } 00147 }; 00148 00149 #endif 00150