contrib/mul/mbl/mbl_cloneables_factory.h
Go to the documentation of this file.
00001 // This is mul/mbl/mbl_cloneables_factory.h
00002 #ifndef mbl_cloneables_factory_h
00003 #define mbl_cloneables_factory_h
00004 //:
00005 //  \file
00006 // \brief A general factory pattern.
00007 // \author Ian Scott.
00008 
00009 #include <vcl_map.h>
00010 // not used? #include <vcl_utility.h>
00011 #include <vcl_memory.h>
00012 #include <vcl_string.h>
00013 #include <vcl_sstream.h>
00014 #include <mbl/mbl_exception.h>
00015 #include <mbl/mbl_cloneable_ptr.h>
00016 
00017 //=======================================================================
00018 //: A general factory pattern.
00019 // After templating this on a base class, and loading in
00020 // a bunch of concrete instantiations of the derived classes,
00021 // you can create any of the derived classes simply from
00022 // the class's name.
00023 //
00024 // BASE must define a clone() and is_a() members
00025 // \code
00026 // class BASE
00027 // {
00028 //   ...
00029 // public:
00030 //   virtual BASE* clone() const=0; // Derived classes must copy themselves.
00031 //   virtual vcl_string BASE::is_a() const; {
00032 //     return "BASE";} // Derived classes need unique names.
00033 // }
00034 // \endcode
00035 //
00036 // Example:
00037 // \code
00038 // mbl_cloneables_factory<vimt_image>::add(vimt_image_2d());
00039 // mbl_cloneables_factory<vimt_image>::add(vimt_image_3d());
00040 //
00041 // vcl_auto_ptr<vimt_image> p = mbl_cloneables_factory<vimt_image>::get_clone("vimt_image_2d()");
00042 // assert(dynamic_cast<vimt_image_2d>(p));
00043 // \endcode
00044 
00045 
00046 template <class BASE>
00047 class mbl_cloneables_factory
00048 {
00049  private: 
00050   typedef vcl_map<vcl_string, mbl_cloneable_ptr<BASE> > MAP;
00051 
00052   //: Singleton array of names, and association concrete instantiations of BASE.
00053   static vcl_auto_ptr<MAP> objects_;
00054 
00055  private:
00056 
00057   //: Get singleton instance.
00058   static MAP &objects()
00059   {
00060     if (objects_.get() == 0)
00061       objects_.reset(new MAP);
00062  
00063     return *objects_;
00064   }
00065 
00066  public:
00067 
00068   //: Add an object for later cloning by the factory.
00069   // Use the object's class name via the is_a() member.
00070   static void add(const BASE & object) { add(object, object.is_a()); }
00071 
00072   //: Add an object for later cloning by the factory.
00073   // If there already is an object called name, it will
00074   // be overwritten.
00075   static void add(const BASE & object, const vcl_string & name)
00076   {
00077     objects()[name] = object;
00078   }
00079 
00080   //: Get a pointer to a new copy of the object identified by name.
00081   // An exception will be thrown if name does not exist.
00082   static vcl_auto_ptr<BASE > get_clone(const vcl_string & name)
00083   {
00084     typedef VCL_DISAPPEARING_TYPENAME MAP::const_iterator IT;
00085 
00086     IT found = objects().find(name);
00087     const IT end = objects().end();
00088 
00089     if (found == end)
00090     {
00091       vcl_ostringstream ss;
00092       IT it = objects().begin();
00093       if (!objects().empty())
00094       {
00095         ss << it->first;
00096         while ( ++it != end)
00097           ss << ", " << it->first;
00098       }
00099       mbl_exception_error(mbl_exception_no_name_in_factory(name, ss.str()));
00100       return vcl_auto_ptr<BASE >();
00101     }
00102     return vcl_auto_ptr<BASE >(found->second->clone());
00103   }
00104 };
00105 
00106 // Macro to instantiate template, and initialise singleton data item.
00107 #define MBL_CLONEABLES_FACTORY_INSTANTIATE(T) \
00108 template <class BASE > \
00109 vcl_auto_ptr<VCL_DISAPPEARING_TYPENAME mbl_cloneables_factory<BASE >::MAP > \
00110   mbl_cloneables_factory<BASE >::objects_ =  \
00111     vcl_auto_ptr<VCL_DISAPPEARING_TYPENAME mbl_cloneables_factory<BASE >::MAP >(0); \
00112 template class mbl_cloneables_factory< T >
00113 
00114 #endif  // mbl_cloneables_factory_h