Hydra 0.20
hydra.src/hydra/Registry.h
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 
 All Classes Namespaces Functions Variables