00001 /*!@file Simulation/test-serialization.C simple test code for serialization of SimEvent */ 00002 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00006 // by the University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Simulation/SimEvent.H $ 00036 // $Id: SimEvent.H 9031 2007-11-23 10:54:03Z siagian $ 00037 // 00038 00039 #include "Util/log.H" 00040 00041 #ifndef HAVE_BOOST_SERIALIZATION 00042 00043 int main(int argc, const char **argv) 00044 { 00045 LFATAL("You need Boost::Serialization installed on your system for this program to work"); 00046 return 1; 00047 } 00048 00049 #else 00050 00051 // include headers that implement an archive in simple text format 00052 #include <boost/archive/text_oarchive.hpp> 00053 #include <boost/archive/text_iarchive.hpp> 00054 #include <boost/serialization/access.hpp> 00055 #include <boost/serialization/config.hpp> 00056 #include <boost/serialization/vector.hpp> 00057 00058 #include <fstream> 00059 00060 typedef unsigned char byte; 00061 00062 // this code derived from http://www.boost.org/doc/libs/1_42_0/libs/serialization/doc/index.html 00063 00064 // ###################################################################### 00065 // ###################################################################### 00066 // Straight-up code for a serializable class and a derived class: 00067 // ###################################################################### 00068 // ###################################################################### 00069 00070 // ###################################################################### 00071 // SimModule is used in the constructor of SimEvent, here we just fake it 00072 class SimModule { 00073 }; 00074 00075 // ###################################################################### 00076 // Base class, contains no data 00077 // this will be provided in the systemwide definition of SimEvent 00078 class SimEvent { 00079 public: 00080 SimEvent(SimModule* src = 0) { } 00081 00082 virtual ~SimEvent() { } 00083 00084 inline std::string toString() const { return std::string("define me as in old SimEvent def"); } 00085 00086 private: 00087 friend class boost::serialization::access; 00088 template<class Archive> inline void serialize(Archive& ar, const unsigned int version) { } 00089 }; 00090 00091 BOOST_CLASS_VERSION(SimEvent, 0); // bump this whenever you change the class' serializable data members 00092 00093 // ###################################################################### 00094 // Class derived directly from SimEvent, adds two data members, one int and one float 00095 class MySimEvent : public SimEvent { 00096 public: 00097 MySimEvent(SimModule* src = 0) { } 00098 00099 MySimEvent(SimModule* src__, const int idata__, const float fdata__) : 00100 SimEvent(src__), idata_(idata__), fdata_(fdata__) { } 00101 00102 virtual ~MySimEvent() { } 00103 00104 int& idata() { return idata_; } 00105 float& fdata() { return fdata_; } 00106 00107 const int& idata() const { return idata_; } 00108 const float& fdata() const { return fdata_; } 00109 00110 private: 00111 friend class boost::serialization::access; 00112 00113 template<class Archive> void serialize(Archive& ar, const unsigned int version) 00114 { 00115 // serialize base class information: 00116 ar & boost::serialization::base_object<SimEvent>(*this); 00117 00118 // and the new data from the derived class: 00119 ar & idata_; 00120 ar & fdata_; 00121 } 00122 00123 int idata_; // some data member 00124 float fdata_; // some data member 00125 }; 00126 00127 BOOST_CLASS_VERSION(MySimEvent, 0); // bump this whenever you change the class' serializable data members 00128 00129 00130 // ###################################################################### 00131 // Class further derived from the derived MySimEvent, adds yet more data members 00132 class DerSimEvent : public MySimEvent { 00133 public: 00134 DerSimEvent(SimModule* src = 0) { } 00135 00136 DerSimEvent(SimModule* src__, const int idata__, const float fdata__, 00137 const std::string& sdata__, const std::vector<byte>& vdata__) : 00138 MySimEvent(src__, idata__, fdata__), sdata_(sdata__), vdata_(vdata__) { } 00139 00140 virtual ~DerSimEvent() { } 00141 00142 std::string& sdata() { return sdata_; } 00143 std::vector<byte>& vdata() { return vdata_; } 00144 00145 const std::string& sdata() const { return sdata_; } 00146 const std::vector<byte>& vdata() const { return vdata_; } 00147 00148 private: 00149 friend class boost::serialization::access; 00150 00151 template<class Archive> void serialize(Archive& ar, const unsigned int version) 00152 { 00153 // serialize base class information: 00154 ar & boost::serialization::base_object<MySimEvent>(*this); 00155 00156 // and the new data from the derived class: 00157 ar & sdata_; 00158 ar & vdata_; 00159 } 00160 00161 std::string sdata_; // note: initialization will deep copy, in reality we will use shared_ptr 00162 std::vector<byte> vdata_; 00163 }; 00164 00165 BOOST_CLASS_VERSION(DerSimEvent, 0); // bump this whenever you change the class' serializable data members 00166 00167 // ###################################################################### 00168 // ###################################################################### 00169 // Version with automatic creation of serialize() 00170 // ###################################################################### 00171 // ###################################################################### 00172 00173 // ********************************************************************** 00174 // ******************** INTERNALS: 00175 // ********************************************************************** 00176 00177 #include <boost/preprocessor/seq.hpp> 00178 #include <boost/preprocessor/arithmetic/add.hpp> 00179 #include <boost/preprocessor/comparison/equal.hpp> 00180 #include <boost/preprocessor/punctuation/comma.hpp> 00181 #include <boost/preprocessor/control/if.hpp> 00182 #include <boost/preprocessor/punctuation/paren.hpp> 00183 #include <boost/preprocessor/facilities/empty.hpp> 00184 00185 // try: g++ -include config.h -E src/Simulation/test-serialization.C to see the generated source 00186 00187 //! Root class for our SimEvent objects 00188 #define INVT_PP_SIMEVENT_ROOT_CLASS SimEvent 00189 00190 //! Build our class variable's name from the named passed 00191 #define INVT_PP_SIMEVENT_VAR(V) BOOST_PP_CAT(V, _) 00192 00193 //! Get elements of a tuple from our declaration list 00194 #define INVT_PP_SIMEVENT_ELEM_TYP(v) BOOST_PP_TUPLE_ELEM(2, 0, v) 00195 #define INVT_PP_SIMEVENT_ELEM_VAR(v) BOOST_PP_TUPLE_ELEM(2, 1, v) 00196 00197 //! Declare a variable (use with BOOST_PP_SEQ_FOR_EACH) 00198 #define INVT_PP_SIMEVENT_DECLARE(r,x,val) INVT_PP_SIMEVENT_ELEM_TYP(val) \ 00199 INVT_PP_SIMEVENT_VAR(INVT_PP_SIMEVENT_ELEM_VAR(val)); \ 00200 /**/ 00201 00202 //! Archive (serialization) action for a variable (use with BOOST_PP_SEQ_FOR_EACH) 00203 #define INVT_PP_SIMEVENT_ARCHIVE(r,x,val) ar & INVT_PP_SIMEVENT_VAR(INVT_PP_SIMEVENT_ELEM_VAR(val)); 00204 00205 //! Access function for a variable (use with BOOST_PP_SEQ_FOR_EACH) 00206 #define INVT_PP_SIMEVENT_ACCESS(r,x,val) \ 00207 inline INVT_PP_SIMEVENT_ELEM_TYP(val) & INVT_PP_SIMEVENT_ELEM_VAR(val)() \ 00208 { return INVT_PP_SIMEVENT_VAR(INVT_PP_SIMEVENT_ELEM_VAR(val)); } \ 00209 /**/ 00210 00211 //! Access function for a variable, const version (use with BOOST_PP_SEQ_FOR_EACH) 00212 #define INVT_PP_SIMEVENT_ACCESS_CONST(r,x,val) \ 00213 inline const INVT_PP_SIMEVENT_ELEM_TYP(val)& INVT_PP_SIMEVENT_ELEM_VAR(val)() const \ 00214 { return INVT_PP_SIMEVENT_VAR(INVT_PP_SIMEVENT_ELEM_VAR(val)); } \ 00215 /**/ 00216 00217 //! Some empty implementation of a function 00218 #define INVT_PP_SIMEVENT_EMPTY_IMPL { } 00219 00220 //! Default constructor 00221 #define INVT_PP_SIMEVENT_DEFAULT_CONSTRUCTOR(CLASSNAME, BASECLASSNAME, CONSTR) \ 00222 BOOST_PP_IF(BOOST_PP_EQUAL(CONSTR, 0), BOOST_PP_EMPTY(), \ 00223 CLASSNAME(SimModule* invt_pp_simevent_source = 0) \ 00224 BOOST_PP_IF(BOOST_PP_EQUAL(CONSTR, 1), ;, \ 00225 : BASECLASSNAME(invt_pp_simevent_source) INVT_PP_SIMEVENT_EMPTY_IMPL) ) \ 00226 /**/ 00227 00228 //! Destructor 00229 #define INVT_PP_SIMEVENT_DESTRUCTOR(CLASSNAME, DESTR) \ 00230 BOOST_PP_IF(BOOST_PP_EQUAL(DESTR, 0), BOOST_PP_EMPTY(), \ 00231 BOOST_PP_IF(BOOST_PP_EQUAL(DESTR, 1), virtual ~CLASSNAME();, \ 00232 virtual inline ~CLASSNAME() INVT_PP_SIMEVENT_EMPTY_IMPL) ) \ 00233 /**/ 00234 00235 //! Serialization friend, to allow the boost-serializer to access our private serialize() function 00236 #define INVT_PP_SIMEVENT_SERIALIZATION_FRIEND friend class boost::serialization::access; 00237 00238 //! Serialize function declaration and definition 00239 #define INVT_PP_SIMEVENT_SERIALIZE_FUNC(BASECLASSNAME, V) \ 00240 template<class Archive> inline void serialize(Archive& ar, const unsigned int version) \ 00241 { \ 00242 ar & boost::serialization::base_object<BASECLASSNAME>(*this); \ 00243 BOOST_PP_SEQ_FOR_EACH(INVT_PP_SIMEVENT_ARCHIVE,,V) \ 00244 } \ 00245 /**/ 00246 00247 //! toString function declaration 00248 #define INVT_PP_SIMEVENT_TOSTRING_DECL(BASECLASSNAME, TOSTR) \ 00249 BOOST_PP_IF(BOOST_PP_EQUAL(TOSTR, 0), BOOST_PP_EMPTY(), \ 00250 virtual std::string toString() const \ 00251 BOOST_PP_IF(BOOST_PP_EQUAL(TOSTR, 1), ;, { return BASECLASSNAME::toString(); } ) ) 00252 /**/ 00253 00254 //! General class declaration 00255 #define INVT_PP_SIMEVENT_CLASSDECL(CLASSNAME, BASECLASSNAME, CLASSDECL, SERVERSION) \ 00256 BOOST_PP_IF(BOOST_PP_EQUAL(CLASSDECL, 0), BOOST_PP_EMPTY(), \ 00257 class CLASSNAME; \ 00258 BOOST_CLASS_VERSION(CLASSNAME, SERVERSION); \ 00259 class CLASSNAME : public BASECLASSNAME { ) \ 00260 /**/ 00261 00262 // ********************************************************************** 00263 // ******************** USER MACROS: 00264 // ********************************************************************** 00265 00266 //! Class declaration for a SimEvent derived class 00267 /*! CLASSDECL = 0 (no class declaration, no opening brace), 1 (class decl + brace) 00268 CONSTR = 0 (no default constructor), 1 (declaration), 2 (decl + empty implementation) 00269 DESTR = 0 (no destructor), 1 (declaration), 2 (decl + empty implementation) 00270 TOSTR = 0 (no toString() declaration), 1 (declaration), 2 (decl + empty implementation) */ 00271 00272 #define SIMEVENT_CLASS_DECLARATION_INTERNAL(CLASSNAME, BASECLASSNAME, V, CLASSDECL, CONSTR, DESTR, TOSTR, SERVERSION) \ 00273 INVT_PP_SIMEVENT_CLASSDECL(CLASSNAME, BASECLASSNAME, CLASSDECL, SERVERSION) \ 00274 \ 00275 public: \ 00276 INVT_PP_SIMEVENT_DEFAULT_CONSTRUCTOR(CLASSNAME, BASECLASSNAME, CONSTR) \ 00277 INVT_PP_SIMEVENT_DESTRUCTOR(CLASSNAME, DESTR) \ 00278 BOOST_PP_SEQ_FOR_EACH(INVT_PP_SIMEVENT_ACCESS,, V) \ 00279 BOOST_PP_SEQ_FOR_EACH(INVT_PP_SIMEVENT_ACCESS_CONST,, V) \ 00280 INVT_PP_SIMEVENT_TOSTRING_DECL(BASECLASSNAME, TOSTR) \ 00281 \ 00282 private: \ 00283 BOOST_PP_SEQ_FOR_EACH(INVT_PP_SIMEVENT_DECLARE,, V) \ 00284 INVT_PP_SIMEVENT_SERIALIZATION_FRIEND \ 00285 INVT_PP_SIMEVENT_SERIALIZE_FUNC(BASECLASSNAME, V) \ 00286 /**/ 00287 00288 // ##### Declare the class and define a bunch of things in it. Nice but screws up auto-indent in emacs 00289 #define SIMEVENT_CLASS_DECLARATION_TRIVIAL(CLASSNAME) \ 00290 SIMEVENT_CLASS_DECLARATION_INTERNAL(CLASSNAME, INVT_PP_SIMEVENT_ROOT_CLASS, , 1, 2, 2, 2, 0) 00291 00292 #define SIMEVENT_CLASS_DECLARATION_SIMPLE(CLASSNAME, V) \ 00293 SIMEVENT_CLASS_DECLARATION_INTERNAL(CLASSNAME, INVT_PP_SIMEVENT_ROOT_CLASS, V, 1, 2, 2, 1, 0) 00294 00295 #define SIMEVENT_CLASS_DECLARATION_BARE(CLASSNAME, BASECLASSNAME, V) \ 00296 SIMEVENT_CLASS_DECLARATION_INTERNAL(CLASSNAME, BASECLASSNAME, V, 1, 0, 0, 0, 0) 00297 00298 #define SIMEVENT_CLASS_DECLARATION(CLASSNAME, BASECLASSNAME, V, CONSTR, DESTR, TOSTR, SERVERSION) \ 00299 SIMEVENT_CLASS_DECLARATION_INTERNAL(CLASSNAME, BASECLASSNAME, V, 1, CONSTR, DESTR, TOSTR, SERVERSION) \ 00300 /**/ 00301 00302 // ##### You declare the class manually (including opening brace), and here we just fill in the details 00303 #define SIMEVENT_CLASS_DEFINITION_TRIVIAL(CLASSNAME) \ 00304 SIMEVENT_CLASS_DECLARATION_INTERNAL(CLASSNAME, INVT_PP_SIMEVENT_ROOT_CLASS, , 0, 2, 2, 2, 0) 00305 00306 #define SIMEVENT_CLASS_DEFINITION_SIMPLE(CLASSNAME, V) \ 00307 SIMEVENT_CLASS_DECLARATION_INTERNAL(CLASSNAME, INVT_PP_SIMEVENT_ROOT_CLASS, V, 0, 2, 2, 1, 0) 00308 00309 #define SIMEVENT_CLASS_DEFINITION_BARE(CLASSNAME, BASECLASSNAME, V) \ 00310 SIMEVENT_CLASS_DECLARATION_INTERNAL(CLASSNAME, BASECLASSNAME, V, 0, 0, 0, 0, 0) 00311 00312 #define SIMEVENT_CLASS_DEFINITION(CLASSNAME, BASECLASSNAME, V, CONSTR, DESTR, TOSTR, SERVERSION) \ 00313 SIMEVENT_CLASS_DECLARATION_INTERNAL(CLASSNAME, BASECLASSNAME, V, 0, CONSTR, DESTR, TOSTR, SERVERSION) \ 00314 /**/ 00315 00316 00317 // ********************************************************************** 00318 // ******************** Examples: 00319 // ********************************************************************** 00320 00321 // ###################################################################### 00322 SIMEVENT_CLASS_DECLARATION_TRIVIAL(TrivSimEvent) 00323 // could declare alternate (parameterized) constructors here 00324 00325 // could declare member functions here 00326 00327 // you should not declare data members here, all your data members should be serializable! 00328 }; 00329 00330 // ###################################################################### 00331 SIMEVENT_CLASS_DECLARATION_SIMPLE( MySimEvent2, 00332 (( int, idata )) 00333 (( float, fdata )) ) 00334 public: 00335 // could declare alternate (parameterized) constructors here, for example: 00336 MySimEvent2(SimModule* src__, const int idata__, const float fdata__) : 00337 SimEvent(src__), idata_(idata__), fdata_(fdata__) { } 00338 00339 00340 // could declare member functions here 00341 00342 // you should not declare data members here, all your data members should be serializable! 00343 00344 // can access data members either directly as idata_ and fdata_ (which are private), or through the public member 00345 // functions idata() and fdata() which both exist in const and non-const versions 00346 }; 00347 00348 // we just need to implement toString() outside the class declaration: 00349 std::string MySimEvent2::toString() const 00350 { return SimEvent::toString() + "MySimEvent2 Message"; } 00351 00352 // ###################################################################### 00353 class DerSimEvent2 : public MySimEvent2 { 00354 00355 // bare definition, only our vars, serialize and access functions, no constr, destr, or toString() 00356 SIMEVENT_CLASS_DEFINITION_BARE( DerSimEvent2, MySimEvent2, 00357 (( std::string, sdata )) 00358 (( std::vector<byte>, vdata )) ) 00359 00360 public: 00361 // could declare alternate (parameterized) constructors here, for example: 00362 DerSimEvent2(SimModule* src__, const int idata__, const float fdata__, 00363 const std::string& sdata__, const std::vector<byte>& vdata__) : 00364 MySimEvent2(src__, idata__, fdata__), sdata_(sdata__), vdata_(vdata__) { } 00365 00366 // could declare member functions here 00367 00368 // you should not declare data members here, all your data members should be serializable! 00369 00370 // finally need to declare and implement constr, destr, and toString() function: 00371 00372 // can both declare and implement here 00373 DerSimEvent2(SimModule* src = 0) : MySimEvent2(src) { /* do something cool */ } 00374 00375 // can both declare and implement here 00376 virtual ~DerSimEvent2() { /* do something rad */ } 00377 00378 // or can just declare and will implement later 00379 std::string toString() const; 00380 }; 00381 00382 // need to implement toString() outside the class declaration: 00383 std::string DerSimEvent2::toString() const 00384 { return MySimEvent2::toString() + "DerSimEvent2 Message"; } 00385 00386 // ###################################################################### 00387 // ###################################################################### 00388 // Test program: 00389 // ###################################################################### 00390 // ###################################################################### 00391 00392 // choose MySimEvent or MySimEvent2, DerSimEvent or DerSimEvent2 00393 #if 0 00394 # define MYSIMEVENT MySimEvent 00395 # define DERSIMEVENT DerSimEvent 00396 #else 00397 # define MYSIMEVENT MySimEvent2 00398 # define DERSIMEVENT DerSimEvent2 00399 #endif 00400 00401 int main(int argc, const char **argv) 00402 { 00403 // create and open a character archive for output 00404 std::ofstream ofs("test-serialization.object"); 00405 00406 // create class instance 00407 SimModule *sm = 0; 00408 std::vector<byte> v; v.push_back(byte(3)); v.push_back(byte(42)); 00409 std::string str("serialization inferno"); 00410 const DERSIMEVENT s(sm, 5, 10.0F, str, v); 00411 00412 LINFO("original data: %d %f '%s' [%d %d]", s.idata(), s.fdata(), s.sdata().c_str(), s.vdata()[0], s.vdata()[1]); 00413 00414 // save data to archive 00415 { 00416 boost::archive::text_oarchive oa(ofs); 00417 // write class instance to archive 00418 oa << s; 00419 // archive and stream closed when destructors are called 00420 } 00421 00422 // ... some time later restore the class instance to its orginal state 00423 DERSIMEVENT ss(sm); 00424 00425 LINFO("new object before load: %d %f '%s' []", ss.idata(), ss.fdata(), ss.sdata().c_str()); 00426 00427 { 00428 // create and open an archive for input 00429 std::ifstream ifs("test-serialization.object"); 00430 boost::archive::text_iarchive ia(ifs); 00431 // read class state from archive 00432 ia >> ss; 00433 // archive and stream closed when destructors are called 00434 } 00435 00436 LINFO("re-loaded data: %d %f '%s' [%d %d]", s.idata(), s.fdata(), s.sdata().c_str(), s.vdata()[0], s.vdata()[1]); 00437 00438 return 0; 00439 } 00440 00441 00442 #endif 00443 00444 // ###################################################################### 00445 /* So things look consistent in everyone's emacs... */ 00446 /* Local Variables: */ 00447 /* mode: c++ */ 00448 /* indent-tabs-mode: nil */ 00449 /* End: */