/*////////////////////////////////////////////////////////////////////////////// // CMT Cosmic Muon Tomography project ////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova All rights reserved Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it > ------------------------------------------------------------------ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. //////////////////////////////////////////////////////////////////////////////*/ #ifndef U_SERIALIZABLE_H #define U_SERIALIZABLE_H /* Serialization: TODO: * Problema nella serializzazione delle properties in test_archive * implementare human readable make_hrp ... non riesco.. */ #include #include #include #include #include // #include // #include // #include // #include // #include "boost/archive/polymorphic_iarchive.hpp" // #include "boost/archive/polymorphic_oarchive.hpp" #include #include #include #include #include #include "Core/Archives.h" #include "Core/Export.h" #include "Core/Mpl.h" //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // BOOST SERIALIZATION ADD-ON namespace boost { namespace serialization { // ACCESS 2 // template struct access2 {}; template class hrp : public boost::serialization::wrapper_traits> { const char *m_name; const char *m_units; T &m_value; bool m_has_range; T m_min, m_max; bool m_has_default; T m_default; public: explicit hrp(const char *name_, T &t, const char* units_ = nullptr) : m_name(name_), m_units(units_), m_value(t), m_has_range(false), m_has_default(false) {} hrp& range(const T& min_val, const T& max_val) { m_min = min_val; m_max = max_val; m_has_range = true; return *this; } hrp& set_default(const T& def_val) { m_default = def_val; m_has_default = true; return *this; } const char *name() const { return this->m_name; } const char *units() const { return this->m_units; } T &value() { return this->m_value; } const T &const_value() const { return this->m_value; } bool has_range() const { return m_has_range; } const T& min_val() const { return m_min; } const T& max_val() const { return m_max; } bool has_default() const { return m_has_default; } const T& default_val() const { return m_default; } static constexpr bool is_read_only() { return false; } BOOST_SERIALIZATION_SPLIT_MEMBER() template void save(Archivex &ar, const unsigned int /* version */) const { ar << boost::serialization::make_nvp(m_name, m_value); } template void load(Archivex &ar, const unsigned int /* version */) { ar >> boost::serialization::make_nvp(m_name, m_value); } }; template class hrp_enum : public boost::serialization::wrapper_traits> { const char *m_name; const char *m_units; T &m_value; std::vector m_labels; bool m_has_default; T m_default; public: explicit hrp_enum(const char *name_, T &t, const std::vector& labels, const char* units_ = nullptr) : m_name(name_), m_units(units_), m_value(t), m_labels(labels), m_has_default(false) {} hrp_enum& set_default(const T& def_val) { m_default = def_val; m_has_default = true; return *this; } const char *name() const { return this->m_name; } const char *units() const { return this->m_units; } T &value() { return this->m_value; } const std::vector& labels() const { return m_labels; } bool has_default() const { return m_has_default; } const T& default_val() const { return m_default; } static constexpr bool is_read_only() { return false; } BOOST_SERIALIZATION_SPLIT_MEMBER() template void save(Archivex &ar, const unsigned int /* version */) const { ar << boost::serialization::make_nvp(m_name, m_value); } template void load(Archivex &ar, const unsigned int /* version */) { ar >> boost::serialization::make_nvp(m_name, m_value); } }; template class hrp_val : public boost::serialization::wrapper_traits> { const char *m_name; const char *m_units; T m_value; bool m_has_range; T m_min, m_max; bool m_has_default; T m_default; public: explicit hrp_val(const char *name_, T t, const char* units_ = nullptr) : m_name(name_), m_units(units_), m_value(t), m_has_range(false), m_has_default(false) {} hrp_val& range(const T& min_val, const T& max_val) { m_min = min_val; m_max = max_val; m_has_range = true; return *this; } hrp_val& set_default(const T& def_val) { m_default = def_val; m_has_default = true; return *this; } const char *name() const { return this->m_name; } const char *units() const { return this->m_units; } T &value() { return this->m_value; } const T &const_value() const { return this->m_value; } bool has_range() const { return m_has_range; } const T& min_val() const { return m_min; } const T& max_val() const { return m_max; } bool has_default() const { return m_has_default; } const T& default_val() const { return m_default; } static constexpr bool is_read_only() { return true; } BOOST_SERIALIZATION_SPLIT_MEMBER() template void save(Archivex &ar, const unsigned int /* version */) const { ar << boost::serialization::make_nvp(m_name, m_value); } template void load(Archivex &ar, const unsigned int /* version */) { // Only for output archives } }; template class hrp_enum_val : public boost::serialization::wrapper_traits> { const char *m_name; const char *m_units; T m_value; std::vector m_labels; bool m_has_default; T m_default; public: explicit hrp_enum_val(const char *name_, T t, const std::vector& labels, const char* units_ = nullptr) : m_name(name_), m_units(units_), m_value(t), m_labels(labels), m_has_default(false) {} hrp_enum_val& set_default(const T& def_val) { m_default = def_val; m_has_default = true; return *this; } const char *name() const { return this->m_name; } const char *units() const { return this->m_units; } T &value() { return this->m_value; } const std::vector& labels() const { return m_labels; } bool has_default() const { return m_has_default; } const T& default_val() const { return m_default; } static constexpr bool is_read_only() { return true; } BOOST_SERIALIZATION_SPLIT_MEMBER() template void save(Archivex &ar, const unsigned int /* version */) const { ar << boost::serialization::make_nvp(m_name, m_value); } template void load(Archivex &ar, const unsigned int /* version */) { // Only for output archives } }; template inline hrp make_hrp(const char *name, T &t, const char* units = nullptr) { return hrp(name, t, units); } // Specialization for rvalues (value-based storage) template inline hrp_val make_hrp(const char *name, T &&t, const char* units = nullptr) { return hrp_val(name, t, units); } template inline hrp_enum make_hrp_enum(const char *name, T &t, const std::vector& labels, const char* units = nullptr) { return hrp_enum(name, t, labels, units); } // Specialization for rvalues (value-based storage) template inline hrp_enum_val make_hrp_enum(const char *name, T &&t, const std::vector& labels, const char* units = nullptr) { return hrp_enum_val(name, t, labels, units); } template inline hrp make_nvp(const char *name, T &t, const char* units) { return hrp(name, t, units); } // Specialization for rvalues (value-based storage) template inline hrp_val make_nvp(const char *name, T &&t, const char* units) { return hrp_val(name, t, units); } } // namespace serialization } // namespace boost //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // ULIB SERIALIZATION namespace uLib { #define _AR_OP(r, data, elem) data &BOOST_SERIALIZATION_BASE_OBJECT_NVP(elem); // NAME VALUE PAIR // #define NVP_GET_MACRO(_1, _2, _3, NAME, ...) NAME #define NVP(...) NVP_GET_MACRO(__VA_ARGS__, NVP3, NVP2, NVP1)(__VA_ARGS__) #define NVP1(data) BOOST_SERIALIZATION_NVP(data) #define NVP2(name, data) boost::serialization::make_nvp(name, data) #define NVP3(name, data, units) boost::serialization::make_nvp(name, data, units) // HUMAN READABLE PROPERTY // #define HRP_GET_MACRO(_1, _2, _3, _4, _5, _6, NAME, ...) NAME #define HRP(...) HRP_GET_MACRO(__VA_ARGS__, HRP6, HRP5, HRP4, HRP3, HRP2, HRP1)(__VA_ARGS__) #define HRP1(data) boost::serialization::make_hrp(BOOST_PP_STRINGIZE(data), data) #define HRP2(name, data) boost::serialization::make_hrp(name, data) #define HRP3(name, data, units) boost::serialization::make_hrp(name, data, units) #define HRP4(name, data, units, default) boost::serialization::make_hrp(name, data, units).set_default(default) #define HRP5(name, data, units, min, max) boost::serialization::make_hrp(name, data, units).range(min, max) #define HRP6(name, data, units, default, min, max) boost::serialization::make_hrp(name, data, units).set_default(default).range(min, max) #define HRPE(name, data, labels) boost::serialization::make_hrp_enum(name, data, labels) // LEFT FOR BACKWARD COMPATIBILITY #define HRPU(name, units) boost::serialization::make_hrp(BOOST_PP_STRINGIZE(name), name, units) namespace serialization { using boost::serialization::make_nvp; using boost::serialization::make_hrp; using boost::serialization::make_hrp_enum; } // serialization //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // SERIALIZTION MACROS // // !!! WARNING !!! INTRUSIVE SERIALIZATION IS ACTUALLY NOT WORKING FEATURE // SO LEAVE ULIB_CFG_INTRUSIVE_SERIALIZATION NOT DEFINED #ifdef ULIB_CFG_INTRUSIVE_SERIALIZATION_OBJECT #define ULIB_SERIALIZABLE_OBJECT _ULIB_DETAIL_INTRUSIVE_SERIALIZABLE_OBJECT #define ULIB_SERIALIZE_OBJECT(_Ob, ...) \ _ULIB_DETAIL_INTRUSIVE_SERIALIZE_OBJECT(_Ob, __VA_ARGS__) #define _AR_(_name) _ULIB_DETAIL_INTRUSIVE_AR_(_name) #else #define ULIB_SERIALIZABLE(_Ob) \ _ULIB_DETAIL_UNINTRUSIVE_SERIALIZABLE(_Ob) \ ULIB_CLASS_EXPORT_KEY(_Ob) #define ULIB_SERIALIZE(_Ob, ...) _ULIB_DETAIL_UNINTRUSIVE_SERIALIZE(_Ob) #define ULIB_SERIALIZE_DERIVED(_Ob, ...) \ _ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_DERIVED(_Ob, __VA_ARGS__) #define ULIB_SERIALIZABLE_OBJECT(_Ob) \ _ULIB_DETAIL_UNINTRUSIVE_SERIALIZABLE_OBJECT(_Ob) \ ULIB_CLASS_EXPORT_OBJECT_KEY(_Ob) #define ULIB_SERIALIZE_OBJECT(_Ob, ...) \ _ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_OBJECT(_Ob, __VA_ARGS__) #define AR(_name) _ULIB_DETAIL_UNINTRUSIVE_AR_(_name) #define HR(_name) _ULIB_DETAIL_UNINTRUSIVE_HR_(_name) #endif #define ULIB_SERIALIZE_ACCESS \ friend class boost::serialization::access; \ template friend class boost::serialization::access2; #define ULIB_CLASS_EXPORT_KEY(_FullNamespaceClass) \ BOOST_CLASS_EXPORT_KEY(_FullNamespaceClass) #define ULIB_CLASS_EXPORT_OBJECT_KEY(_FullNamespaceClass) \ BOOST_CLASS_EXPORT_KEY(_FullNamespaceClass) #define _SERIALIZE_IMPL_SEQ \ (uLib::Archive::text_iarchive) \ (uLib::Archive::text_oarchive) \ (uLib::Archive::hrt_iarchive) \ (uLib::Archive::hrt_oarchive) \ (uLib::Archive::xml_iarchive) \ (uLib::Archive::xml_oarchive) \ (uLib::Archive::log_archive) /** Solving virtual class check problem */ #define _ULIB_DETAIL_SPECIALIZE_IS_VIRTUAL_BASE(_Base, _Derived) \ namespace boost { \ template <> \ struct is_virtual_base_of<_Base, _Derived> : public boost::mpl::true_ {}; \ } #define _ULIB_DETAIL_SPECIALIZE_IS_VIRTUAL_BASE_OP(r, data, elem) \ _ULIB_DETAIL_SPECIALIZE_IS_VIRTUAL_BASE(elem, data) //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // INTRUSIVE SERIALIZATION ( NOT WORKING YET !! ) // #define _ULIB_DETAIL_INTRUSIVE_AR_(name) ar &BOOST_SERIALIZATION_NVP(name); #define _ULIB_DETAIL_INTRUSIVE_SERIALIZE_FUNC(Class, Archive) \ template void Class::serialize(Archive &ar, const unsigned int); #define _ULIB_DETAIL_INTRUSIVE_SERIALIZE_FUNC_OP(r, data, elem) \ _ULIB_DETAIL_INTRUSIVE_SERIALIZE_FUNC(data, elem); #define _ULIB_DETAIL_INTRUSIVE_SERIALIZABLE_OBJECT \ typedef boost::mpl::bool_ serializable; \ typedef boost::mpl::remove_if::type \ SerilizableTypeList; \ void PrintSerializableListId() { \ boost::mpl::for_each(PrintTypeId()); \ } \ template \ void serialize(ArchiveT &ar, const unsigned int version); \ template \ void serialize_parents(ArchiveT &ar, const unsigned int version); \ template \ void save_override(ArchiveT &ar, const unsigned int version); #define _ULIB_DETAIL_INTRUSIVE_SERIALIZE_OBJECT(_Ob, ...) \ template \ void _Ob::serialize(ArchiveT &ar, const unsigned int version) { \ boost::serialization::void_cast_register<_Ob, _Ob::BaseClass>( \ static_cast<_Ob *>(NULL), static_cast<_Ob::BaseClass *>(NULL)); \ _Ob::serialize_parents(ar, version); \ _Ob::save_override(ar, version); \ } \ template \ void _Ob::serialize_parents(ArchiveT &ar, const unsigned int v) { \ BOOST_PP_SEQ_FOR_EACH(_AR_OP, ar, BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))); \ } \ BOOST_PP_SEQ_FOR_EACH(_ULIB_DETAIL_INTRUSIVE_SERIALIZE_FUNC_OP, _Ob, \ _SERIALIZE_IMPL_SEQ) \ BOOST_PP_SEQ_FOR_EACH(_ULIB_DETAIL_SPECIALIZE_IS_VIRTUAL_BASE_OP, _Ob, \ BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))) \ ULIB_CLASS_EXPORT_IMPLEMENT(_Ob) \ namespace boost { \ namespace serialization { \ template \ inline void load_construct_data(ArchiveT &ar, _Ob *o, \ const unsigned int file_version) { \ ::new (o) _Ob(); \ o->init_parameters(); \ } \ } \ } \ template \ void _Ob::save_override(ArchiveT &ar, const unsigned int version) //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // UNINTRUSIVE SERIALIZATION #define _UNAR_OP(r, data, elem) \ ar &boost::serialization::make_nvp( \ BOOST_PP_STRINGIZE(elem), boost::serialization::base_object(ob)); #define _ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_FUNC(Class, Archive) \ template void boost::serialization::serialize(Archive &ar, Class &ob, \ const unsigned int i); #define _ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_FUNC_OP(r, data, elem) \ _ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_FUNC(data, elem) // NOTE: becouse of BOOST_PP_VARIADIC_SIZE issue of some boost macro has two // different implementation #define _ULIB_DETAIL_UNINTRUSIVE_SERIALIZABLE(_Ob) \ namespace boost { \ namespace serialization { \ template \ void serialize(ArchiveT &ar, _Ob &ob, const unsigned int version); \ template \ void serialize_parents(ArchiveT &ar, _Ob &ob, const unsigned int version); \ template <> struct access2<_Ob> { \ template \ static void save_override(ArchiveT &ar, _Ob &ob, \ const unsigned int version); \ }; \ } \ } #define _ULIB_DETAIL_UNINTRUSIVE_SERIALIZE(_Ob) \ namespace boost { \ namespace serialization { \ template \ void serialize_parents(ArchiveT &ar, _Ob &ob, const unsigned int v) {} \ template \ void serialize(ArchiveT &ar, _Ob &ob, const unsigned int version) { \ serialize_parents(ar, ob, version); \ access2<_Ob>::save_override(ar, ob, version); \ } \ } \ } \ ULIB_CLASS_EXPORT_IMPLEMENT(_Ob) \ BOOST_PP_SEQ_FOR_EACH(_ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_FUNC_OP, _Ob, \ _SERIALIZE_IMPL_SEQ) \ template \ void boost::serialization::access2<_Ob>::save_override( \ ArchiveT &ar, _Ob &ob, const unsigned int version) #define _ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_DERIVED(_Ob, ...) \ namespace boost { \ namespace serialization { \ template \ void serialize_parents(ArchiveT &ar, _Ob &ob, const unsigned int v) { \ BOOST_PP_IF(BOOST_PP_VARIADIC_SIZE((__VA_ARGS__)), \ BOOST_PP_SEQ_FOR_EACH(_UNAR_OP, ob, \ BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))); \ , ) \ } \ template \ void serialize(ArchiveT &ar, _Ob &ob, const unsigned int version) { \ serialize_parents(ar, ob, version); \ access2<_Ob>::save_override(ar, ob, version); \ } \ } \ } \ ULIB_CLASS_EXPORT_IMPLEMENT(_Ob) \ BOOST_PP_SEQ_FOR_EACH(_ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_FUNC_OP, _Ob, \ _SERIALIZE_IMPL_SEQ) \ BOOST_PP_SEQ_FOR_EACH(_ULIB_DETAIL_SPECIALIZE_IS_VIRTUAL_BASE_OP, _Ob, \ BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))) \ template \ void boost::serialization::access2<_Ob>::save_override( \ ArchiveT &ar, _Ob &ob, const unsigned int version) #define _ULIB_DETAIL_UNINTRUSIVE_SERIALIZABLE_OBJECT(_Ob) \ namespace boost { \ namespace serialization { \ template \ void serialize(ArchiveT &ar, _Ob &ob, const unsigned int version); \ template \ void serialize_parents(ArchiveT &ar, _Ob &ob, const unsigned int version); \ template <> struct access2<_Ob> { \ template \ static void save_override(ArchiveT &ar, _Ob &ob, \ const unsigned int version); \ }; \ } \ } #define _ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_OBJECT(_Ob, ...) \ namespace boost { \ namespace serialization { \ template \ void serialize_parents(ArchiveT &ar, _Ob &ob, const unsigned int v) { \ /* PP serialize */ BOOST_PP_SEQ_FOR_EACH( \ _UNAR_OP, ob, BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))); \ /* MPL serialize */ /*uLib::mpl::for_each<_Ob::BaseList> \ (uLib::detail::Serializable::serialize_baseobject<_Ob,ArchiveT>(ob,ar) );*/ }\ template \ inline void load_construct_data(ArchiveT &ar, _Ob *ob, \ const unsigned int file_version) { \ ::new (ob) _Ob(); \ } \ template \ void serialize(ArchiveT &ar, _Ob &ob, const unsigned int version) { \ void_cast_register<_Ob, _Ob::BaseClass>( \ static_cast<_Ob *>(NULL), \ static_cast<_Ob::BaseClass *>(NULL)); /*fix*/ \ serialize_parents(ar, ob, version); \ access2<_Ob>::save_override(ar, ob, version); \ } \ } \ } \ ULIB_CLASS_EXPORT_IMPLEMENT(_Ob) \ BOOST_PP_SEQ_FOR_EACH(_ULIB_DETAIL_SPECIALIZE_IS_VIRTUAL_BASE_OP, _Ob, \ BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))) \ BOOST_PP_SEQ_FOR_EACH(_ULIB_DETAIL_UNINTRUSIVE_SERIALIZE_FUNC_OP, _Ob, \ _SERIALIZE_IMPL_SEQ) \ template \ void boost::serialization::access2<_Ob>::save_override( \ ArchiveT &ar, _Ob &ob, const unsigned int version) #define _ULIB_DETAIL_UNINTRUSIVE_AR_(name) \ boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), ob.name) #define _ULIB_DETAIL_UNINTRUSIVE_HR_(name) \ boost::serialization::make_hrp(BOOST_PP_STRINGIZE(name), ob.name) //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// namespace detail { struct Serializable { /** * Serializable trait to check if an object type is serializable. * This only works if UNINTRUSIVE SERIALIZATION is applyed; in intrusive * cases a has_serialize trait should be implemented */ template struct serializable_trait : mpl::bool_ {}; /** * IsA Serializable Implementation Template */ template struct IsA : serializable_trait {}; template struct serialize_baseobject { ThisClass &m_object; Archive &m_ar; serialize_baseobject(ThisClass &o, Archive &ar) : m_object(o), m_ar(ar) {} template void operator()(T &o) { m_ar &boost::serialization::make_nvp( typeid(T).name(), boost::serialization::base_object(m_object)); } }; }; } // namespace detail struct Serializable { friend class boost::serialization::access; template friend class boost::serialization::access2; virtual ~Serializable() {} protected: }; } // namespace uLib #endif // U_SERIALIZABLE_H