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