Sirikata
libcore/include/sirikata/core/util/Factory.hpp
Go to the documentation of this file.
00001 /*  Sirikata Utilities -- Sirikata Utilities
00002  *  Factory.hpp
00003  *
00004  *  Copyright (c) 2009, Daniel Reiter Horn
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions are
00009  *  met:
00010  *  * Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *  * Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in
00014  *    the documentation and/or other materials provided with the
00015  *    distribution.
00016  *  * Neither the name of Sirikata nor the names of its contributors may
00017  *    be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00021  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00022  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00023  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00024  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00026  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  */
00032 
00033 #ifndef _SIRIKATA_FACTORY_HPP_
00034 #define _SIRIKATA_FACTORY_HPP_
00035 
00036 namespace Sirikata {
00037 
00038 class FactoryMissingConstructorException : public std::exception {
00039 public:
00040     FactoryMissingConstructorException(const String& _name)
00041      : name(_name),
00042        what_msg(new String())
00043     {}
00044     FactoryMissingConstructorException(const FactoryMissingConstructorException& rhs)
00045      : name(rhs.name),
00046        what_msg(new String(*(rhs.what_msg)))
00047     {}
00048     virtual ~FactoryMissingConstructorException() throw() {
00049         delete what_msg;
00050     }
00051 
00052     char const* what() const throw() {
00053         if (what_msg->empty())
00054             (*what_msg) = "Factory missing constructor: " + name + " not registered in the factory.";
00055         return what_msg->c_str();
00056     }
00057 private:
00058     const String name;
00059     String* what_msg;
00060 };
00061 
00062 template<class T, class Ftype>
00063 class FactoryImpl {
00064 
00065     typedef std::tr1::unordered_map<String,Ftype> ConstructorMap;
00066     ConstructorMap mConstructors;
00067     template <class U> static U* noop(U*) {
00068         return NULL;
00069     }
00070     template <class U> static U noop(const U&) {
00071         return U();
00072     }
00073     static T staticNoop() {
00074         T temp=T();
00075         return noop(temp);
00076     }
00077     Ftype mNoop;
00078     String mDefault;
00079 public:
00080     FactoryImpl():mNoop(std::tr1::bind(&FactoryImpl<T,Ftype>::staticNoop)){}
00081     bool unregisterConstructor(const String& name) {
00082 
00083         typename ConstructorMap::iterator where=mConstructors.find(name);
00084         if (where==mConstructors.end())
00085             return false;
00086         mConstructors.erase(where);
00087         if (mDefault==name) {
00088             mDefault=String();
00089         }
00090         return true;
00091     }
00092     bool registerConstructor(const String& name,
00093                              const Ftype &constructor,
00094                              bool isDefault=false) {
00095         if (mConstructors.find(name)!=mConstructors.end())
00096             return false;
00097         mConstructors[name]=constructor;
00098         if (isDefault) {
00099             mDefault=name;
00100         }
00101         return true;
00102     }
00103     const String& getDefault() const {
00104         return mDefault;
00105     }
00106     bool hasConstructor(const String&name)const {
00107         return mConstructors.find(name) != mConstructors.end();
00108     }
00109     typedef std::list<String> ConstructorNameList;
00110     ConstructorNameList getNames() const {
00111         ConstructorNameList result;
00112         for(typename ConstructorMap::const_iterator it = mConstructors.begin(); it != mConstructors.end(); it++)
00113             result.push_back(it->first);
00114         return result;
00115     }
00116 
00117     const Ftype &getConstructorOrDefault(const String&name)const{
00118         typename ConstructorMap::const_iterator where=mConstructors.find(name);
00119         if (where==mConstructors.end()) {
00120             if (name.length()==0&&mDefault.length()) {
00121                 return getConstructor(mDefault);
00122             }
00123             return mNoop;
00124         }
00125         return where->second;
00126     }
00127 
00128     // Gets a specific constructor and throws a
00129     // FactoryMissingConstructorException if it can't be found
00130     const Ftype& getConstructor(const String&name) const {
00131         if (!hasConstructor(name))
00132             throw FactoryMissingConstructorException(name);
00133         return getConstructorOrDefault(name);
00134     }
00135 
00136     const Ftype& getDefaultConstructor()const{
00137         return getConstructor(mDefault);
00138     }
00139 };
00140 
00141 template <class T>class Factory:public FactoryImpl<T,std::tr1::function<T()> >{};
00142 
00143 template <class T, typename A>class Factory1:public FactoryImpl<T,std::tr1::function<T(A)> >{};
00144 
00145 template <class T, typename A, typename B>class Factory2:public FactoryImpl<T,std::tr1::function<T(A,B)> >{};
00146 
00147 template <class T, typename A, typename B, typename C>class Factory3:public FactoryImpl<T,std::tr1::function<T(A,B,C)> >{};
00148 
00149 template <class T, typename A, typename B, typename C, typename D>class Factory4:public FactoryImpl<T,std::tr1::function<T(A,B,C,D)> >{};
00150 
00151 template <class T, typename A, typename B, typename C, typename D, typename E>class Factory5:public FactoryImpl<T,std::tr1::function<T(A,B,C,D,E)> >{};
00152 
00153 template <class T, typename A, typename B, typename C, typename D, typename E, typename F>class Factory6:public FactoryImpl<T,std::tr1::function<T(A,B,C,D,E,F)> >{};
00154 
00155 }
00156 #endif