Miam-Player  0.8.0
A nice music player
factory.h
Go to the documentation of this file.
1 /******************************************************************************
2  Factory: factory template
3  Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 ******************************************************************************/
19 #ifndef FACTORY_H
20 #define FACTORY_H
21 /*
22  * NOTE: this file can not be included in public headers! It must be used
23  * inside the library, i.e., only be included in cpp or internal header.
24  * Using it outside results in initializing static singleton member twice.
25  */
26 
27 #include <ctype.h> //tolower
28 #include <cstring>
29 #include <time.h>
30 #include <map>
31 #include <vector>
32 #include <algorithm> //std::remove
33 #include "singleton.h"
34 #if 0
35 #include <loki/Singleton.h>
36 template<class Class>
37 Class& Loki::Singleton<Class>::Instance()
38 {
39  return Loki::SingletonHolder<Class>::Instance();
40 }
41 #endif
42 
43 #define FACTORY_REGISTER(BASE, _ID, NAME) FACTORY_REGISTER_ID_TYPE(BASE, BASE##Id_##_ID, BASE##_ID, NAME)
44 #define FACTORY_REGISTER_ID_TYPE(BASE, ID, TYPE, NAME) \
45  FACTORY_REGISTER_ID_TYPE_AUTO(BASE, ID, TYPE, NAME) \
46  bool Register##TYPE##_Man() { \
47  return BASE::Register<TYPE>(ID, NAME); \
48  }
49 
50 #define FACTORY_REGISTER_ID_TYPE_AUTO(BASE, ID, TYPE, NAME) \
51  namespace { \
52  static const struct factory_register_##TYPE { \
53  inline factory_register_##TYPE() { \
54  BASE::Register<TYPE>(ID, NAME); \
55  } \
56  } sInit_##TYPE; \
57  }
58 
59 #define FACTORY_DEFINE(T) \
60  class T##Factory : public Factory<T##Id, T, T##Factory> {}; \
61  bool T::Register(T##Id id, T##Creator c, const char *name) { \
62  DBG(#T "::Register(..., %s)\n", name); \
63  return T##Factory::Instance().registerCreator(id, c) && T##Factory::Instance().registerIdName(id, name); \
64  } \
65  T* T::create(T##Id id) {return T##Factory::Instance().create(id);} \
66  T* T::create(const char* name) { return T::create(T::id(name));} \
67  T##Id* T::next(T##Id *id) { \
68  const std::vector<T##Id>& ids = T##Factory::Instance().registeredIds(); \
69  if (!id) return (T##Id*)&ids[0]; \
70  T##Id *id0 = (T##Id*)&ids[0], *id1 = (T##Id*)&ids[ids.size() - 1]; \
71  if (id >= id0 && id < id1) return id + 1; \
72  if (id == id1) return NULL; \
73  std::vector<T##Id>::const_iterator it = std::find(ids.begin(), ids.end(), *id); \
74  if (it == ids.end()) return NULL; \
75  return (T##Id*)&*(it++); \
76  } \
77  T##Id T::id(const char* name) { DBG(#T "::id(\"%s\")\n", name); return T##Factory::Instance().id(name, false);} \
78  const char* T::name(T##Id id) {return T##Factory::Instance().name(id);}
79 /*
80  * Used in library, can not be used both in library and outside. so we don't need export it
81  */
82 
83 template <typename Id, typename T, class Class>
84 class Factory : public Singleton<Class>
85 {
87  typedef Id ID;
88  typedef T Type;
89  typedef Type* (*Creator)();
90 public:
91  Type* create(const ID& id);
92  template<class C>
93  bool register_(const ID& id) { // register_<C>(id, name)
94  std::pair<typename CreatorMap::iterator, bool> result = creators.insert(std::make_pair(id, create<C>));
95  return result.second;
96  }
97 
98  //template <typename Func>
99  bool registerCreator(const ID& id, const Creator& callback);
100  bool registerIdName(const ID& id, const char* name);
101  bool unregisterCreator(const ID& id);
102  //bool unregisterAll();
103  ID id(const char* name, bool caseSensitive = true) const;
104  const char* name(const ID &id) const;
105  size_t count() const;
106  const std::vector<ID> &registeredIds() const;
107  std::vector<const char*> registeredNames() const;
108  Type* getRandom(); //remove
109 // Type* at(int index);
110 // ID idAt(int index);
111 
112 protected:
113  Factory() {}
114  virtual ~Factory() {}
115 
116 private:
117  template<class C>
118  static Type* create() {
119  return new C();
120  }
121  typedef std::map<ID, Creator> CreatorMap;
122  CreatorMap creators;
123  std::vector<ID> ids;
124  typedef std::map<ID, const char*> NameMap;
125  NameMap name_map; //static?
126 };
127 #if 0
128 template<typename Id, typename T, class Class>
129 typename Factory<Id, T, Class>::CreatorMap Factory<Id, T, Class>::creators;
130 template<typename Id, typename T, class Class>
131 typename Factory<Id, T, Class>::NameMap Factory<Id, T, Class>::name_map;
132 #endif
133 template<typename Id, typename T, class Class>
134 typename Factory<Id, T, Class>::Type *Factory<Id, T, Class>::create(const ID& id)
135 {
136  typename CreatorMap::const_iterator it = creators.find(id);
137  if (it == creators.end()) {
138  DBG("Unknown id ");
139  return 0;
140  //throw std::runtime_error(err_msg.arg(id).toStdString());
141  }
142  return (it->second)();
143 }
144 
145 template<typename Id, typename T, class Class>
146 bool Factory<Id, T, Class>::registerCreator(const ID& id, const Creator& callback)
147 {
148  //DBG("%p id [%d] registered. size=%d\n", &Factory<Id, T, Class>::Instance(), id, ids.size());
149  ids.insert(ids.end(), id);
150  return creators.insert(typename CreatorMap::value_type(id, callback)).second;
151 }
152 
153 template<typename Id, typename T, class Class>
154 bool Factory<Id, T, Class>::registerIdName(const ID& id, const char* name)
155 {
156  return name_map.insert(typename NameMap::value_type(id, name/*.toLower()*/)).second;
157 }
158 
159 template<typename Id, typename T, class Class>
161 {
162  //DBG("Id [%d] unregistered\n", id);
163  ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end());
164  name_map.erase(id);
165  return creators.erase(id) == 1;
166 }
167 
168 template<typename Id, typename T, class Class>
169 typename Factory<Id, T, Class>::ID Factory<Id, T, Class>::id(const char* name, bool caseSensitive) const
170 {
171 #ifdef _MSC_VER
172 #define strcasecmp(s1, s2) _strcmpi(s1, s2)
173 #endif
174  //need 'typename' because 'Factory<Id, T, Class>::NameMap' is a dependent scope
175  for (typename NameMap::const_iterator it = name_map.begin(); it!=name_map.end(); ++it) {
176  if (caseSensitive) {
177  if (it->second == name || !strcmp(it->second, name))
178  return it->first;
179  } else {
180  if (!strcasecmp(it->second, name)) {
181  return it->first;
182  }
183  }
184  }
185  DBG("Not found\n");
186  return ID(); //can not return ref. TODO: Use a ID wrapper class
187 }
188 
189 template<typename Id, typename T, class Class>
190 const char* Factory<Id, T, Class>::name(const ID &id) const
191 {
192  typename NameMap::const_iterator it = name_map.find(id);
193  if (it == name_map.end())
194  return NULL;
195  return it->second;
196 }
197 
198 template<typename Id, typename T, class Class>
199 const std::vector<Id>& Factory<Id, T, Class>::registeredIds() const
200 {
201  return ids;
202 }
203 
204 template<typename Id, typename T, class Class>
205 std::vector<const char*> Factory<Id, T, Class>::registeredNames() const
206 {
207  std::vector<const char*> names;
208  for (typename NameMap::const_iterator it = name_map.begin(); it != name_map.end(); ++it) {
209  names.push_back((*it).second);
210  }
211  return names;
212 }
213 
214 template<typename Id, typename T, class Class>
216 {
217  //DBG("%p size = %d", &Factory<Id, T, Class>::Instance(), ids.size());
218  return ids.size();
219 }
220 
221 template<typename Id, typename T, class Class>
222 typename Factory<Id, T, Class>::Type* Factory<Id, T, Class>::getRandom()
223 {
224  srand(time(0));
225  int index = rand() % ids.size();
226  //DBG("random %d/%d", index, ids.size());
227  ID new_eid = ids.at(index);
228  //DBG("id %d", new_eid);
229  return create(new_eid);
230 }
231 
232 #endif // FACTORY_H
const char * name(const ID &id) const
Definition: factory.h:190
Type * create(const ID &id)
Definition: factory.h:134
#define DBG(fmt,...)
Definition: singleton.h:33
Definition: singleton.h:49
Definition: factory.h:84
size_t count() const
Definition: factory.h:215
bool register_(const ID &id)
Definition: factory.h:93
bool unregisterCreator(const ID &id)
Definition: factory.h:160
ID id(const char *name, bool caseSensitive=true) const
Definition: factory.h:169
bool registerIdName(const ID &id, const char *name)
Definition: factory.h:154
Type * getRandom()
Definition: factory.h:222
Factory()
Definition: factory.h:113
#define DISABLE_COPY(Class)
Definition: singleton.h:40
std::vector< const char * > registeredNames() const
Definition: factory.h:205
bool registerCreator(const ID &id, const Creator &callback)
Definition: factory.h:146
const std::vector< ID > & registeredIds() const
Definition: factory.h:199
virtual ~Factory()
Definition: factory.h:114