PTLib  Version 2.14.3
 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: 32250 $
27  * $Author: rjongbloed $
28  * $Date: 2014-06-28 14:55:01 +1000 (Sat, 28 Jun 2014) $
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 
116 {
117  protected:
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:
147 
148  private:
149  PFactoryBase(const PFactoryBase &) {}
150  void operator=(const PFactoryBase &) {}
151 };
152 
153 
156 template <class AbstractClass, typename ParamType, typename KeyType>
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 
170  {
171  public:
172  enum Types {
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  {
193  }
194 
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 
224 
225  friend class PFactoryTemplate;
226  };
227 
228  virtual void DestroySingletons()
229  {
230  for (WorkerIter_T it = m_workers.begin(); it != m_workers.end(); ++it)
231  it->second->DestroySingleton();
232  }
233 
234  protected:
236  { }
237 
239  {
241  }
242 
243  bool InternalRegister(const Key_T & key, WorkerBase * worker)
244  {
245  PWaitAndSignal mutex(m_mutex);
246  typename WorkerMap_T::iterator it = m_workers.find(key);
247  if (it != m_workers.end())
248  return it->second == worker;
249 
251  m_workers[key] = PAssertNULL(worker);
252  return true;
253  }
254 
255  bool InternalRegister(const Key_T & key, Abstract_T * instance, bool autoDeleteInstance)
256  {
257  PWaitAndSignal mutex(m_mutex);
258  typename WorkerMap_T::iterator it = m_workers.find(key);
259  if (it != m_workers.end())
260  return it->second->m_singletonInstance == instance;
261 
263  m_workers[key] = PNEW WorkerBase(instance, autoDeleteInstance);
264  return true;
265  }
266 
267  PBoolean InternalRegisterAs(const Key_T & newKey, const Key_T & oldKey)
268  {
269  PWaitAndSignal mutex(m_mutex);
270  typename WorkerMap_T::iterator itOld = m_workers.find(oldKey);
271  if (itOld == m_workers.end())
272  return false;
273 
274  typename WorkerMap_T::iterator itNew = m_workers.find(newKey);
275  if (itNew != m_workers.end())
276  return itNew->second == itOld->second;
277 
278  m_workers[newKey] = PAssertNULL(itOld->second);
279  return true;
280  }
281 
282  void InternalUnregister(const Key_T & key)
283  {
284  m_mutex.Wait();
285  m_workers.erase(key);
286  m_mutex.Signal();
287  }
288 
289  void InternalUnregister(WorkerBase * instance)
290  {
291  m_mutex.Wait();
292  for (WorkerIter_T it = m_workers.begin(); it != m_workers.end(); ++it) {
293  if (it->second == instance) {
294  m_workers.erase(it);
295  break;
296  }
297  }
298  m_mutex.Signal();
299  }
300 
302  {
303  m_mutex.Wait();
304  m_workers.clear();
305  m_mutex.Signal();
306  }
307 
308  bool InternalIsRegistered(const Key_T & key)
309  {
310  PWaitAndSignal mutex(m_mutex);
311  return m_workers.find(key) != m_workers.end();
312  }
313 
315  {
316  PWaitAndSignal mutex(m_mutex);
317  WorkerIter_T entry = m_workers.find(key);
318  return entry == m_workers.end() ? NULL : entry->second->CreateInstance(param);
319  }
320 
321  void InternalDestroy(const Key_T & key, Abstract_T * instance)
322  {
323  PWaitAndSignal mutex(m_mutex);
324  WorkerIter_T entry = m_workers.find(key);
325  if (entry != m_workers.end() && !entry->second->IsSingleton())
326  delete instance;
327  }
328 
329  bool InternalIsSingleton(const Key_T & key)
330  {
331  PWaitAndSignal mutex(m_mutex);
332  WorkerIter_T entry = m_workers.find(key);
333  return entry != m_workers.end() && entry->second->IsSingleton();
334  }
335 
337  {
338  PWaitAndSignal mutex(m_mutex);
339  KeyList_T list;
340  for (WorkerIter_T entry = m_workers.begin(); entry != m_workers.end(); ++entry)
341  list.push_back(entry->first);
342  return list;
343  }
344 
345  protected:
347 
348  private:
350  void operator=(const PFactoryTemplate &) {}
351 
352  friend class PFactoryBase;
353 };
354 
355 
357 typedef std::string PDefaultPFactoryKey;
358 
359 
360 #define PFACTORY_STATICS(cls) \
361  static cls & GetFactory() { return PFactoryBase::GetFactoryAs<cls>(); } \
362  static bool Register(const Key_T & k, WorkerBase_T * w) { return GetFactory().InternalRegister(k, w); } \
363  static bool Register(const Key_T & k, Abstract_T * i, bool a = true) { return GetFactory().InternalRegister(k, i, a); } \
364  static bool RegisterAs(const Key_T & synonym, const Key_T & original){ return GetFactory().InternalRegisterAs(synonym, original); } \
365  static void Unregister(const Key_T & k) { GetFactory().InternalUnregister(k); } \
366  static void Unregister(WorkerBase_T * a) { GetFactory().InternalUnregister(a); } \
367  static void UnregisterAll() { GetFactory().InternalUnregisterAll(); } \
368  static bool IsRegistered(const Key_T & k) { return GetFactory().InternalIsRegistered(k); } \
369  static bool IsSingleton(const Key_T & k) { return GetFactory().InternalIsSingleton(k); } \
370  static typename Base_T::KeyList_T GetKeyList() { return GetFactory().InternalGetKeyList(); } \
371  static PMutex & GetMutex() { return GetFactory().m_mutex; } \
372 
373 
377 template <class AbstractClass, typename KeyType = PDefaultPFactoryKey>
378 class PFactory : public PFactoryTemplate<AbstractClass, const KeyType &, KeyType>
379 {
380  public:
382  typedef typename Base_T::WorkerBase WorkerBase_T;
383  typedef typename Base_T::Abstract_T Abstract_T;
384  typedef typename Base_T::Param_T Param_T;
385  typedef typename Base_T::Key_T Key_T;
386 
388 
389  template <class ConcreteClass>
390  class Worker : protected WorkerBase_T
391  {
392  private:
393  Key_T m_key;
394  public:
395  Worker(const Key_T & key, bool singleton = false)
396  : WorkerBase_T(singleton)
397  , m_key(key)
398  {
399  PAssert(Register(key, this), "Factory Worker already registered");
400  }
401 
403  {
404  Unregister(m_key);
405  }
406 
407  const Key_T & GetKey() const { return m_key; }
408 
409  protected:
410  virtual Abstract_T * Create(Param_T) const
411  {
412  return new ConcreteClass();
413  }
414  };
415 
416  static Abstract_T * CreateInstance(const Key_T & key)
417  {
418  return GetFactory().InternalCreateInstance(key, key);
419  }
420 
421  template <class Derived_T>
422  static Derived_T * CreateInstanceAs(const Key_T & key)
423  {
424  Abstract_T * instance = GetFactory().InternalCreateInstance(key, key);
425  Derived_T * derived = dynamic_cast<Derived_T *>(instance);
426  if (derived != NULL)
427  return derived;
428 
429  GetFactory().InternalDestroy(key, instance);
430  return NULL;
431  }
432 };
433 
434 
438 template <class AbstractClass, typename ParamType, typename KeyType = PDefaultPFactoryKey>
439 class PParamFactory : public PFactoryTemplate<AbstractClass, ParamType, KeyType>
440 {
441  public:
444  typedef typename Base_T::Abstract_T Abstract_T;
445  typedef typename Base_T::Param_T Param_T;
446  typedef typename Base_T::Key_T Key_T;
447 
449 
450  template <class ConcreteClass>
451  class Worker : protected WorkerBase_T
452  {
453  private:
454  Key_T m_key;
455  public:
456  Worker(const Key_T & key, bool singleton = false)
457  : WorkerBase_T(singleton)
458  , m_key(key)
459  {
460  PAssert(Register(key, this), "Factory Worker already registered");
461  }
462 
464  {
465  Unregister(m_key);
466  }
467 
468  const Key_T & GetKey() const { return m_key; }
469 
470  protected:
471  virtual Abstract_T * Create(Param_T param) const
472  {
473  return new ConcreteClass(param);
474  }
475  };
476 
477  static Abstract_T * CreateInstance(const Key_T & key, Param_T param)
478  {
479  return GetFactory().InternalCreateInstance(key, param);
480  }
481 
482  template <class Derived_T>
483  static Derived_T * CreateInstanceAs(const Key_T & key, Param_T param)
484  {
485  Abstract_T * instance = GetFactory().InternalCreateInstance(key, param);
486  Derived_T * derived = dynamic_cast<Derived_T *>(instance);
487  if (derived != NULL)
488  return derived;
489  GetFactory().InternalDestroy(key, instance);
490  return NULL;
491  }
492 };
493 
494 
506 #define PFACTORY_CREATE(factory, ConcreteClass, ...) \
507  namespace PFactoryLoader { \
508  int ConcreteClass##_link() { return 0; } \
509  factory::Worker<ConcreteClass> ConcreteClass##_instance(__VA_ARGS__); \
510  }
511 
512 #define PFACTORY_SYNONYM(factory, ConcreteClass, name, key) \
513  namespace PFactoryLoader { \
514  bool ConcreteClass##name##_synonym = factory::RegisterAs(key, ConcreteClass##_instance.GetKey()); \
515  }
516 
517 #define PFACTORY_CREATE_SINGLETON(factory, ConcreteClass) \
518  PFACTORY_CREATE(factory, ConcreteClass, typeid(ConcreteClass).name(), true)
519 
520 #define PFACTORY_GET_SINGLETON(factory, ConcreteClass) \
521  static ConcreteClass & GetInstance() { \
522  return *factory::CreateInstanceAs<ConcreteClass>(typeid(ConcreteClass).name()); \
523  }
524 
525 
526 
527 
528 /* This macro is used to force linking of factories.
529  See PFACTORY_CREATE() for more information
530  */
531 #define PFACTORY_LOAD(ConcreteType) \
532  namespace PFactoryLoader { \
533  extern int ConcreteType##_link(); \
534  int const ConcreteType##_loader = ConcreteType##_link(); \
535  }
536 
537 
538 #endif // PTLIB_FACTORY_H
539 
540 
541 // End Of File ///////////////////////////////////////////////////////////////