libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/base/factory_manager.hpp
Go to the documentation of this file.
00001 
00011 /*
00012  *  Copyright (C) 2009 Juan Pedro BolĂ­var Puente
00013  *  
00014  *  This program is free software: you can redistribute it and/or modify
00015  *  it under the terms of the GNU General Public License as published by
00016  *  the Free Software Foundation, either version 3 of the License, or
00017  *  (at your option) any later version.
00018  *
00019  *  This program is distributed in the hope that it will be useful,
00020  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  *  GNU General Public License for more details.
00023  *
00024  *  You should have received a copy of the GNU General Public License
00025  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00026  *
00027  */
00028 
00029 #ifndef PSYNTH_FACTORY_MANAGER_H_
00030 #define PSYNTH_FACTORY_MANAGER_H_
00031 
00032 #include <map>
00033 #include <functional>
00034 #include <psynth/base/exception.hpp>
00035 #include <psynth/base/iterator.hpp>
00036 #include <psynth/base/singleton.hpp>
00037 
00038 namespace psynth
00039 {
00040 namespace base
00041 {
00042 
00043 PSYNTH_DECLARE_ERROR (error, factory_error);
00044 
00045 namespace detail
00046 {
00047 
00052 template <typename FactoryManager>
00053 struct factory_access
00054 {
00055     typedef typename FactoryManager::key_type key_type;
00056     typedef typename FactoryManager::factory_method factory_method;
00057     
00058     template <class Concrete>
00059     static void add (FactoryManager& self, const key_type& k)
00060     { self.add <Concrete> (k); }
00061 
00062     static void add (FactoryManager& self, const key_type& k, factory_method fn)
00063     { self.add (k, fn); }
00064 
00065     static void del (FactoryManager& self, const key_type& k)
00066     { self.del (k); }
00067 };
00068 
00069 } /* namespace detail */
00070 
00071 
00076 template <class Key, class BasePtr, typename ...Args>
00077 class restricted_factory_manager
00078 {
00079 public:
00080     typedef Key                                key_type;
00081     typedef BasePtr                            pointer_type;
00082     typedef typename pointee<BasePtr>::type    base_type;
00083     
00084     typedef std::function<pointer_type (Args ...)> factory_method;
00085     typedef map_key_iterator<Key, factory_method>  iterator;
00086     
00087     pointer_type create (const Key&, Args...);
00088 
00089     size_t size ()
00090     { return _map.size (); }
00091 
00092     iterator begin ()
00093     { return _map.begin (); }
00094 
00095     iterator end ()
00096     { return _map.end (); }
00097 
00098 protected:
00099     template <class Concrete>
00100     void add (const Key& k);
00101     void add (const Key& k, factory_method fn);
00102     void del (const Key& k);
00103 
00104 private:
00105     friend class detail::factory_access<restricted_factory_manager>;
00106     typedef std::map<Key, factory_method> factory_map;
00107     factory_map _map;
00108 };
00109 
00110 template <class Key, class BasePtr, typename ...Args>
00111 class factory_manager :
00112     public restricted_factory_manager <Key, BasePtr, Args...>
00113 {
00114     typedef restricted_factory_manager <Key, BasePtr, Args...> base;
00115     typedef typename base::factory_method factory_method;
00116     
00117 public:
00118     template <class Concrete>
00119     void add (const Key& k)
00120     { this->base::template add <Concrete> (k); }
00121     
00122     void add (const Key& k, factory_method fn)
00123     { this->base::add (k, fn); }
00124     
00125     void del (const Key& k)
00126     { this->base::del (k); }
00127 };
00128 
00129 template <class GlobalFactory, class Concrete>
00130 struct factory_registrant : public boost::noncopyable
00131 {
00132     typedef typename GlobalFactory::type factory_type;
00133     typedef typename factory_type::key_type key_type;
00134 
00135     factory_registrant (key_type k)
00136     {
00137         detail::factory_access<factory_type>::template add<Concrete> (
00138             GlobalFactory::self (), k);
00139     }
00140 };
00141 
00142 template <typename Key, typename BasePtr, typename... Args>
00143 struct global_factory_manager :
00144         public singleton_holder<factory_manager<
00145                                     Key, BasePtr, Args...> >
00146 {
00147     template <class Concrete>
00148     struct registrant : factory_registrant<global_factory_manager,
00149                                            Concrete>
00150     {
00151         registrant (Key k)
00152             : factory_registrant<global_factory_manager,
00153                                  Concrete> (k)
00154         {}
00155     };
00156 };
00157 
00158 template <typename Key, typename BasePtr, typename... Args>
00159 struct restricted_global_factory_manager :
00160         public singleton_holder<restricted_factory_manager<
00161                                     Key, BasePtr, Args...> >
00162 {
00163     template <class Concrete>
00164     struct registrant : factory_registrant<restricted_global_factory_manager,
00165                                            Concrete>
00166     {
00167         registrant (Key k)
00168             : factory_registrant<restricted_global_factory_manager,
00169                                  Concrete> (k)
00170         {}
00171     };
00172 };
00173 
00174 
00175 } /* namespace base */
00176 } /* namespace psynth */
00177 
00178 #include <psynth/base/factory_manager.tpp>
00179 
00180 #endif /* PSYNTH_FACTORY_MANAGER_H_ */