/*! * Copyright (c) 2015 by Contributors * \file serializer.h * \brief serializer template class that helps serialization. * This file do not need to be directly used by most user. */ #ifndef DMLC_SERIALIZER_H_ #define DMLC_SERIALIZER_H_ #include #include #include #include #include #include #include #include "./base.h" #include "./io.h" #include "./logging.h" #include "./type_traits.h" #if DMLC_USE_CXX11 #include #include #endif namespace dmlc { /*! \brief internal namespace for serializers */ namespace serializer { /*! * \brief generic serialization handler * \tparam T the type to be serialized */ template struct Handler; //! \cond Doxygen_Suppress /*! * \brief Serializer that redirect calls by condition * \tparam cond the condition * \tparam Then the serializer used for then condition * \tparam Else the serializer used for else condition * \tparam Return the type of data the serializer handles */ template struct IfThenElse; template struct IfThenElse { inline static void Write(Stream *strm, const T &data) { Then::Write(strm, data); } inline static bool Read(Stream *strm, T *data) { return Then::Read(strm, data); } }; template struct IfThenElse { inline static void Write(Stream *strm, const T &data) { Else::Write(strm, data); } inline static bool Read(Stream *strm, T *data) { return Else::Read(strm, data); } }; /*! \brief Serializer for POD(plain-old-data) data */ template struct PODHandler { inline static void Write(Stream *strm, const T &data) { strm->Write(&data, sizeof(T)); } inline static bool Read(Stream *strm, T *dptr) { return strm->Read((void*)dptr, sizeof(T)) == sizeof(T); // NOLINT(*) } }; // serializer for class that have save/load function template struct SaveLoadClassHandler { inline static void Write(Stream *strm, const T &data) { data.Save(strm); } inline static bool Read(Stream *strm, T *data) { return data->Load(strm); } }; /*! * \brief dummy class for undefined serialization. * This is used to generate error message when user tries to * serialize something that is not supported. * \tparam T the type to be serialized */ template struct UndefinedSerializerFor { }; /*! * \brief Serializer handler for std::vector where T is POD type. * \tparam T element type */ template struct PODVectorHandler { inline static void Write(Stream *strm, const std::vector &vec) { uint64_t sz = static_cast(vec.size()); strm->Write(&sz, sizeof(sz)); if (sz != 0) { strm->Write(&vec[0], sizeof(T) * vec.size()); } } inline static bool Read(Stream *strm, std::vector *out_vec) { uint64_t sz; if (strm->Read(&sz, sizeof(sz)) != sizeof(sz)) return false; size_t size = static_cast(sz); out_vec->resize(size); if (sz != 0) { size_t nbytes = sizeof(T) * size; return strm->Read(&(*out_vec)[0], nbytes) == nbytes; } return true; } }; /*! * \brief Serializer handler for std::vector where T can be composed type * \tparam T element type */ template struct ComposeVectorHandler { inline static void Write(Stream *strm, const std::vector &vec) { uint64_t sz = static_cast(vec.size()); strm->Write(&sz, sizeof(sz)); for (size_t i = 0; i < vec.size(); ++i) { Handler::Write(strm, vec[i]); } } inline static bool Read(Stream *strm, std::vector *out_vec) { uint64_t sz; if (strm->Read(&sz, sizeof(sz)) != sizeof(sz)) return false; size_t size = static_cast(sz); out_vec->resize(size); for (size_t i = 0; i < size; ++i) { if (!Handler::Read(strm, &(*out_vec)[i])) return false; } return true; } }; /*! * \brief Serializer handler for std::basic_string where T is POD type. * \tparam T element type */ template struct PODStringHandler { inline static void Write(Stream *strm, const std::basic_string &vec) { uint64_t sz = static_cast(vec.length()); strm->Write(&sz, sizeof(sz)); if (sz != 0) { strm->Write(&vec[0], sizeof(T) * vec.length()); } } inline static bool Read(Stream *strm, std::basic_string *out_vec) { uint64_t sz; if (strm->Read(&sz, sizeof(sz)) != sizeof(sz)) return false; size_t size = static_cast(sz); out_vec->resize(size); if (sz != 0) { size_t nbytes = sizeof(T) * size; return strm->Read(&(*out_vec)[0], nbytes) == nbytes; } return true; } }; /*! \brief Serializer for std::pair */ template struct PairHandler { inline static void Write(Stream *strm, const std::pair &data) { Handler::Write(strm, data.first); Handler::Write(strm, data.second); } inline static bool Read(Stream *strm, std::pair *data) { return Handler::Read(strm, &(data->first)) && Handler::Read(strm, &(data->second)); } }; // set type handler that can handle most collection type case template struct CollectionHandler { inline static void Write(Stream *strm, const ContainerType &data) { typedef typename ContainerType::value_type ElemType; // dump data to vector std::vector vdata(data.begin(), data.end()); // serialize the vector Handler >::Write(strm, vdata); } inline static bool Read(Stream *strm, ContainerType *data) { typedef typename ContainerType::value_type ElemType; std::vector vdata; if (!Handler >::Read(strm, &vdata)) return false; data->clear(); data->insert(vdata.begin(), vdata.end()); return true; } }; // handler that can handle most list type case // this type insert function takes additional iterator template struct ListHandler { inline static void Write(Stream *strm, const ListType &data) { typedef typename ListType::value_type ElemType; // dump data to vector std::vector vdata(data.begin(), data.end()); // serialize the vector Handler >::Write(strm, vdata); } inline static bool Read(Stream *strm, ListType *data) { typedef typename ListType::value_type ElemType; std::vector vdata; if (!Handler >::Read(strm, &vdata)) return false; data->clear(); data->insert(data->begin(), vdata.begin(), vdata.end()); return true; } }; //! \endcond /*! * \brief generic serialization handler for type T * * User can define specialization of this class to support * composite serialization of their own class. * * \tparam T the type to be serialized */ template struct Handler { /*! * \brief write data to stream * \param strm the stream we write the data. * \param data the data obeject to be serialized */ inline static void Write(Stream *strm, const T &data) { IfThenElse::value, PODHandler, IfThenElse::value, SaveLoadClassHandler, UndefinedSerializerFor, T>, T> ::Write(strm, data); } /*! * \brief read data to stream * \param strm the stream to read the data. * \param data the pointer to the data obeject to read * \return whether the read is successful */ inline static bool Read(Stream *strm, T *data) { return IfThenElse::value, PODHandler, IfThenElse::value, SaveLoadClassHandler, UndefinedSerializerFor, T>, T> ::Read(strm, data); } }; //! \cond Doxygen_Suppress template struct Handler > { inline static void Write(Stream *strm, const std::vector &data) { IfThenElse::value, PODVectorHandler, ComposeVectorHandler, std::vector > ::Write(strm, data); } inline static bool Read(Stream *strm, std::vector *data) { return IfThenElse::value, PODVectorHandler, ComposeVectorHandler, std::vector > ::Read(strm, data); } }; template struct Handler > { inline static void Write(Stream *strm, const std::basic_string &data) { IfThenElse::value, PODStringHandler, UndefinedSerializerFor, std::basic_string > ::Write(strm, data); } inline static bool Read(Stream *strm, std::basic_string *data) { return IfThenElse::value, PODStringHandler, UndefinedSerializerFor, std::basic_string > ::Read(strm, data); } }; template struct Handler > { inline static void Write(Stream *strm, const std::pair &data) { IfThenElse::value && dmlc::is_pod::value, PODHandler >, PairHandler, std::pair > ::Write(strm, data); } inline static bool Read(Stream *strm, std::pair *data) { return IfThenElse::value && dmlc::is_pod::value, PODHandler >, PairHandler, std::pair > ::Read(strm, data); } }; template struct Handler > : public CollectionHandler > { }; template struct Handler > : public CollectionHandler > { }; template struct Handler > : public CollectionHandler > { }; template struct Handler > : public CollectionHandler > { }; template struct Handler > : public ListHandler > { }; template struct Handler > : public ListHandler > { }; #if DMLC_USE_CXX11 template struct Handler > : public CollectionHandler > { }; template struct Handler > : public CollectionHandler > { }; template struct Handler > : public CollectionHandler > { }; template struct Handler > : public CollectionHandler > { }; #endif //! \endcond } // namespace serializer } // namespace dmlc #endif // DMLC_SERIALIZER_H_