PWLib
1.10.10
|
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 * $Log: pfactory.h,v $ 00027 * Revision 1.22 2005/09/18 13:01:40 dominance 00028 * fixed pragma warnings when building with gcc. 00029 * 00030 * Revision 1.21 2005/05/03 11:58:45 csoutheren 00031 * Fixed various problems reported by valgrind 00032 * Thanks to Paul Cadach 00033 * 00034 * Revision 1.20 2005/01/04 07:44:02 csoutheren 00035 * More changes to implement the new configuration methodology, and also to 00036 * attack the global static problem 00037 * 00038 * Revision 1.19 2004/08/16 06:40:59 csoutheren 00039 * Added adapters template to make device plugins available via the abstract factory interface 00040 * 00041 * Revision 1.18 2004/07/12 09:17:20 csoutheren 00042 * Fixed warnings and errors under Linux 00043 * 00044 * Revision 1.17 2004/07/06 10:12:52 csoutheren 00045 * Added static integer o factory template to assist in ensuring factories are instantiated 00046 * 00047 * Revision 1.16 2004/07/06 04:26:44 csoutheren 00048 * Fixed problem when using factory maps with non-standard keys 00049 * 00050 * Revision 1.15 2004/07/02 03:14:47 csoutheren 00051 * Made factories non-singleton, by default 00052 * Added more docs 00053 * 00054 * Revision 1.14 2004/07/01 11:41:28 csoutheren 00055 * Fixed compile and run problems on Linux 00056 * 00057 * Revision 1.13 2004/07/01 04:33:57 csoutheren 00058 * Updated documentation on PFactory classes 00059 * 00060 * Revision 1.12 2004/06/30 12:17:04 rjongbloed 00061 * Rewrite of plug in system to use single global variable for all factories to avoid all sorts 00062 * of issues with startup orders and Windows DLL multiple instances. 00063 * 00064 * Revision 1.11 2004/06/17 06:35:12 csoutheren 00065 * Use attribute (( constructor )) to guarantee that factories are 00066 * instantiated when loaded from a shared library 00067 * 00068 * Revision 1.10 2004/06/03 13:30:57 csoutheren 00069 * Renamed INSTANTIATE_FACTORY to avoid potential namespace collisions 00070 * Added documentaton on new PINSTANTIATE_FACTORY macro 00071 * Added generic form of PINSTANTIATE_FACTORY 00072 * 00073 * Revision 1.9 2004/06/03 12:47:58 csoutheren 00074 * Decomposed PFactory declarations to hopefully avoid problems with Windows DLLs 00075 * 00076 * Revision 1.8 2004/06/01 05:44:12 csoutheren 00077 * Added typedefs to allow access to types 00078 * Changed singleton class to use new so as to allow full cleanup 00079 * 00080 * Revision 1.7 2004/05/23 12:33:56 rjongbloed 00081 * Made some subtle changes to the way the static variables are instantiated in 00082 * the factoris to fix problems with DLL's under windows. May not be final solution. 00083 * 00084 * Revision 1.6 2004/05/19 06:48:39 csoutheren 00085 * Added new functions to allow handling of singletons without concrete classes 00086 * 00087 * Revision 1.5 2004/05/18 06:01:06 csoutheren 00088 * Deferred plugin loading until after main has executed by using abstract factory classes 00089 * 00090 * Revision 1.4 2004/05/18 02:32:08 csoutheren 00091 * Fixed linking problems with PGenericFactory classes 00092 * 00093 * Revision 1.3 2004/05/13 15:10:51 csoutheren 00094 * Removed warnings under Windows 00095 * 00096 * Revision 1.2 2004/05/13 14:59:00 csoutheren 00097 * Removed warning under gcc 00098 * 00099 * Revision 1.1 2004/05/13 14:53:35 csoutheren 00100 * Add "abstract factory" template classes 00101 * 00102 */ 00103 00104 #ifndef _PFACTORY_H 00105 #define _PFACTORY_H 00106 00107 #ifdef P_USE_PRAGMA 00108 #pragma interface 00109 #endif 00110 00111 #include <ptlib.h> 00112 #include <string> 00113 #include <map> 00114 #include <vector> 00115 00116 #if defined(_MSC_VER) 00117 #pragma warning(disable:4786) 00118 #endif 00119 00178 class PFactoryBase 00179 { 00180 protected: 00181 PFactoryBase() 00182 { } 00183 public: 00184 virtual ~PFactoryBase() 00185 { } 00186 00187 class FactoryMap : public std::map<std::string, PFactoryBase *> 00188 { 00189 public: 00190 FactoryMap() { } 00191 ~FactoryMap(); 00192 }; 00193 00194 static FactoryMap & GetFactories(); 00195 static PMutex & GetFactoriesMutex(); 00196 00197 PMutex mutex; 00198 00199 private: 00200 PFactoryBase(const PFactoryBase &) {} 00201 void operator=(const PFactoryBase &) {} 00202 }; 00203 00204 00207 template <class _Abstract_T, typename _Key_T = PString> 00208 class PFactory : PFactoryBase 00209 { 00210 public: 00211 typedef _Key_T Key_T; 00212 typedef _Abstract_T Abstract_T; 00213 00214 class WorkerBase 00215 { 00216 protected: 00217 WorkerBase(bool singleton = false) 00218 : isDynamic(false), 00219 isSingleton(singleton), 00220 singletonInstance(NULL), 00221 deleteSingleton(false) 00222 { } 00223 WorkerBase(Abstract_T * instance) 00224 : isDynamic(true), 00225 isSingleton(true), 00226 singletonInstance(instance), 00227 deleteSingleton(true) 00228 { } 00229 00230 virtual ~WorkerBase() 00231 { 00232 if (deleteSingleton) 00233 delete singletonInstance; 00234 } 00235 00236 Abstract_T * CreateInstance(const Key_T & key) 00237 { 00238 if (!isSingleton) 00239 return Create(key); 00240 00241 if (singletonInstance == NULL) 00242 singletonInstance = Create(key); 00243 return singletonInstance; 00244 } 00245 00246 virtual Abstract_T * Create(const Key_T & /*key*/) const { return singletonInstance; } 00247 00248 bool isDynamic; 00249 bool isSingleton; 00250 Abstract_T * singletonInstance; 00251 bool deleteSingleton; 00252 00253 friend class PFactory<_Abstract_T, _Key_T>; 00254 }; 00255 00256 template <class _Concrete_T> 00257 class Worker : WorkerBase 00258 { 00259 public: 00260 Worker(const Key_T & key, bool singleton = false) 00261 : WorkerBase(singleton) 00262 { 00263 PFactory<_Abstract_T, _Key_T>::Register(key, this); // here 00264 } 00265 00266 protected: 00267 virtual Abstract_T * Create(const Key_T & /*key*/) const { return new _Concrete_T; } 00268 }; 00269 00270 typedef std::map<_Key_T, WorkerBase *> KeyMap_T; 00271 typedef std::vector<_Key_T> KeyList_T; 00272 00273 static void Register(const _Key_T & key, WorkerBase * worker) 00274 { 00275 GetInstance().Register_Internal(key, worker); 00276 } 00277 00278 static void Register(const _Key_T & key, Abstract_T * instance) 00279 { 00280 GetInstance().Register_Internal(key, new WorkerBase(instance)); 00281 } 00282 00283 static void Unregister(const _Key_T & key) 00284 { 00285 GetInstance().Unregister_Internal(key); 00286 } 00287 00288 static void UnregisterAll() 00289 { 00290 GetInstance().UnregisterAll_Internal(); 00291 } 00292 00293 static bool IsRegistered(const _Key_T & key) 00294 { 00295 return GetInstance().IsRegistered_Internal(key); 00296 } 00297 00298 static _Abstract_T * CreateInstance(const _Key_T & key) 00299 { 00300 return GetInstance().CreateInstance_Internal(key); 00301 } 00302 00303 static BOOL IsSingleton(const _Key_T & key) 00304 { 00305 return GetInstance().IsSingleton_Internal(key); 00306 } 00307 00308 static KeyList_T GetKeyList() 00309 { 00310 return GetInstance().GetKeyList_Internal(); 00311 } 00312 00313 static KeyMap_T & GetKeyMap() 00314 { 00315 return GetInstance().keyMap; 00316 } 00317 00318 static PMutex & GetMutex() 00319 { 00320 return GetInstance().mutex; 00321 } 00322 00323 protected: 00324 PFactory() 00325 { } 00326 00327 ~PFactory() 00328 { 00329 typename KeyMap_T::const_iterator entry; 00330 for (entry = keyMap.begin(); entry != keyMap.end(); ++entry) { 00331 if (entry->second->isDynamic) 00332 delete entry->second; 00333 } 00334 } 00335 00336 static PFactory & GetInstance() 00337 { 00338 std::string className = typeid(PFactory).name(); 00339 PWaitAndSignal m(GetFactoriesMutex()); 00340 FactoryMap & factories = GetFactories(); 00341 FactoryMap::const_iterator entry = factories.find(className); 00342 if (entry != factories.end()) { 00343 PAssert(entry->second != NULL, "Factory map returned NULL for existing key"); 00344 PFactoryBase * b = entry->second; 00345 // don't use the following dynamic cast, because gcc does not like it 00346 //PFactory * f = dynamic_cast<PFactory*>(b); 00347 return *(PFactory *)b; 00348 } 00349 00350 PFactory * factory = new PFactory; 00351 factories[className] = factory; 00352 return *factory; 00353 } 00354 00355 00356 void Register_Internal(const _Key_T & key, WorkerBase * worker) 00357 { 00358 PWaitAndSignal m(mutex); 00359 if (keyMap.find(key) == keyMap.end()) 00360 keyMap[key] = worker; 00361 } 00362 00363 void Unregister_Internal(const _Key_T & key) 00364 { 00365 PWaitAndSignal m(mutex); 00366 keyMap.erase(key); 00367 } 00368 00369 void UnregisterAll_Internal() 00370 { 00371 PWaitAndSignal m(mutex); 00372 keyMap.erase(keyMap.begin(), keyMap.end()); 00373 } 00374 00375 bool IsRegistered_Internal(const _Key_T & key) 00376 { 00377 PWaitAndSignal m(mutex); 00378 return keyMap.find(key) != keyMap.end(); 00379 } 00380 00381 _Abstract_T * CreateInstance_Internal(const _Key_T & key) 00382 { 00383 PWaitAndSignal m(mutex); 00384 typename KeyMap_T::const_iterator entry = keyMap.find(key); 00385 if (entry != keyMap.end()) 00386 return entry->second->CreateInstance(key); 00387 return NULL; 00388 } 00389 00390 bool IsSingleton_Internal(const _Key_T & key) 00391 { 00392 PWaitAndSignal m(mutex); 00393 if (keyMap.find(key) == keyMap.end()) 00394 return false; 00395 return keyMap[key]->isSingleton; 00396 } 00397 00398 KeyList_T GetKeyList_Internal() 00399 { 00400 PWaitAndSignal m(mutex); 00401 KeyList_T list; 00402 typename KeyMap_T::const_iterator entry; 00403 for (entry = keyMap.begin(); entry != keyMap.end(); ++entry) 00404 list.push_back(entry->first); 00405 return list; 00406 } 00407 00408 KeyMap_T keyMap; 00409 00410 private: 00411 PFactory(const PFactory &) {} 00412 void operator=(const PFactory &) {} 00413 }; 00414 00415 // 00416 // this macro is used to initialise the static member variable used to force factories to instantiate 00417 // 00418 #define PLOAD_FACTORY_DECLARE(AbstractType, KeyType) \ 00419 namespace PWLibFactoryLoader { extern int AbstractType##_##KeyType; } 00420 00421 #define PLOAD_FACTORY(AbstractType, KeyType) \ 00422 PWLibFactoryLoader::AbstractType##_##KeyType = 1; 00423 00424 // 00425 // this macro is used to instantiate a static variable that accesses the static member variable 00426 // in a factory forcing it to load 00427 // 00428 #define PINSTANTIATE_FACTORY(AbstractType, KeyType) \ 00429 namespace PWLibFactoryLoader { int AbstractType##_##KeyType; }; 00430 00431 #endif // _PFACTORY_H