PTLib Version 2.12.9

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
pfactory.h
Go to the documentation of this file.
1 /*
2 * factory.h
3 *
4 * Abstract Factory Classes
5 *
6 * Portable Windows Library
7 *
8 * Copyright (C) 2004 Post Increment
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * The Original Code is Portable Windows Library.
21 *
22 * The Initial Developer of the Original Code is Post Increment
23 *
24 * Contributor(s): ______________________________________.
25 *
26 * $Revision: 27635 $
27 * $Author: rjongbloed $
28 * $Date: 2012-05-15 16:14:08 +1000 (Tue, 15 May 2012) $
29 */
30
31 #ifndef PTLIB_FACTORY_H
32 #define PTLIB_FACTORY_H
33
34 #ifdef P_USE_PRAGMA
35 #pragma interface
36 #endif
37
38 #include <ptlib.h>
39
40 #include <typeinfo>
41 #include <string>
42 #include <map>
43 #include <vector>
44
45 #if defined(_MSC_VER)
46 #pragma warning(disable:4786)
47 #endif
48
115 class PFactoryBase
116 {
117 protected:
118 PFactoryBase()
119 { }
120 public:
121 virtual ~PFactoryBase()
122 { }
123
124 virtual void DestroySingletons() = 0;
125
126 class FactoryMap : public std::map<std::string, PFactoryBase *>, public PMutex
127 {
128 public:
129 ~FactoryMap();
130 void DestroySingletons();
131 };
132
133 static FactoryMap & GetFactories();
134
135 protected:
136 static PFactoryBase & InternalGetFactory(const std::string & className, PFactoryBase * (*createFactory)());
137
138 template <class TheFactory> static PFactoryBase * CreateFactory() { return new TheFactory; }
139
140 template <class TheFactory> static TheFactory & GetFactoryAs()
141 {
142 return dynamic_cast<TheFactory&>(InternalGetFactory(typeid(TheFactory).name(), CreateFactory<TheFactory>));
143 }
144
145 protected:
146 PMutex m_mutex;
147
148 private:
149 PFactoryBase(const PFactoryBase &) {}
150 void operator=(const PFactoryBase &) {}
151 };
152
153
156 template <class AbstractClass, typename ParamType, typename KeyType>
157 class PFactoryTemplate : public PFactoryBase
158 {
159 public:
160 class WorkerBase;
161
162 typedef AbstractClass Abstract_T;
163 typedef ParamType Param_T;
164 typedef KeyType Key_T;
165 typedef std::vector<Key_T> KeyList_T;
166 typedef std::map<Key_T, WorkerBase*> WorkerMap_T;
167 typedef typename WorkerMap_T::iterator WorkerIter_T;
168
169 class WorkerBase
170 {
171 public:
172 enum Types {
173 NonSingleton,
174 StaticSingleton,
175 DynamicSingleton
176 };
177
178 WorkerBase(bool singleton = false)
179 : m_type(singleton ? DynamicSingleton : NonSingleton)
180 , m_singletonInstance(NULL)
181 {
182 }
183
184 WorkerBase(Abstract_T * instance, bool delSingleton = true)
185 : m_type(delSingleton ? DynamicSingleton : StaticSingleton)
186 , m_singletonInstance(instance)
187 {
188 }
189
190 virtual ~WorkerBase()
191 {
192 DestroySingleton();
193 }
194
195 Abstract_T * CreateInstance(Param_T param)
196 {
197 if (m_type == NonSingleton)
198 return Create(param);
199
200 if (m_singletonInstance == NULL)
201 m_singletonInstance = Create(param);
202 return m_singletonInstance;
203 }
204
205 virtual void DestroySingleton()
206 {
207 if (m_type == DynamicSingleton) {
208 delete m_singletonInstance;
209 m_singletonInstance = NULL;
210 }
211 }
212
213 bool IsSingleton() const { return m_type != NonSingleton; }
214
215 protected:
216 virtual Abstract_T * Create(Param_T /*param*/) const
217 {
218 PAssert(this->m_type == StaticSingleton, "Incorrect factory worker descendant");
219 return this->m_singletonInstance;
220 }
221
222 Types m_type;
223 Abstract_T * m_singletonInstance;
224 };
225
226 virtual void DestroySingletons()
227 {
228 for (WorkerIter_T it = m_workers.begin(); it != m_workers.end(); ++it)
229 it->second->DestroySingleton();
230 }
231
232 protected:
233 PFactoryTemplate()
234 { }
235
236 ~PFactoryTemplate()
237 {
238 DestroySingletons();
239 }
240
241 bool InternalRegister(const Key_T & key, WorkerBase * worker)
242 {
243 PWaitAndSignal mutex(m_mutex);
244 if (m_workers.find(key) != m_workers.end())
245 return false;
246
247 PMEMORY_IGNORE_ALLOCATIONS_FOR_SCOPE;
248 m_workers[key] = PAssertNULL(worker);
249 return true;
250 }
251
252 bool InternalRegister(const Key_T & key, Abstract_T * instance, bool autoDeleteInstance)
253 {
254 PWaitAndSignal mutex(m_mutex);
255 if (m_workers.find(key) != m_workers.end())
256 return false;
257
258 PMEMORY_IGNORE_ALLOCATIONS_FOR_SCOPE;
259 m_workers[key] = PNEW WorkerBase(instance, autoDeleteInstance);
260 return true;
261 }
262
263 PBoolean InternalRegisterAs(const Key_T & newKey, const Key_T & oldKey)
264 {
265 PWaitAndSignal mutex(m_mutex);
266 if (m_workers.find(oldKey) == m_workers.end())
267 return false;
268
269 m_workers[newKey] = m_workers[oldKey];
270 return true;
271 }
272
273 void InternalUnregister(const Key_T & key)
274 {
275 m_mutex.Wait();
276 m_workers.erase(key);
277 m_mutex.Signal();
278 }
279
280 void InternalUnregister(WorkerBase * instance)
281 {
282 m_mutex.Wait();
283 for (WorkerIter_T it = m_workers.begin(); it != m_workers.end(); ++it) {
284 if (it->second == instance) {
285 m_workers.erase(it);
286 break;
287 }
288 }
289 m_mutex.Signal();
290 }
291
292 void InternalUnregisterAll()
293 {
294 m_mutex.Wait();
295 m_workers.clear();
296 m_mutex.Signal();
297 }
298
299 bool InternalIsRegistered(const Key_T & key)
300 {
301 PWaitAndSignal mutex(m_mutex);
302 return m_workers.find(key) != m_workers.end();
303 }
304
305 Abstract_T * InternalCreateInstance(const Key_T & key, Param_T param)
306 {
307 PWaitAndSignal mutex(m_mutex);
308 WorkerIter_T entry = m_workers.find(key);
309 return entry == m_workers.end() ? NULL : entry->second->CreateInstance(param);
310 }
311
312 void InternalDestroy(const Key_T & key, Abstract_T * instance)
313 {
314 PWaitAndSignal mutex(m_mutex);
315 WorkerIter_T entry = m_workers.find(key);
316 if (entry != m_workers.end() && !entry->second->IsSingleton())
317 delete instance;
318 }
319
320 bool InternalIsSingleton(const Key_T & key)
321 {
322 PWaitAndSignal mutex(m_mutex);
323 WorkerIter_T entry = m_workers.find(key);
324 return entry != m_workers.end() && entry->second->IsSingleton();
325 }
326
327 KeyList_T InternalGetKeyList()
328 {
329 PWaitAndSignal mutex(m_mutex);
330 KeyList_T list;
331 for (WorkerIter_T entry = m_workers.begin(); entry != m_workers.end(); ++entry)
332 list.push_back(entry->first);
333 return list;
334 }
335
336 protected:
337 WorkerMap_T m_workers;
338
339 private:
340 PFactoryTemplate(const PFactoryTemplate &) {}
341 void operator=(const PFactoryTemplate &) {}
342
343 friend class PFactoryBase;
344 };
345
346
348 typedef std::string PDefaultPFactoryKey;
349
350
351 #define PFACTORY_STATICS(cls) \
352 static cls & GetFactory() { return PFactoryBase::GetFactoryAs<cls>(); } \
353 static bool Register(const Key_T & k, WorkerBase_T * w) { return GetFactory().InternalRegister(k, w); } \
354 static bool Register(const Key_T & k, Abstract_T * i, bool a = true) { return GetFactory().InternalRegister(k, i, a); } \
355 static bool RegisterAs(const Key_T & synonym, const Key_T & original){ return GetFactory().InternalRegisterAs(synonym, original); } \
356 static void Unregister(const Key_T & k) { GetFactory().InternalUnregister(k); } \
357 static void Unregister(WorkerBase_T * a) { GetFactory().InternalUnregister(a); } \
358 static void UnregisterAll() { GetFactory().InternalUnregisterAll(); } \
359 static bool IsRegistered(const Key_T & k) { return GetFactory().InternalIsRegistered(k); } \
360 static bool IsSingleton(const Key_T & k) { return GetFactory().InternalIsSingleton(k); } \
361 static typename Base_T::KeyList_T GetKeyList() { return GetFactory().InternalGetKeyList(); } \
362 static PMutex & GetMutex() { return GetFactory().m_mutex; } \
363
364
368 template <class AbstractClass, typename KeyType = PDefaultPFactoryKey>
369 class PFactory : public PFactoryTemplate<AbstractClass, const KeyType &, KeyType>
370 {
371 public:
372 typedef PFactoryTemplate<AbstractClass, const KeyType &, KeyType> Base_T;
373 typedef typename Base_T::WorkerBase WorkerBase_T;
374 typedef typename Base_T::Abstract_T Abstract_T;
375 typedef typename Base_T::Param_T Param_T;
376 typedef typename Base_T::Key_T Key_T;
377
378 PFACTORY_STATICS(PFactory);
379
380 template <class ConcreteClass>
381 class Worker : protected WorkerBase_T
382 {
383 public:
384 Worker(const Key_T & key, bool singleton = false)
385 : WorkerBase_T(singleton)
386 {
387 Register(key, this);
388 }
389
390 protected:
391 virtual Abstract_T * Create(Param_T) const
392 {
393 return new ConcreteClass();
394 }
395 };
396
397 static Abstract_T * CreateInstance(const Key_T & key)
398 {
399 return GetFactory().InternalCreateInstance(key, key);
400 }
401
402 template <class Derived_T>
403 static Derived_T * CreateInstanceAs(const Key_T & key)
404 {
405 Abstract_T * instance = GetFactory().InternalCreateInstance(key, key);
406 Derived_T * derived = dynamic_cast<Derived_T *>(instance);
407 if (derived != NULL)
408 return derived;
409
410 GetFactory().InternalDestroy(key, instance);
411 return NULL;
412 }
413 };
414
415
419 template <class AbstractClass, typename ParamType, typename KeyType = PDefaultPFactoryKey>
420 class PParamFactory : public PFactoryTemplate<AbstractClass, ParamType, KeyType>
421 {
422 public:
423 typedef PFactoryTemplate<AbstractClass, ParamType, KeyType> Base_T;
424 typedef typename Base_T::WorkerBase WorkerBase_T;
425 typedef typename Base_T::Abstract_T Abstract_T;
426 typedef typename Base_T::Param_T Param_T;
427 typedef typename Base_T::Key_T Key_T;
428
429 PFACTORY_STATICS(PParamFactory);
430
431 template <class ConcreteClass>
432 class Worker : protected WorkerBase_T
433 {
434 public:
435 Worker(const Key_T & key, bool singleton = false)
436 : WorkerBase_T(singleton)
437 {
438 Register(key, this);
439 }
440
441 protected:
442 virtual Abstract_T * Create(Param_T param) const
443 {
444 return new ConcreteClass(param);
445 }
446 };
447
448 static Abstract_T * CreateInstance(const Key_T & key, Param_T param)
449 {
450 return GetFactory().InternalCreateInstance(key, param);
451 }
452
453 template <class Derived_T>
454 static Derived_T * CreateInstanceAs(const Key_T & key, Param_T param)
455 {
456 Abstract_T * instance = GetFactory().InternalCreateInstance(key, param);
457 Derived_T * derived = dynamic_cast<Derived_T *>(instance);
458 if (derived != NULL)
459 return derived;
460 GetFactory().InternalDestroy(key, instance);
461 return NULL;
462 }
463 };
464
465
477 #define PFACTORY_CREATE(factory, ConcreteClass, ...) \
478 namespace PFactoryLoader { \
479 int ConcreteClass##_link() { return 0; } \
480 factory::Worker<ConcreteClass> ConcreteClass##_instance(__VA_ARGS__); \
481 }
482
483 #define PFACTORY_CREATE_SINGLETON(factory, ConcreteClass) \
484 PFACTORY_CREATE(factory, ConcreteClass, typeid(ConcreteClass).name(), true)
485
486 #define PFACTORY_GET_SINGLETON(factory, ConcreteClass) \
487 static ConcreteClass & GetInstance() { \
488 return *factory::CreateInstanceAs<ConcreteClass>(typeid(ConcreteClass).name()); \
489 }
490
491
492
493
494 /* This macro is used to force linking of factories.
495 See PFACTORY_CREATE() for more information
496 */
497 #define PFACTORY_LOAD(ConcreteType) \
498 namespace PFactoryLoader { \
499 extern int ConcreteType##_link(); \
500 int const ConcreteType##_loader = ConcreteType##_link(); \
501 }
502
503
504 #endif // PTLIB_FACTORY_H
505
506
507 // End Of File ///////////////////////////////////////////////////////////////