/*****************************************************************************/ /** * \file portable_binary_iarchive.hpp * \brief Provides an archive to read from portable binary files. * \author christian.pfligersdorffer@eos.info * \version 1.0 * * This archive (pair) brings the advantanges of binary streams to the cross * platform boost::serialization user. While being almost as fast as the native * binary archive it allows its files to be exchanged between cpu architectures * using different byte order (endianness). Speaking of speed: in serializing * numbers the (portable) binary approach is approximately ten times faster than * the ascii implementation. * * Based on the portable archive example by Robert Ramey this implementation * uses Beman Dawes endian library and fp_utilities from Johan Rade which both * have applied but have not yet been accepted into the boost libraries. So you * need to add them to your boost directory manually. * * \note Correct behaviour has been confirmed using PowerPC-32 and x86-32 * platforms featuring big endian and little endian byte order. It might * or might not instantly work for your specific setup. If you encounter * problems or have suggestions please contact the author. * * \copyright The boost software license applies. */ /*****************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include /** * Exception being thrown when an incompatible integer size is encountered. * * Note that it will also be thrown if you mixed up your stream position and * accidentially interpret some value for size data (in this case invalid_size * will be more than one digit most of the time). */ class portable_binary_archive_exception : public boost::archive::archive_exception { public: portable_binary_archive_exception(unsigned int invalid_size) : boost::archive::archive_exception(other_exception) , msg("requested integer size exceeds type size: ") { msg += boost::lexical_cast(invalid_size); } virtual const char* what() { return msg.c_str(); } private: std::string msg; }; /** * Portable binary input archive using little endian format. * * This archive addresses integer size, endianness and floating point types so * that data can be transferred across different systems. There may still be * constraints as to what systems are compatible and the user will have to take * care that e.g. a very large int being saved on a 64 bit machine will result * in a portable_binary_archive_exception if loaded into an int on a 32 bit * system. A possible workaround to this would be to use fixed types like * boost::uint64_t in your serialization structures. * * \note The class is based on the portable binary example by Robert Ramey and * uses Beman Dawes endian library plus fp_utilities by Johan Rade. */ class portable_binary_iarchive : // don't derive from binary_iarchive !!! public boost::archive::binary_iarchive_impl< portable_binary_iarchive #if BOOST_VERSION >= 103400 , std::istream::char_type , std::istream::traits_type #endif > { // base class typedef typedef boost::archive::binary_iarchive_impl< portable_binary_iarchive #if BOOST_VERSION >= 103400 , std::istream::char_type , std::istream::traits_type #endif > archive_base_t; // binary primitive typedef typedef boost::archive::basic_binary_iprimitive< portable_binary_iarchive #if BOOST_VERSION < 103400 , std::istream #else , std::ostream::char_type , std::ostream::traits_type #endif > primitive_base_t; // This typedef typedef portable_binary_iarchive derived_t; #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS public: #else friend archive_base_t; // needed for static polymorphism friend primitive_base_t; // since with override load below friend class boost::archive::detail::polymorphic_iarchive_impl; friend class boost::archive::basic_binary_iarchive; friend class boost::archive::load_access; #endif // workaround for gcc: use a dummy struct // as additional argument type for overloading template struct dummy { dummy(int) {}}; //! default fall through for non-arithmetic types (ie. strings) template BOOST_DEDUCED_TYPENAME boost::disable_if >::type load(T & t, dummy<1> = 0) { archive_base_t::load(t); } //! special case loading bool type, preserving compatibility //! to integer types - this is somewhat redundant but simply //! treating bool as integer type generates some warnings void load(bool& b) { char c; archive_base_t::load(c); // size archive_base_t::load(c); // value b = (c != 0); } /** * load integer types * * First we load the size information ie. the number of bytes that * hold the actual data. Then we retrieve the data and transform it * to the original value by using load_little_endian. */ template BOOST_DEDUCED_TYPENAME boost::enable_if >::type load(T & t, dummy<2> = 0) { // get the number of bytes following char size; archive_base_t::load(size); if (size > sizeof(T)) throw portable_binary_archive_exception(size); // temporary holder of the value T temp = 0; load_binary(&temp, size); // load the value from little endian - is is then converted // to the target type T and fits it because size <= sizeof(T) t = boost::detail::load_little_endian(&temp); } /** * load floating point types * * We simply rely on fp_traits to set the bit pattern from the * (unsigned) integral type that was stored in the stream. * * \todo treat nan values using fp_classify */ template BOOST_DEDUCED_TYPENAME boost::enable_if >::type load(T & t, dummy<3> = 0) { using namespace boost::math::detail; BOOST_DEDUCED_TYPENAME fp_traits::type::bits bits; load(bits); fp_traits::type::set_bits(t, bits); } public: //! always construct on a stream using std::ios::binary mode! portable_binary_iarchive(std::istream & is, unsigned flags = 0) : archive_base_t(is, flags | boost::archive::no_header) {} }; #include #include #include namespace boost { namespace archive { // explicitly instantiate for this type of binary stream template class basic_binary_iarchive ; template class basic_binary_iprimitive< portable_binary_iarchive #if BOOST_VERSION < 103400 , std::istream #else , std::istream::char_type , std::istream::traits_type #endif > ; template class binary_iarchive_impl< portable_binary_iarchive #if BOOST_VERSION >= 103400 , std::istream::char_type , std::istream::traits_type #endif >; template class detail::archive_pointer_iserializer ; } // namespace archive } // namespace boost #define BOOST_ARCHIVE_CUSTOM_IARCHIVE_TYPES portable_binary_iarchive // polymorphic portable binary iarchive typdef typedef boost::archive::detail::polymorphic_iarchive_impl< portable_binary_iarchive> polymorphic_portable_binary_iarchive;