core/vbl/io/vbl_io_smart_ptr.txx
Go to the documentation of this file.
00001 // This is core/vbl/io/vbl_io_smart_ptr.txx
00002 #ifndef vbl_io_smart_ptr_txx_
00003 #define vbl_io_smart_ptr_txx_
00004 //:
00005 // \file
00006 // \brief Serialised binary IO functions for vbl_smart_ptr<T>
00007 // \author Ian Scott (Manchester)
00008 // \date 26-Mar-2001
00009 
00010 #include "vbl_io_smart_ptr.h"
00011 #include <vsl/vsl_binary_io.h>
00012 #include <vbl/vbl_smart_ptr.h>
00013 #include <vcl_cstdlib.h> // vcl_abort()
00014 
00015 //=========================================================================
00016 //: Binary save self to stream.
00017 template<class T>
00018 void vsl_b_write(vsl_b_ostream & os, const vbl_smart_ptr<T> &p)
00019 {
00020   // write version number
00021   const short io_version_no = 2;
00022   vsl_b_write(os, io_version_no);
00023   vsl_b_write(os, p.is_protected());
00024 
00025   if (p.ptr() == 0)  // Deal with Null pointers first.
00026   {
00027     vsl_b_write(os, true);
00028     vsl_b_write(os, 0ul); // Use 0 to indicate a null pointer.
00029                           // True serialisation IDs are always 1 or more.
00030     return;
00031   }
00032 
00033   // Get a serial_number for object being pointed to
00034   unsigned long id = os.get_serial_number(p.ptr());
00035   // Find out if this is the first time the object being pointed to is
00036   // being saved
00037   if (id == 0)
00038   {
00039     // <rant> IMS
00040     // It is not clear how to deal fully satisfactorily with unprotected
00041     // smart_ptrs. For example is we save and reload them without any error
00042     // checks we could restore the object with a reference count of 0.
00043     // To be honest, I think the idea of an unprotected smart_ptr is
00044     // not so smart. Either it is a smart pointer, in which case it should
00045     // be protected, or it is unprotected in which case you should use a
00046     // ordinary pointer. Cycles in the pointer network, are best dealt with
00047     // by avoiding them. You have to be aware they are happening to unprotect
00048     // the pointer anyway.
00049     // </rant>
00050     if (!p.is_protected())
00051     {
00052         vcl_cerr << "vsl_b_write(vsl_b_ostream & os, const vbl_smart_ptr<T>&):"
00053                  << " You cannot\nsave unprotected smart pointers before saving"
00054                  << " a protected smart pointer\nto the same object. Either do"
00055                  << " not save unprotected smart pointers, or\nbe very careful"
00056                  << " about the order.\n";
00057         vcl_abort();
00058     }
00059 
00060     id = os.add_serialisation_record(p.ptr());
00061 
00062       // Say that this is the first time
00063       // that this object is being saved.
00064       // This isn't really necessary but
00065       // it is useful as an error check
00066     vsl_b_write(os, true);
00067     vsl_b_write(os, id);     // Save the serial number
00068 // If you get an error in the next line, it could be because your type T
00069 // has no vsl_b_write(vsl_b_ostream &,const T*)  defined on it.
00070 // See the documentation in the .h file to see how to add it.
00071     vsl_b_write(os, p.ptr());    // Only save the actual object if it
00072                                   //hasn't been saved before to this stream
00073   }
00074   else
00075   {
00076       // Say that this is not the first time
00077       // that this object is being saved.
00078       // This isn't really necessary but
00079       // it is useful as an error check
00080 
00081     vsl_b_write(os, false);
00082     vsl_b_write(os, id);         // Save the serial number
00083   }
00084 }
00085 
00086 //=====================================================================
00087 //: Binary load self from stream.
00088 template<class T>
00089 void vsl_b_read(vsl_b_istream &is, vbl_smart_ptr<T> &p)
00090 {
00091   if (!is) return;
00092 
00093   short ver;
00094   vsl_b_read(is, ver);
00095   switch (ver)
00096   {
00097    case 1:
00098    case 2:
00099    {
00100     bool is_protected; // true if the smart_ptr is to be
00101                        //responsible for the object
00102     vsl_b_read(is, is_protected);
00103 
00104     bool first_time; // true if the object is about to be loaded
00105     vsl_b_read(is, first_time);
00106 
00107     if (first_time && !is_protected)  // This should have been
00108     {                                  //checked during saving
00109       vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vbl_smart_ptr<T>&)\n"
00110                << "           De-serialisation failure of non-protected smart_ptr\n";
00111       is.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00112       return;
00113     }
00114     unsigned long id; // Unique serial number indentifying object
00115     vsl_b_read(is, id);
00116 
00117     if (id == 0) // Deal with Null pointers first.
00118     {
00119       p = 0;
00120       return;
00121     }
00122 
00123     T * pointer = static_cast<T *>( is.get_serialisation_pointer(id));
00124     if (first_time != (pointer == 0))
00125     {
00126       // This checks that the saving stream and reading stream
00127       // both agree on whether or not this is the first time they
00128       // have seen this object.
00129       vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vbl_smart_ptr<T>&)\n"
00130                << "           De-serialisation failure\n";
00131       is.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00132       return;
00133     }
00134 
00135     if (pointer == 0)
00136     {
00137       // If you get an error in the next line, it could be because your type T
00138       // has no vsl_b_read(vsl_b_istream&,T*&)  defined on it.
00139       // See the documentation in the .h file to see how to add it.
00140       vsl_b_read(is, pointer);
00141       is.add_serialisation_record(id, pointer);
00142     }
00143 
00144     p = pointer; // This operator method will set the internal
00145                  //pointer in vbl_smart_ptr.
00146     if (!is_protected)
00147       p.unprotect();
00148 
00149     break;
00150    }
00151    default:
00152     vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, vbl_smart_ptr<T>&)\n"
00153              << "           Unknown version number "<< ver << '\n';
00154     is.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00155     return;
00156   }
00157 }
00158 
00159 //=====================================================================
00160 //: Output a human readable summary to the stream
00161 template<class T>
00162 void vsl_print_summary(vcl_ostream & os,const vbl_smart_ptr<T> & p)
00163 {
00164   if (p.is_protected())
00165     os <<"Unprotected ";
00166   os << "Smart ptr to ";
00167   if (p.ptr())
00168   {
00169     // If you get an error in the next line, it could be because your type T
00170     // has no vsl_print_summary(vsl_b_ostream &, const T*)  defined on it.
00171     // See the documentation in the .h file to see how to add it.
00172     vsl_print_summary(os, p.ptr());
00173   }
00174   else
00175     os << "NULL";
00176 }
00177 
00178 
00179 #undef VBL_IO_SMART_PTR_INSTANTIATE
00180 #define VBL_IO_SMART_PTR_INSTANTIATE(T) \
00181 template void vsl_print_summary(vcl_ostream &, const vbl_smart_ptr<T > &); \
00182 template void vsl_b_read(vsl_b_istream &, vbl_smart_ptr<T > &); \
00183 template void vsl_b_write(vsl_b_ostream &, const vbl_smart_ptr<T > &)
00184 
00185 #endif // vbl_io_smart_ptr_txx_