1 /* -*- c++ -*- */ 2 #ifndef FACTORY_H 3 #define FACTORY_H 4 5 #include "stringutilities.h" 6 //#include "systemutilities.h" 7 #include "Report.h" 8 9 #include <vector> 10 #include <map> 11 #include <set> 12 13 namespace ProtoMol { 14 15 //_____________________________________________________ FactoryBase 16 /** 17 Base class of all factories templated with the family type. 18 Container to keep pointers for each prototype exemplar and their aliases, where 19 the real prototype is keep in a separate set. 20 */ 21 template<typename Type> 22 class FactoryBase { 23 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 24 // Constructors, destructors, assignment 25 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26 protected: FactoryBase()27 FactoryBase():myCache(false){ 28 //Report::report << Report::plain <<"[FactoryBase<"<<Type::scope<<">::FactoryBase()]"<< Report::endr; 29 } ~FactoryBase()30 virtual ~FactoryBase(){ 31 //Report::report << Report::plain <<"[FactoryBase<"<<Type::scope<<">::~FactoryBase()]"<< Report::endr; 32 clear(); 33 } 34 private: FactoryBase(const FactoryBase &)35 FactoryBase(const FactoryBase&){} 36 FactoryBase& operator=(const FactoryBase&){return *this;} 37 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 38 // New methods of class FactoryBase 39 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 40 protected: getPrototype(const std::string & id)41 const Type* getPrototype(const std::string& id) const{ 42 const Type* prototype = NULL; 43 44 if(myExemplars.find(id) != myExemplars.end()){ 45 prototype = myExemplars.find(id)->second; 46 } 47 else if (myAliasExemplars.find(id) != myAliasExemplars.end()){ 48 prototype = myAliasExemplars.find(id)->second; 49 } 50 51 return prototype; 52 } 53 clear()54 void clear(){ 55 for(typename std::set<const Type*>::iterator i=myPointers.begin();i != myPointers.end();++i) 56 delete (*i); 57 myExemplars.clear(); 58 //realclear(myExemplars); 59 myAliasExemplars.clear(); 60 //realclear(myAliasExemplars); 61 myPointers.clear(); 62 //realclear(myPointers); 63 myCache = false; 64 } 65 66 protected: 67 virtual std::string doPrint() const=0; ///< Hook method called from static method print 68 virtual void doRegisterHelpText() const=0; ///< Hook method called from static method registerHelpText 69 70 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 71 // private data members 72 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 73 protected: 74 std::map<std::string,const Type*,ltstrNocase> myExemplars; 75 std::map<std::string,const Type*,ltstrNocase> myAliasExemplars; 76 std::set<const Type*> myPointers; 77 mutable bool myCache; 78 }; 79 80 81 82 //_____________________________________________________ FactoryTraits<> 83 template <class T> 84 class FactoryTraits; 85 86 //_____________________________________________________ Factory 87 /** 88 Concrete factory implementing the singleton pattern and 89 inheriting the implementation details by traits. The concept of three 90 levels enables to combine the singleton pattern and implementation details, 91 where the base class FactoryBase provides the essential methods and 92 data members for the implementation details. 93 */ 94 95 template<typename Type> 96 class Factory : public FactoryTraits<Type>::Details{ 97 public: 98 typedef typename std::set<const Type*>::const_iterator const_iterator; 99 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 100 // Constructors, destructors, assignment 101 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 102 protected: Factory()103 Factory():FactoryTraits<Type>::Details(){ 104 //Report::report << Report::plain <<"[Factory<"<<Type::scope<<">::Factory()]"<< Report::endr; 105 } ~Factory()106 virtual ~Factory(){ 107 //Report::report << Report::plain <<"[Factory<"<<Type::scope<<">::~Factory()]"<< Report::endr; 108 } 109 110 private: Factory(const Factory &)111 Factory(const Factory&){} 112 Factory& operator=(const Factory&){return *this;} 113 private: 114 /// Call by atexit() to clean up. kill()115 static void kill(){ 116 Factory* p = obj; 117 obj = NULL; 118 p->~Factory(); 119 } 120 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 121 // New methods of class Factory 122 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 123 public: 124 125 static void registerExemplar(const Type* exemplar, std::string id=""){ 126 if(id.empty()) 127 id = exemplar->getId(); 128 Factory::instance().doRegisterExemplar(id,exemplar); 129 } 130 131 static void registerExemplar(const Type* exemplar,const std::vector<std::string>& aliases, std::string id=""){ 132 if(id.empty()) 133 id = exemplar->getId(); 134 Factory::instance().doRegisterExemplar(id,exemplar,aliases); 135 } 136 unregisterExemplar(const std::string & id)137 static bool unregisterExemplar(const std::string& id){ 138 return Factory::instance().doUnregisterExemplar(id); 139 } 140 unregisterAllExemplars()141 static void unregisterAllExemplars(){ 142 Factory::instance().clear(); 143 } 144 print()145 static std::string print(){ 146 return Factory::instance().doPrint(); 147 } 148 registerHelpText()149 static void registerHelpText(){ 150 Factory::instance().doRegisterHelpText(); 151 } 152 empty()153 static bool empty(){ 154 return Factory::instance().myPointers.empty(); 155 } 156 instance()157 static Factory& instance(){ 158 //static Factory obj; 159 //return obj; 160 // We have to do it ourself ... M$ problem ... 161 if(obj == NULL){ 162 obj = new Factory(); 163 std::atexit(kill); 164 } 165 return *obj; 166 } 167 begin()168 static const_iterator begin(){ 169 return Factory::instance().myPointers.begin(); 170 } 171 end()172 static const_iterator end(){ 173 return Factory::instance().myPointers.end(); 174 } 175 176 find(const std::string & id)177 static const Type* find(const std::string& id){ 178 return Factory::instance().getPrototype(id); 179 } 180 181 private: doRegisterExemplar(const std::string & id,const Type * exemplar)182 void doRegisterExemplar(const std::string& id, const Type* exemplar){ 183 if(this->myExemplars.find(id) != this->myExemplars.end()){ 184 Report::report << Report::hint << "Prototype \'"<<id<<"\' already registered in "<<Type::scope<<"Factory"<<Type::scope<<", overwriting."<<Report::endr; 185 186 } 187 if(exemplar->getParameterSize() != exemplar->getParameters().size()){ 188 Report::report << Report::error <<Type::scope<<"Factory"<<Type::scope<<" prototype \'"<<id<<"\' has different parameter size definitions "<<exemplar->getParameterSize()<<" != "<<exemplar->getParameters().size()<<", fix it."<<Report::endr; 189 } 190 this->myExemplars[id] = exemplar; 191 this->myPointers.insert(exemplar); 192 this->myCache = false; 193 } 194 doRegisterExemplar(const std::string & id,const Type * exemplar,const std::vector<std::string> & aliases)195 void doRegisterExemplar(const std::string& id, const Type* exemplar,const std::vector<std::string>& aliases) { 196 doRegisterExemplar(id,exemplar); 197 for(unsigned int i=0;i<aliases.size();i++){ 198 this->myAliasExemplars[aliases[i]] = exemplar; 199 } 200 this->myCache = false; 201 } 202 doUnregisterExemplar(const std::string & id)203 bool doUnregisterExemplar(const std::string& id) { 204 // Get object pointer 205 const Type* p=this->getPrototype(id); 206 if(p == NULL) 207 return false; 208 209 // Remove pointers 210 for(typename std::map<std::string,const Type*,ltstrNocase>::iterator i=this->myExemplars.begin();i != this->myExemplars.end();){ 211 if(i->second == p) 212 this->myExemplars.erase(i++); 213 else 214 ++i; 215 } 216 for(typename std::map<std::string,const Type*,ltstrNocase>::iterator i=this->myAliasExemplars.begin();i != this->myAliasExemplars.end();){ 217 if(i->second == p) 218 this->myAliasExemplars.erase(i++); 219 else 220 ++i; 221 } 222 this->myPointers.erase(p); 223 224 // ... and delete the object 225 delete p; 226 227 this->myCache = false; 228 return true; 229 } 230 231 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 232 // private data members 233 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 234 private: 235 static Factory* obj; 236 237 }; 238 239 template<typename Type> 240 Factory<Type>* Factory<Type>::obj=NULL; 241 242 243 } 244 #endif /* FACTORY_H */ 245