core/vsl/vsl_clipon_binary_loader.h
Go to the documentation of this file.
00001 // This is core/vsl/vsl_clipon_binary_loader.h
00002 #ifndef vsl_clipon_binary_loader_h_
00003 #define vsl_clipon_binary_loader_h_
00004 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00005 #pragma interface
00006 #endif
00007 //:
00008 // \file
00009 
00010 #include <vsl/vsl_binary_loader_base.h>
00011 #include <vsl/vsl_binary_io.h>
00012 #include <vcl_vector.h>
00013 #include <vcl_string.h>
00014 
00015 //: Class to load objects by baseclass pointer using `clipon' classes
00016 // An example of a singleton design pattern for loading
00017 // a DerivedClass from a stream into a BaseClass*.
00018 // All we are given is a BaseClass* into which
00019 // the object has to be loaded but we can only tell
00020 // what sort of object it is from the name information
00021 // stored in the stream.
00022 // We assume the existence of a polymorphic hierarchy of `clipon'
00023 // loader objects, eg BaseClassIO and DerivedClassIO, one per
00024 // class in the hierarchy derived from BaseClass. Each XXXXIO
00025 // class is able to read and write the corresponding XXXX class.
00026 //
00027 // BaseClassIO must implement the following functions:
00028 // \code
00029 // //: Base for objects which provide IO for classes derived from BaseClass
00030 // class BaseClassIO
00031 // {
00032 //  public:
00033 //   //: Create new object of type BaseClass on heap
00034 //   virtual BaseClass* new_object() const;
00035 //   //: Write derived class to os using baseclass reference
00036 //   virtual void b_write_by_base(vsl_b_ostream& os,
00037 //                                const BaseClass& base) const;
00038 //   //: Write derived class to os using baseclass reference
00039 //   virtual void b_read_by_base(vsl_b_istream& is, BaseClass& base) const;
00040 //   //: Print summary to stream by BaseClass pointer
00041 //   void vsl_print_summary(vsl_b_ostream &os, const BaseClass * b);
00042 //   //: Copy this object onto the heap and return a pointer
00043 //   virtual BaseClassIO* clone() const;
00044 //   //: Return name of class for which this object provides IO
00045 //   virtual vcl_string target_classname() const;
00046 //   //: Return true if b is of class target_classname()
00047 //   //  Typically this will just be "return b.is_a()==target_classname()"
00048 //   //  However, third party libraries may use a different system
00049 //   virtual bool is_io_for(const BaseClass& b) const;
00050 // };
00051 // \endcode
00052 //
00053 // To handle the actual IO we define a loader
00054 // which has a list of BaseClassIO pointers,
00055 // and the ChainOfResponsibility (Design Pattern)
00056 // approach is used to load the object i.e. each
00057 // io->target_classname() is matched against the string on the stream
00058 // until we find a match or run out of pointers. If
00059 // a pointer is found which matches the string on
00060 // the stream, we use it to create an object on the
00061 // heap (using io->new_object()) and then load the
00062 // data into that from the stream (using io->b_read_by_base())
00063 //
00064 // We use a singleton so that there is only one list of
00065 // concrete derived classes which can be added
00066 // to for loading purposes. If you derive a new
00067 // class you just have to append it to the list of
00068 // classes of the singleton, viz:
00069 //     vsl_clipon_binary_loader<B,IO>::instance().add(my_object)
00070 //
00071 // For examples of usage please see vsl/tests/test_clipon_polymorphic_io.cxx
00072 // or look in the Binary IO chapter of the VXL book.
00073 //
00074 // To indicate a null pointer (0), the string "VSL_NULL_PTR" is saved
00075 // to the stream.
00076 // All loader singletons can be deleted using vsl_delete_all_loaders()
00077 template<class BaseClass, class BaseClassIO>
00078 class vsl_clipon_binary_loader : public vsl_binary_loader_base
00079 {
00080   //: the singleton object
00081   static vsl_clipon_binary_loader<BaseClass,BaseClassIO>* instance_;
00082 
00083   //: List of object loaders
00084   vcl_vector<BaseClassIO*> object_io_;
00085 
00086   //: Return index associated with given object name
00087   int index_for_name(const vcl_string& name) const;
00088 
00089  public:
00090   //: Constructor
00091   vsl_clipon_binary_loader() {}
00092 
00093   //: Destructor
00094   ~vsl_clipon_binary_loader();
00095 
00096   //: Returns the instance variable for the singleton.
00097   static vsl_clipon_binary_loader<BaseClass,BaseClassIO>& instance();
00098 
00099   //: Remove all example objects
00100   void make_empty();
00101 
00102   //: Add example object to list of those that can be loaded
00103   void add( const BaseClassIO& b);
00104 
00105   //: Return current list of individual IO objects
00106   const vcl_vector<BaseClassIO*>& object_io() const { return object_io_; }
00107 
00108   //: Return IO object for given named class
00109   //  Aborts if not available
00110   const BaseClassIO& object_io(const vcl_string& name) const;
00111 
00112   //: Return IO object that can deal with given class
00113   const BaseClassIO& io_for_class(const BaseClass& b) const;
00114 
00115   //: Reads object from stream and sets base class pointer
00116   //  Determines which derived class object on stream belongs
00117   //  to, loads it and sets b to be a pointer to it.
00118   //  (Class must be one given to Loader by the add method).
00119   //  If is indicates a NULL pointer, b will be set to NULL.
00120   //  If b not initially NULL, *b will be deleted.
00121   void read_object( vsl_b_istream& is, BaseClass*& b);
00122 
00123   //: Writes object to stream given base class pointer
00124   //  Determines which derived class object is
00125   //  and calls the appropriate write function.
00126   //  (Class must be one given to Loader by the add method).
00127   //  If b==0, a suitable string will be saved
00128   void write_object( vsl_b_ostream& is, const BaseClass* b);
00129 
00130   //: Prints summary of object state to stream given base class pointer
00131   //  Determines which derived class object is
00132   //  and calls the appropriate print summary function.
00133   //  (Class must be one given to Loader by the add method).
00134   //  If b==0, a suitable string will be saved
00135   void print_object_summary( vcl_ostream& os, const BaseClass* b);
00136 };
00137 
00138 
00139 #if 0
00140 //: Loads object and sets base class pointer
00141 //  Determines which derived class object on bfs belongs
00142 //  to, loads it and sets b to be a pointer to it.
00143 //  (Class must be one given to Loader by the append method).
00144 //  If bfs indicates a NULL pointer, b will be set to NULL.
00145 //  If b not initially NULL, *b will be deleted.
00146 inline void vsl_b_read( vsl_b_istream& bfs, BaseClass*& b)
00147 {
00148   vsl_clipon_binary_loader<BaseClass,BaseClassIO>::
00149     instance().load_object(bfs,b);
00150 }
00151 #endif // 0
00152 
00153 #endif // vsl_clipon_binary_loader_h_