//========================================================================= // binaryIO.hh // // "Low-level" utility API for reading/writing data in a binary form // (this particular form is not platform independent). All "geners" I/O // should be performed through one of the functions defined in this file, // there should be no direct user manipulation of C++ streams. In this // way possible future I/O modifications will be isolated and restricted // to this facility. // // I. Volobouev // April 2009 //========================================================================= #ifndef GENERS_BINARYIO_HH_ #define GENERS_BINARYIO_HH_ #include #include #include #include "geners/CPP11_shared_ptr.hh" #include "geners/CPP11_auto_ptr.hh" #include "geners/ClassId.hh" #include "geners/IOException.hh" namespace gs { // The following functions perform binary I/O of built-in types. // Note that all of them are "void". It is assumed that the // top-level code will check the status of the stream after // several I/O operations. template inline void write_pod(std::ostream& of, const T& pod) { of.write(reinterpret_cast(&pod), sizeof(T)); } template inline void read_pod(std::istream& in, T* pod) { assert(pod); in.read(reinterpret_cast(pod), sizeof(T)); } template inline void write_pod_array(std::ostream& of, const T* pod, const unsigned long len) { if (len) { assert(pod); of.write(reinterpret_cast(pod), len*sizeof(T)); } } template inline void read_pod_array(std::istream& in, T* pod, const unsigned long len) { if (len) { assert(pod); in.read(reinterpret_cast(pod), len*sizeof(T)); } } // String is treated as a pod vector. This will be guaranteed // to work correctly in the C++11 standard (the current standard // does not specify that the characters must be stored contuguously // inside the string -- however, this is always true in practice). template inline void write_string(std::ostream& of, const std::basic_string& v) { const unsigned long sz = v.size(); write_pod(of, sz); if (sz) write_pod_array(of, v.data(), sz); } template inline void read_string(std::istream& in, std::basic_string* pv) { assert(pv); unsigned long vlen = 0UL; read_pod(in, &vlen); if (vlen) { pv->resize(vlen); read_pod_array(in, const_cast(pv->data()), vlen); } else pv->clear(); } // Specialization of POD-based I/O functions so that they work // as if std::string is a POD template<> inline void write_pod(std::ostream& of, const std::string& s) { write_string(of, s); } template<> inline void read_pod(std::istream& in, std::string* ps) { read_string(in, ps); } template<> inline void write_pod_array(std::ostream& of, const std::string* pod, const unsigned long len) { if (len) { assert(pod); for (unsigned long i=0; i(of, pod[i]); } } template<> inline void read_pod_array(std::istream& in, std::string* pod, const unsigned long len) { if (len) { assert(pod); for (unsigned long i=0; i(in, pod + i); } } template inline void write_pod_vector(std::ostream& of, const std::vector& v) { const unsigned long sz = v.size(); write_pod(of, sz); if (sz) write_pod_array(of, &v[0], sz); } template inline void read_pod_vector(std::istream& in, std::vector* pv) { assert(pv); unsigned long vlen = 0UL; read_pod(in, &vlen); if (in.fail()) throw IOReadFailure( "In gs::read_pod_vector: input stream failure"); if (vlen) { pv->resize(vlen); read_pod_array(in, &((*pv)[0]), vlen); } else pv->clear(); } // The following functions perform binary I/O on objects // which have write/read/restore functions. Compared to // calling the corresponding class methods directly, these // function take care of writing out the class identifier. // template inline bool write_obj(std::ostream& of, const T& obj) { return obj.classId().write(of) && obj.write(of); } template inline CPP11_auto_ptr read_obj(std::istream& in) { const ClassId id(in, 1); return CPP11_auto_ptr(T::read(id, in)); } template inline void restore_obj(std::istream& in, T* obj) { assert(obj); const ClassId id(in, 1); T::restore(id, in, obj); } // The following function is templated upon the reader factory template inline CPP11_auto_ptr read_base_obj(std::istream& in, const Reader& f) { typedef typename Reader::value_type T; const ClassId id(in, 1); return CPP11_auto_ptr(f.read(id, in)); } // The following function assumes that the array contains actual // objects rather than pointers template inline bool write_obj_array(std::ostream& of, const T* arr, const unsigned long len) { bool status = true; if (len) { assert(arr); status = arr[0].classId().write(of); for (unsigned long i=0; i inline void read_placed_obj_array(std::istream& in, T* arr, const unsigned long len) { if (len) { assert(arr); const ClassId id(in, 1); for (unsigned long i=0; i inline void read_heap_obj_array(std::istream& in, CPP11_shared_ptr* arr, const unsigned long len) { if (len) { assert(arr); const ClassId id(in, 1); for (unsigned long i=0; i(obj); } } } // The following function is templated upon the reader factory template inline void read_base_obj_array( std::istream& in, const Reader& f, CPP11_shared_ptr* arr, const unsigned long len) { typedef typename Reader::value_type T; if (len) { assert(arr); const ClassId id(in, 1); for (unsigned long i=0; i(obj); } } } // The following assumes that the vector contains actual objects template inline bool write_obj_vector(std::ostream& of, const std::vector& v) { const unsigned long sz = v.size(); write_pod(of, sz); bool status = !of.fail(); if (sz && status) status = write_obj_array(of, &v[0], sz); return status; } // The following assumes that the vector contains actual objects template inline void read_placed_obj_vector(std::istream& in, std::vector* pv) { unsigned long vlen = 0UL; read_pod(in, &vlen); if (in.fail()) throw IOReadFailure( "In gs::read_placed_obj_vector: input stream failure"); assert(pv); if (vlen) { pv->resize(vlen); read_placed_obj_array(in, &(*pv)[0], vlen); } else pv->clear(); } // The following assumes that the vector contains a bunch of // shared pointers template inline void read_heap_obj_vector(std::istream& in, std::vector >* pv) { unsigned long vlen = 0UL; read_pod(in, &vlen); if (in.fail()) throw IOReadFailure( "In gs::read_heap_obj_vector: input stream failure"); assert(pv); if (vlen) { pv->resize(vlen); return read_heap_obj_array(in, &(*pv)[0], vlen); } else pv->clear(); } // The following assumes that the vector contains actual objects. // This function is less efficient than others, but it has to be // used sometimes if one wants to have a vector of objects without // default constructors. // template inline void read_heap_obj_vector_as_placed(std::istream& in, std::vector* pv) { unsigned long vlen = 0UL; read_pod(in, &vlen); if (in.fail()) throw IOReadFailure( "In gs::read_heap_obj_vector_as_placed: input stream failure"); assert(pv); pv->clear(); if (vlen) { const ClassId id(in, 1); pv->reserve(vlen); for (unsigned long i=0; i obj(T::read(id, in)); pv->push_back(*obj); } } } // The following function is templated upon the reader factory template inline void read_base_obj_vector( std::istream& in, const Reader& f, std::vector >* pv) { unsigned long vlen = 0UL; read_pod(in, &vlen); if (in.fail()) throw IOReadFailure( "In gs::read_base_obj_vector: input stream failure"); assert(pv); if (vlen) { pv->resize(vlen); read_base_obj_array(in, f, &(*pv)[0], vlen); } else pv->clear(); } } #endif // GENERS_BINARYIO_HH_