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_