factory.h

Go to the documentation of this file.
00001 /** @file rutz/factory.h template class for object factories, which
00002     create objects belonging to some inheritance hierarchy given just
00003     a type name as a string */
00004 
00005 ///////////////////////////////////////////////////////////////////////
00006 //
00007 // Copyright (c) 1999-2004 California Institute of Technology
00008 // Copyright (c) 2004-2007 University of Southern California
00009 // Rob Peters <rjpeters at usc dot edu>
00010 //
00011 // created: Sat Jun 26 23:40:55 1999
00012 // commit: $Id: factory.h 8274 2007-04-19 17:44:48Z rjpeters $
00013 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/factory.h $
00014 //
00015 // --------------------------------------------------------------------
00016 //
00017 // This file is part of GroovX.
00018 //   [http://ilab.usc.edu/rjpeters/groovx/]
00019 //
00020 // GroovX is free software; you can redistribute it and/or modify it
00021 // under the terms of the GNU General Public License as published by
00022 // the Free Software Foundation; either version 2 of the License, or
00023 // (at your option) any later version.
00024 //
00025 // GroovX is distributed in the hope that it will be useful, but
00026 // WITHOUT ANY WARRANTY; without even the implied warranty of
00027 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00028 // General Public License for more details.
00029 //
00030 // You should have received a copy of the GNU General Public License
00031 // along with GroovX; if not, write to the Free Software Foundation,
00032 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00033 //
00034 ///////////////////////////////////////////////////////////////////////
00035 
00036 #ifndef GROOVX_RUTZ_FACTORY_H_UTC20050626084020_DEFINED
00037 #define GROOVX_RUTZ_FACTORY_H_UTC20050626084020_DEFINED
00038 
00039 #include "rutz/assocarray.h"
00040 #include "rutz/demangle.h"
00041 #include "rutz/fileposition.h"
00042 #include "rutz/mutex.h"
00043 #include "rutz/shared_ptr.h"
00044 #include "rutz/traits.h"
00045 
00046 #include <typeinfo>
00047 
00048 namespace rutz
00049 {
00050   class fstring;
00051 
00052   /// Abstract interface for creating objects of a particular type.
00053   /** rutz::creator_base is a template class that defines a single
00054       abstract function, create(), that returns an object of type
00055       creator_base::base_t. */
00056   template <class T>
00057   class creator_base
00058   {
00059   public:
00060     typedef T base_t;
00061 
00062     /// Virtual destructor.
00063     virtual ~creator_base() {}
00064 
00065     /// Return a clone of this Creator
00066     virtual creator_base* clone() const = 0;
00067 
00068     /// Return a new pointer (or smart pointer) to type \c Base.
00069     virtual base_t create() = 0;
00070   };
00071 
00072 
00073   /// Implements rutz::creator_base by calling a function pointer.
00074   /** rutz::creator_from_func implements the rutz::creator_base
00075       interface by storing a pointer to function that returns an
00076       object of the appropriate type. */
00077   template <class base_t, class derived_t>
00078   class creator_from_func : public rutz::creator_base<base_t>
00079   {
00080   public:
00081     /// Creator function type.
00082     typedef derived_t (*creator_func_t) ();
00083 
00084     /// Construct with a creator function.
00085     creator_from_func(creator_func_t func) :
00086       rutz::creator_base<base_t>(), m_creator_func(func) {}
00087 
00088     /// Clone operator.
00089     virtual rutz::creator_base<base_t>* clone() const
00090     { return new creator_from_func<base_t, derived_t>(*this); }
00091 
00092     /// Create an object using the creator function.
00093     virtual base_t create() { return base_t(m_creator_func()); }
00094 
00095   private:
00096     creator_func_t m_creator_func;
00097   };
00098 
00099 
00100   /// Abstract class for a fallback strategy when factory lookup fails.
00101   class factory_fallback
00102   {
00103   public:
00104     /// Default constructor.
00105     factory_fallback() throw();
00106 
00107     /// Virtual no-throw destructor for proper inheritance.
00108     virtual ~factory_fallback() throw();
00109 
00110     /// This will be called with the key whose lookup failed in the factory.
00111     virtual void try_fallback(const rutz::fstring& key) const = 0;
00112   };
00113 
00114   /// Non-template helper class for rutz::factory.
00115   class factory_base
00116   {
00117   public:
00118     typedef void (fallback_t)(const rutz::fstring&);
00119 
00120     /// Default constructor sets the fallback to null.
00121     factory_base() throw();
00122 
00123     /// Virtual no-throw destructor for proper inheritance.
00124     virtual ~factory_base() throw();
00125 
00126     /// Change the fallback object.
00127     void set_fallback(rutz::shared_ptr<factory_fallback> f);
00128 
00129     /// Change the fallback function.
00130     void set_fallback(fallback_t* fptr);
00131 
00132     /// Try running the fallback function for the given key.
00133     void try_fallback(const rutz::fstring& key) const;
00134 
00135   private:
00136     rutz::shared_ptr<factory_fallback> m_fallback;
00137   };
00138 
00139 
00140   /// Create objects base on 'key' strings.
00141   /** rutz::factory can create objects of different types associated
00142       with different 'key' strings. rutz::factory maintains a mapping
00143       from key strings to rutz::creator_base's, and so given a key can
00144       call the create() function of the associated creator_base. All
00145       of the product types of a factory must be derived from
00146       factory::base_t. The recommended usage is for factories for
00147       specific types to be implemented as singleton classes derived
00148       from rutz::factory.
00149 
00150       rutz::factory uses an internal mutex so that all of its member
00151       functions can safely be called in a multithreaded program
00152       without external locking.
00153   */
00154   template <class T>
00155   class factory
00156   {
00157   public:
00158     // typedefs
00159 
00160     typedef factory_base::fallback_t fallback_t;
00161     typedef T base_t;
00162 
00163   private:
00164     rutz::factory_base                               m_base;
00165     rutz::assoc_array<rutz::creator_base<base_t> >   m_map;
00166     mutable pthread_mutex_t                          m_mutex;
00167 
00168   protected:
00169     /// Find a creator for the given key; otherwise return null.
00170     rutz::creator_base<base_t>*
00171     find_creator(const rutz::fstring& key) const
00172     {
00173       rutz::creator_base<base_t>* creator = 0;
00174 
00175       {
00176         GVX_MUTEX_LOCK(&m_mutex);
00177         creator = m_map.get_ptr_for_key(key);
00178       }
00179 
00180       if (creator == 0)
00181         {
00182           // note that we must call try_fallback() with our mutex
00183           // UN-locked because the intention is that the fallback
00184           // function will try do something to cause a new entry to be
00185           // inserted into this very factory object; that insertion
00186           // will require locking the mutex so if we have the mutex
00187           // locked here we will end up with a deadlock:
00188           m_base.try_fallback(key);
00189 
00190           {
00191             GVX_MUTEX_LOCK(&m_mutex);
00192             creator = m_map.get_ptr_for_key(key);
00193           }
00194         }
00195 
00196       return creator;
00197     }
00198 
00199   public:
00200     /// Default constructor.
00201     /** @param key_descr a human-readable description of what this
00202         factory's keys represent; this is used in error messages,
00203         e.g. if descr is "frobnicator", then error messages would
00204         include "unknown frobnicator"
00205 
00206         @param nocase true if the factory should use case-insensitive
00207         string comparisons (default is false, giving normal
00208         case-sensitive string comparisons)
00209     */
00210     factory(const char* keydescr = "object type", bool nocase = false)
00211       : m_base(), m_map(keydescr, nocase), m_mutex()
00212     {
00213       pthread_mutex_init(&m_mutex, (pthread_mutexattr_t*) 0);
00214     }
00215 
00216     /// Virtual no-throw destructor.
00217     virtual ~factory() throw()
00218     {
00219       pthread_mutex_destroy(&m_mutex);
00220     }
00221 
00222     /// Registers a creation object with the factory.
00223     /** The function returns the actual key that was paired with the
00224         creation function.*/
00225     const char* register_creator(rutz::creator_base<base_t>* creator,
00226                                  const char* name)
00227     {
00228       GVX_MUTEX_LOCK(&m_mutex);
00229 
00230       m_map.set_ptr_for_key(name, creator);
00231 
00232       return name;
00233     }
00234 
00235     /// Registers a creation function with the factory.
00236     /** The default key associated with the creation function will be
00237         given by the type's actual C++ name. The function returns the
00238         actual key that was paired with the creation function.*/
00239     template <class derived_t>
00240     const char* register_creator(derived_t (*func) (),
00241                                  const char* key = 0)
00242     {
00243       GVX_MUTEX_LOCK(&m_mutex);
00244 
00245       if (key == 0)
00246         key = rutz::demangled_name
00247           (typeid(typename rutz::type_traits<derived_t>::pointee_t));
00248 
00249       m_map.set_ptr_for_key
00250         (key, new rutz::creator_from_func<base_t, derived_t>(func));
00251 
00252       return key;
00253     }
00254 
00255     /// Introduces an alternate key for an existing key.
00256     /** There must already have been a creation function registered
00257         for the original key. */
00258     void register_alias(const char* orig_key, const char* alias_key)
00259     {
00260       GVX_MUTEX_LOCK(&m_mutex);
00261 
00262       rutz::creator_base<base_t>* creator =
00263         m_map.get_ptr_for_key(orig_key);
00264 
00265       if (creator != 0)
00266         {
00267           m_map.set_ptr_for_key(alias_key, creator->clone());
00268         }
00269     }
00270 
00271     /// Query whether a given key is a valid, known key in the factory.
00272     bool is_valid_key(const char* key) const
00273     {
00274       return (this->find_creator(key) != 0);
00275     }
00276 
00277     /// Get a list of known keys, separated by sep.
00278     rutz::fstring get_known_keys(const char* sep) const
00279     {
00280       GVX_MUTEX_LOCK(&m_mutex);
00281 
00282       return m_map.get_known_keys(sep);
00283     }
00284 
00285     /// Returns a new object of a given type.
00286     /** If the given type has not been registered with the factory, a
00287         null pointer is returned. */
00288     base_t new_object(const rutz::fstring& type) const
00289     {
00290       rutz::creator_base<base_t>* creator = this->find_creator(type);
00291 
00292       if (creator == 0) return base_t();
00293 
00294       return creator->create();
00295     }
00296 
00297     /// Returns a new object of a given type.
00298     /** If the given type has not been registered with the factory, an
00299         exception is thrown. */
00300     base_t new_checked_object(const rutz::fstring& type) const
00301     {
00302       rutz::creator_base<base_t>* creator = this->find_creator(type);
00303 
00304       if (creator == 0)
00305         {
00306           GVX_MUTEX_LOCK(&m_mutex);
00307 
00308           m_map.throw_for_key(type, SRC_POS);
00309         }
00310 
00311       return creator->create();
00312     }
00313 
00314     /// Change the fallback object.
00315     void set_fallback(rutz::shared_ptr<factory_fallback> f)
00316     {
00317       GVX_MUTEX_LOCK(&m_mutex);
00318 
00319       m_base.set_fallback(f);
00320     }
00321 
00322     /// Change the fallback function.
00323     void set_fallback(fallback_t* fptr)
00324     {
00325       GVX_MUTEX_LOCK(&m_mutex);
00326 
00327       m_base.set_fallback(fptr);
00328     }
00329   };
00330 
00331 } // end namespace rutz
00332 
00333 
00334 static const char __attribute__((used)) vcid_groovx_rutz_factory_h_utc20050626084020[] = "$Id: factory.h 8274 2007-04-19 17:44:48Z rjpeters $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/factory.h $";
00335 #endif // !GROOVX_RUTZ_FACTORY_H_UTC20050626084020_DEFINED
Generated on Sun May 8 08:42:09 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3