|
PTLib Version 2.10.2
|
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: 24177 $ 00027 * $Author: rjongbloed $ 00028 * $Date: 2010-04-05 06:52:04 -0500 (Mon, 05 Apr 2010) $ 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 false; 00329 keyMap[newKey] = keyMap[oldKey]; 00330 return true; 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 00403 #define PFACTORY_CREATE(factory, ConcreteType, keyValue, singleton) \ 00404 namespace PFactoryLoader { \ 00405 int ConcreteType##_link() { return 0; } \ 00406 factory::Worker<ConcreteType> ConcreteType##_instance(keyValue, singleton); \ 00407 } 00408 00409 00410 /* This macro is used to force linking of factories. 00411 See PFACTORY_CREATE() for more information 00412 */ 00413 #define PFACTORY_LOAD(ConcreteType) \ 00414 namespace PFactoryLoader { \ 00415 extern int ConcreteType##_link(); \ 00416 int const ConcreteType##_loader = ConcreteType##_link(); \ 00417 } 00418 00419 00420 #endif // PTLIB_FACTORY_H 00421 00422 00423 // End Of File ///////////////////////////////////////////////////////////////