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