pfactory.h

Go to the documentation of this file.
00001 /*
00002  * factory.h
00003  *
00004  * Abstract Factory Classes
00005  *
00006  * Portable Windows Library
00007  *
00008  * Copyright (C) 2004 Post Increment
00009  *
00010  * The contents of this file are subject to the Mozilla Public License
00011  * Version 1.0 (the "License"); you may not use this file except in
00012  * compliance with the License. You may obtain a copy of the License at
00013  * http://www.mozilla.org/MPL/
00014  *
00015  * Software distributed under the License is distributed on an "AS IS"
00016  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00017  * the License for the specific language governing rights and limitations
00018  * under the License.
00019  *
00020  * The Original Code is Portable Windows Library.
00021  *
00022  * The Initial Developer of the Original Code is Post Increment
00023  *
00024  * Contributor(s): ______________________________________.
00025  *
00026  * $Revision: 22552 $
00027  * $Author: csoutheren $
00028  * $Date: 2009-05-07 03:53:20 -0500 (Thu, 07 May 2009) $
00029  */
00030 
00031 #ifndef PTLIB_FACTORY_H
00032 #define PTLIB_FACTORY_H
00033 
00034 #ifdef P_USE_PRAGMA
00035 #pragma interface
00036 #endif
00037 
00038 #include <ptlib.h>
00039 
00040 #include <string>
00041 #include <map>
00042 #include <vector>
00043 
00044 #if defined(_MSC_VER)
00045 #pragma warning(disable:4786)
00046 #endif
00047 
00099 // this define the default class to be used for keys into PFactories
00100 //typedef PString PDefaultPFactoryKey;
00101 typedef std::string PDefaultPFactoryKey;
00102 
00103 
00111 class PFactoryBase
00112 {
00113   protected:
00114     PFactoryBase()
00115     { }
00116   public:
00117     virtual ~PFactoryBase()
00118     { }
00119 
00120     class FactoryMap : public std::map<std::string, PFactoryBase *>
00121     {
00122       public:
00123         FactoryMap() { }
00124         ~FactoryMap();
00125     };
00126 
00127     static FactoryMap & GetFactories();
00128     static PMutex & GetFactoriesMutex();
00129 
00130     PMutex mutex;
00131 
00132   private:
00133     PFactoryBase(const PFactoryBase &) {}
00134     void operator=(const PFactoryBase &) {}
00135 };
00136 
00137 
00140 template <class AbstractClass, typename KeyType = PDefaultPFactoryKey>
00141 class PFactory : PFactoryBase
00142 {
00143   public:
00144     typedef KeyType       Key_T;
00145     typedef AbstractClass Abstract_T;
00146 
00147     class WorkerBase
00148     {
00149       protected:
00150         WorkerBase(bool singleton = false)
00151           : isDynamic(false),
00152             isSingleton(singleton),
00153             singletonInstance(NULL),
00154             deleteSingleton(false)
00155         { }
00156         WorkerBase(Abstract_T * instance, bool delSingleton = true)
00157           : isDynamic(true),
00158             isSingleton(true),
00159             singletonInstance(instance),
00160             deleteSingleton(delSingleton)
00161         { }
00162 
00163         virtual ~WorkerBase()
00164         {
00165           if (deleteSingleton)
00166             delete singletonInstance;
00167         }
00168 
00169         Abstract_T * CreateInstance(const Key_T & key)
00170         {
00171           if (!isSingleton)
00172             return Create(key);
00173 
00174           if (singletonInstance == NULL)
00175             singletonInstance = Create(key);
00176           return singletonInstance;
00177         }
00178 
00179         virtual Abstract_T * Create(const Key_T & /*key*/) const { return singletonInstance; }
00180 
00181         bool         isDynamic;
00182         bool         isSingleton;
00183         Abstract_T * singletonInstance;
00184         bool         deleteSingleton;
00185 
00186       friend class PFactory<Abstract_T, Key_T>;
00187     };
00188 
00189     template <class ConcreteClass>
00190     class Worker : WorkerBase
00191     {
00192       public:
00193         Worker(const Key_T & key, bool singleton = false)
00194           : WorkerBase(singleton)
00195         {
00196           PMEMORY_IGNORE_ALLOCATIONS_FOR_SCOPE;
00197           PFactory<Abstract_T, Key_T>::Register(key, this);   // here
00198         }
00199 
00200       protected:
00201         virtual Abstract_T * Create(const Key_T & /*key*/) const
00202         {
00203 #if PMEMORY_HEAP
00204           // Singletons are never deallocated, so make sure they arenot reported as a leak
00205           PBoolean previousIgnoreAllocations = PMemoryHeap::SetIgnoreAllocations(WorkerBase::isSingleton);
00206 #endif
00207           Abstract_T * instance = new ConcreteClass;
00208 #if PMEMORY_HEAP
00209           PMemoryHeap::SetIgnoreAllocations(previousIgnoreAllocations);
00210 #endif
00211           return instance;
00212         }
00213     };
00214 
00215     typedef std::map<Key_T, WorkerBase *> KeyMap_T;
00216     typedef std::vector<Key_T> KeyList_T;
00217 
00218     static void Register(const Key_T & key, WorkerBase * worker)
00219     {
00220       GetInstance().Register_Internal(key, worker);
00221     }
00222 
00223     static void Register(const Key_T & key, Abstract_T * instance, bool autoDeleteInstance = true)
00224     {
00225       WorkerBase * w = PNEW WorkerBase(instance, autoDeleteInstance);
00226       GetInstance().Register_Internal(key, w);
00227     }
00228 
00229     static PBoolean RegisterAs(const Key_T & newKey, const Key_T & oldKey)
00230     {
00231       return GetInstance().RegisterAs_Internal(newKey, oldKey);
00232     }
00233 
00234     static void Unregister(const Key_T & key)
00235     {
00236       GetInstance().Unregister_Internal(key);
00237     }
00238 
00239     static void UnregisterAll()
00240     {
00241       GetInstance().UnregisterAll_Internal();
00242     }
00243 
00244     static bool IsRegistered(const Key_T & key)
00245     {
00246       return GetInstance().IsRegistered_Internal(key);
00247     }
00248 
00249     static Abstract_T * CreateInstance(const Key_T & key)
00250     {
00251       return GetInstance().CreateInstance_Internal(key);
00252     }
00253 
00254     template <class Derived_T>
00255     static Derived_T * CreateInstanceAs(const Key_T & key)
00256     {
00257       return dynamic_cast<Derived_T *>(GetInstance().CreateInstance_Internal(key));
00258     }
00259 
00260     static PBoolean IsSingleton(const Key_T & key)
00261     {
00262       return GetInstance().IsSingleton_Internal(key);
00263     }
00264 
00265     static KeyList_T GetKeyList()
00266     { 
00267       return GetInstance().GetKeyList_Internal();
00268     }
00269 
00270     static KeyMap_T & GetKeyMap()
00271     { 
00272       return GetInstance().keyMap;
00273     }
00274 
00275     static PMutex & GetMutex()
00276     {
00277       return GetInstance().mutex;
00278     }
00279 
00280   protected:
00281     PFactory()
00282     { }
00283 
00284     ~PFactory()
00285     {
00286       typename KeyMap_T::const_iterator entry;
00287       for (entry = keyMap.begin(); entry != keyMap.end(); ++entry) {
00288         if (entry->second->isDynamic)
00289           delete entry->second;
00290       }
00291     }
00292 
00293     static PFactory & GetInstance()
00294     {
00295       std::string className = typeid(PFactory).name();
00296       PWaitAndSignal m(GetFactoriesMutex());
00297       FactoryMap & factories = GetFactories();
00298       FactoryMap::const_iterator entry = factories.find(className);
00299       if (entry != factories.end()) {
00300         PAssert(entry->second != NULL, "Factory map returned NULL for existing key");
00301         PFactoryBase * b = entry->second;
00302         // don't use the following dynamic cast, because gcc does not like it
00303         //PFactory * f = dynamic_cast<PFactory*>(b);
00304         return *(PFactory *)b;
00305       }
00306 
00307       PMEMORY_IGNORE_ALLOCATIONS_FOR_SCOPE;
00308       PFactory * factory = new PFactory;
00309       factories[className] = factory;
00310       return *factory;
00311     }
00312 
00313 
00314     void Register_Internal(const Key_T & key, WorkerBase * worker)
00315     {
00316       PWaitAndSignal m(mutex);
00317       if (keyMap.find(key) == keyMap.end()) {
00318         keyMap[key] = worker;
00319         if (worker->isSingleton)
00320           worker->CreateInstance(key);
00321       }
00322     }
00323 
00324     PBoolean RegisterAs_Internal(const Key_T & newKey, const Key_T & oldKey)
00325     {
00326       PWaitAndSignal m(mutex);
00327       if (keyMap.find(oldKey) == keyMap.end())
00328         return PFalse;
00329       keyMap[newKey] = keyMap[oldKey];
00330       return PTrue;
00331     }
00332 
00333     void Unregister_Internal(const Key_T & key)
00334     {
00335       PWaitAndSignal m(mutex);
00336       typename KeyMap_T::iterator r = keyMap.find(key);
00337       if (r != keyMap.end()) {
00338         if (r->second->isDynamic)
00339           delete r->second;
00340         keyMap.erase(r);
00341       }
00342     }
00343 
00344     void UnregisterAll_Internal()
00345     {
00346       PWaitAndSignal m(mutex);
00347       while (keyMap.size() > 0)
00348         keyMap.erase(keyMap.begin());
00349     }
00350 
00351     bool IsRegistered_Internal(const Key_T & key)
00352     {
00353       PWaitAndSignal m(mutex);
00354       return keyMap.find(key) != keyMap.end();
00355     }
00356 
00357     Abstract_T * CreateInstance_Internal(const Key_T & key)
00358     {
00359       PWaitAndSignal m(mutex);
00360       typename KeyMap_T::const_iterator entry = keyMap.find(key);
00361       if (entry != keyMap.end())
00362         return entry->second->CreateInstance(key);
00363       return NULL;
00364     }
00365 
00366     bool IsSingleton_Internal(const Key_T & key)
00367     {
00368       PWaitAndSignal m(mutex);
00369       if (keyMap.find(key) == keyMap.end())
00370         return false;
00371       return keyMap[key]->isSingleton;
00372     }
00373 
00374     KeyList_T GetKeyList_Internal()
00375     { 
00376       PWaitAndSignal m(mutex);
00377       KeyList_T list;
00378       typename KeyMap_T::const_iterator entry;
00379       for (entry = keyMap.begin(); entry != keyMap.end(); ++entry)
00380         list.push_back(entry->first);
00381       return list;
00382     }
00383 
00384     KeyMap_T keyMap;
00385 
00386   private:
00387     PFactory(const PFactory &) {}
00388     void operator=(const PFactory &) {}
00389 };
00390 
00391 //
00392 //  this macro is used to initialise the static member variable used to force factories to instantiate
00393 //
00394 #define PLOAD_FACTORY(AbstractType, KeyType) \
00395   namespace PWLibFactoryLoader { \
00396     extern int AbstractType##_##KeyType##_loader; \
00397     static int AbstractType##_##KeyType##_loader_instance = AbstractType##_##KeyType##_loader; \
00398   };
00399 
00400 
00401 //
00402 //  this macro is used to instantiate a static variable that accesses the static member variable 
00403 //  in a factory forcing it to load
00404 //
00405 #define PINSTANTIATE_FACTORY(AbstractType, KeyType) \
00406   namespace PWLibFactoryLoader { int AbstractType##_##KeyType##_loader; }
00407 
00408 
00420 #define PFACTORY_CREATE(factory, ConcreteType, keyValue, singleton) \
00421   namespace PFactoryLoader { \
00422     int ConcreteType##_link() { return 0; } \
00423     factory::Worker<ConcreteType> ConcreteType##_instance(keyValue, singleton); \
00424   }
00425 
00426 /* This macro is used to force linking of factories.
00427    See PFACTORY_CREATE() for more information
00428  */
00429 #define PFACTORY_LOAD(ConcreteType) \
00430   namespace PFactoryLoader { \
00431     extern int ConcreteType##_link(); \
00432     int const ConcreteType##_loader = ConcreteType##_link(); \
00433   }
00434 
00435 
00436 #endif // PTLIB_FACTORY_H
00437 
00438 
00439 // End Of File ///////////////////////////////////////////////////////////////

Generated on Thu May 27 01:36:48 2010 for PTLib by  doxygen 1.4.7