Files
uLib/src/Core/Archives.h
AndreaRigoni 7f558f4f30 switch to Ninja+ccache, add clang/lld fast build profile
- CMakePresets.json: add 'fast' preset (clang+lld+ccache)
- .gitignore: generalize build/ to build*/, add CMakeUserPresets.json
- CMakeUserPresets.json: untrack (conan-generated, now gitignored)
- src/Core/Archives.h: remove redundant 'using basic_xml_iarchive::load_override'
  in xml_iarchive; caused ambiguous overload with clang (diamond inheritance)
- src/Core/Object.cpp: remove invalid explicit instantiations of non-template
  virtual Object::serialize (GCC extension, clang rejects)
- README.md, CLAUDE.md: document GCC and LLVM/clang build workflows

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 10:17:40 +00:00

724 lines
25 KiB
C++

/*//////////////////////////////////////////////////////////////////////////////
// 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_CORE_ARCHIVES_H
#define U_CORE_ARCHIVES_H
#include <boost/archive/detail/basic_pointer_iserializer.hpp>
#include <boost/archive/detail/basic_pointer_oserializer.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <cstring>
#include <iostream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/detail/register_archive.hpp>
#include <boost/archive/detail/polymorphic_iarchive_route.hpp>
#include <boost/archive/detail/polymorphic_oarchive_route.hpp>
#include <boost/archive/polymorphic_iarchive.hpp>
#include <boost/archive/polymorphic_oarchive.hpp>
#include <boost/archive/polymorphic_text_oarchive.hpp>
#include "StringReader.h"
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// FWD DECLARATIONS OF ARCHIVES //
namespace uLib {
namespace Archive {
class xml_iarchive;
class xml_oarchive;
class text_iarchive;
class text_oarchive;
class hrt_iarchive;
class hrt_oarchive;
class log_archive;
} // namespace Archive
} // namespace uLib
namespace boost {
namespace archive {
namespace detail {
template <class ArchiveImplementation> class polymorphic_oarchive_route;
template <class ArchiveImplementation> class polymorphic_iarchive_route;
} // namespace detail
} // namespace archive
} // namespace boost
namespace boost {
namespace serialization {
template <typename T> struct hrp;
template <typename T> struct hrp_val;
template <typename T> struct hrp_enum;
template <typename T> struct hrp_enum_val;
}
} // namespace boost
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// ARCHIVES REGISTRATION //
namespace uLib {
namespace Archive {
namespace detail {
struct adl_tag {};
} // namespace detail
} // namespace Archive
} // namespace uLib
namespace boost {
namespace archive {
namespace detail {
// This function gets called, but its only purpose is to participate
// in overload resolution with the functions declared by
// BOOST_SERIALIZATION_REGISTER_ARCHIVE, below.
template <class Serializable>
void instantiate_ptr_serialization(Serializable *, int,
uLib::Archive::detail::adl_tag) {}
} // namespace detail
} // namespace archive
} // namespace boost
// The function declaration generated by this macro never actually
// gets called, but its return type gets instantiated, and that's
// enough to cause registration of serialization functions between
// Archive and any exported Serializable type. See also:
// boost/serialization/export.hpp
#define ULIB_SERIALIZATION_REGISTER_ARCHIVE(_Archive) \
namespace boost { \
namespace archive { \
namespace detail { \
\
template <class Serializable> \
BOOST_DEDUCED_TYPENAME \
_ptr_serialization_support<_Archive, Serializable>::type \
instantiate_ptr_serialization(Serializable *, _Archive *, \
uLib::Archive::detail::adl_tag); \
} \
} \
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// ARCHIVES IO INTERFACES //
namespace boost {
namespace archive {
namespace detail {
/**
* Custom implementation of boost interface_iarchive to add new operators
*/
template <class Archive> class uLib_interface_iarchive {
protected:
uLib_interface_iarchive() {};
public:
/////////////////////////////////////////////////////////
// archive public interface
typedef mpl::bool_<true> is_loading;
typedef mpl::bool_<false> is_saving;
// return a pointer to the most derived class
Archive *This() { return static_cast<Archive *>(this); }
template <class T>
const basic_pointer_iserializer *register_type(T * = nullptr) {
const basic_pointer_iserializer &bpis = boost::serialization::singleton<
pointer_iserializer<Archive, T>>::get_const_instance();
this->This()->register_basic_serializer(bpis.get_basic_serializer());
return &bpis;
}
template <class T> Archive &operator>>(T &t) {
this->This()->load_override(t);
return *this->This();
}
template <class T>
Archive &operator>>(const boost::serialization::nvp<T> &t) {
this->This()->load_override(t);
return *this->This();
}
template <class T>
Archive &operator>>(const boost::serialization::hrp<T> &t) {
this->This()->load_override(const_cast<boost::serialization::hrp<T> &>(t));
return *this->This();
}
template <class T>
Archive &operator>>(const boost::serialization::hrp_val<T> &t) {
this->This()->load_override(const_cast<boost::serialization::hrp_val<T> &>(t));
return *this->This();
}
template <class T>
Archive &operator>>(const boost::serialization::hrp_enum<T> &t) {
this->This()->load_override(const_cast<boost::serialization::hrp_enum<T> &>(t));
return *this->This();
}
template <class T>
Archive &operator>>(const boost::serialization::hrp_enum_val<T> &t) {
this->This()->load_override(const_cast<boost::serialization::hrp_enum_val<T> &>(t));
return *this->This();
}
// the & operator
template <class T> Archive &operator&(T &t) { return *(this->This()) >> t; }
template <class T>
Archive &operator&(const boost::serialization::nvp<T> &t) {
return *(this->This()) >> t;
}
template <class T>
Archive &operator&(const boost::serialization::hrp<T> &t) {
return *(this->This()) >> t;
}
template <class T>
Archive &operator&(const boost::serialization::hrp_val<T> &t) {
return *(this->This()) >> t;
}
template <class T>
Archive &operator&(const boost::serialization::hrp_enum<T> &t) {
return *(this->This()) >> t;
}
template <class T>
Archive &operator&(const boost::serialization::hrp_enum_val<T> &t) {
return *(this->This()) >> t;
}
// the == operator
template <class T> Archive &operator==(T &t) { return this->operator&(t); }
// the != operator for human readable access
template <class T> Archive &operator!=(T &t) {
return *this->This();
}
};
/**
* Custom implementation of boost interface_oarchive to add new operators
*/
template <class Archive> class uLib_interface_oarchive {
protected:
uLib_interface_oarchive() {};
public:
/////////////////////////////////////////////////////////
// archive public interface
typedef mpl::bool_<false> is_loading;
typedef mpl::bool_<true> is_saving;
// return a pointer to the most derived class
Archive *This() { return static_cast<Archive *>(this); }
template <class T>
const basic_pointer_oserializer *register_type(const T * = nullptr) {
const basic_pointer_oserializer &bpos = boost::serialization::singleton<
pointer_oserializer<Archive, T>>::get_const_instance();
this->This()->register_basic_serializer(bpos.get_basic_serializer());
return &bpos;
}
template <class T> Archive &operator<<(const T &t) {
// to get access you must redefine save_override by typing
// "using save_override" in archive impl
this->This()->save_override(t);
return *this->This();
}
template <class T> Archive &operator<<(const boost::serialization::hrp<T> &t) {
this->This()->save_override(t);
return *this->This();
}
template <class T> Archive &operator<<(const boost::serialization::hrp_val<T> &t) {
this->This()->save_override(t);
return *this->This();
}
template <class T> Archive &operator<<(const boost::serialization::hrp_enum<T> &t) {
this->This()->save_override(t);
return *this->This();
}
template <class T> Archive &operator<<(const boost::serialization::hrp_enum_val<T> &t) {
this->This()->save_override(t);
return *this->This();
}
template <class T> Archive &operator<<(const boost::serialization::nvp<T> &t) {
this->This()->save_override(t);
return *this->This();
}
// the & operator
template <class T> Archive &operator&(const T &t) {
return *this->This() << t;
}
template <class T>
Archive &operator&(const boost::serialization::hrp<T> &t) {
return *this->This() << t;
}
template <class T>
Archive &operator&(const boost::serialization::hrp_val<T> &t) {
return *this->This() << t;
}
template <class T>
Archive &operator&(const boost::serialization::hrp_enum<T> &t) {
return *this->This() << t;
}
template <class T>
Archive &operator&(const boost::serialization::hrp_enum_val<T> &t) {
return *this->This() << t;
}
template <class T>
Archive &operator&(const boost::serialization::nvp<T> &t) {
return *this->This() << t;
}
// the == operator
template <class T> Archive &operator==(T &t) { return this->operator&(t); }
// the != operator for human readable access
template <class T> Archive &operator!=(T &t) {
return *this->This();
}
};
// DECLARE INTERFACE SPECIALIZATIONS ///////////////////////////////////////////
// With this declarations all uLib archive Implementation will use their own
// extended interface //
template <>
class interface_iarchive<uLib::Archive::xml_iarchive>
: public uLib_interface_iarchive<uLib::Archive::xml_iarchive> {};
template <>
class interface_oarchive<uLib::Archive::xml_oarchive>
: public uLib_interface_oarchive<uLib::Archive::xml_oarchive> {};
template <>
class interface_iarchive<uLib::Archive::text_iarchive>
: public uLib_interface_iarchive<uLib::Archive::text_iarchive> {};
template <>
class interface_oarchive<uLib::Archive::text_oarchive>
: public uLib_interface_oarchive<uLib::Archive::text_oarchive> {};
template <>
class interface_iarchive<uLib::Archive::hrt_iarchive>
: public uLib_interface_iarchive<uLib::Archive::hrt_iarchive> {};
template <>
class interface_oarchive<uLib::Archive::hrt_oarchive>
: public uLib_interface_oarchive<uLib::Archive::hrt_oarchive> {};
template <>
class interface_iarchive<uLib::Archive::log_archive>
: public uLib_interface_iarchive<uLib::Archive::log_archive> {};
template <>
class interface_oarchive<uLib::Archive::log_archive>
: public uLib_interface_oarchive<uLib::Archive::log_archive> {};
} // namespace detail
} // namespace archive
} // namespace boost
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// ARCHIVES DEFINITIONS //
namespace boost {
namespace archive {
} // namespace archive
} // namespace boost
namespace uLib {
namespace Archive {
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// XML //
// ULIB_SERIALIZATION_VERSION should be get from the build system
#ifndef ULIB_SERIALIZATION_VERSION
#define ULIB_SERIALIZATION_VERSION "0.0"
#endif
class xml_iarchive : public boost::archive::xml_iarchive_impl<xml_iarchive> {
typedef xml_iarchive Archive;
typedef boost::archive::xml_iarchive_impl<Archive> base;
unsigned int m_flags;
// give serialization implementation access to this class
friend class boost::archive::detail::interface_iarchive<Archive>;
friend class boost::archive::basic_xml_iarchive<Archive>;
friend class boost::archive::load_access;
public:
xml_iarchive(std::istream &is, unsigned int flags = 0)
: boost::archive::xml_iarchive_impl<xml_iarchive>(
is, flags | boost::archive::no_header), m_flags(flags) {
if (0 == (flags & boost::archive::no_header)) {
std::string line;
std::getline(is, line); // <?xml ... ?>
std::getline(is, line); // <!DOCTYPE ...>
std::getline(is, line); // <ulib_serialization ...>
}
}
// Anything not an attribute should be a name value pair as nvp or hrp
typedef boost::archive::detail::common_iarchive<Archive>
detail_common_iarchive;
template <class T>
void load_override(
#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
const
#endif
boost::serialization::hrp<T> &t) {
this->This()->load_start(t.name());
this->detail_common_iarchive::load_override(t.value());
this->This()->load_end(t.name());
}
// class_name_type can't be handled here as it depends upon the
// char type used by the stream. So require the derived implementation.
// derived in this case is xml_iarchive_impl or base ..
// Note: using base::load_override covers all basic_xml_iarchive overloads
// transitively, so a separate 'using basic_xml_iarchive::load_override'
// is redundant and creates ambiguity with clang.
using base::load_override;
void load_override(const char *str) {
// StringReader sr(basic_text_iprimitive::is);
// sr >> str;
}
virtual ~xml_iarchive() {}
};
template <class ArchiveImpl>
struct polymorphic_iarchive_route
: boost::archive::detail::polymorphic_iarchive_route<ArchiveImpl> {
virtual void load(const char *t) { ArchiveImpl::load(t); }
};
class polymorphic_xml_iarchive
: public polymorphic_iarchive_route<
boost::archive::xml_iarchive_impl<xml_iarchive>> {
public:
virtual void load_override(const char *str) {}
};
class xml_oarchive : public boost::archive::xml_oarchive_impl<xml_oarchive> {
typedef xml_oarchive Archive;
typedef boost::archive::xml_oarchive_impl<Archive> base;
unsigned int m_flags;
// give serialization implementation access to this class
friend class boost::archive::detail::interface_oarchive<Archive>;
friend class boost::archive::basic_xml_oarchive<Archive>;
friend class boost::archive::save_access;
public:
xml_oarchive(std::ostream &os, unsigned int flags = 0)
: boost::archive::xml_oarchive_impl<xml_oarchive>(
os, flags | boost::archive::no_header), m_flags(flags) {
if (0 == (flags & boost::archive::no_header)) {
this->This()->put(
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n");
this->This()->put("<!DOCTYPE ulib_serialization>\n");
this->This()->put("<ulib_serialization signature=\"serialization::archive\" ");
this->write_attribute("version", (const char *)ULIB_SERIALIZATION_VERSION);
this->This()->put(">\n");
}
}
virtual ~xml_oarchive() {
if (0 == (m_flags & boost::archive::no_header)) {
this->This()->put("</ulib_serialization>\n");
}
}
using basic_xml_oarchive::save_override;
// special treatment for name-value pairs.
typedef boost::archive::detail::common_oarchive<Archive>
detail_common_oarchive;
template <class T>
void save_override(
#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
const
#endif
::boost::serialization::hrp<T> &t) {
this->This()->save_start(t.name());
this->detail_common_oarchive::save_override(t.const_value());
this->This()->save_end(t.name());
}
void save_override(const char *str) {
// Do not save any human decoration string //
// basic_text_oprimitive::save(str);
}
};
// typedef boost::archive::detail::polymorphic_oarchive_route<
// boost::archive::xml_oarchive_impl<xml_oarchive>
//> polymorphic_xml_oarchive;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// TEXT //
class text_iarchive : public boost::archive::text_iarchive_impl<text_iarchive> {
typedef text_iarchive Archive;
typedef boost::archive::text_iarchive_impl<Archive> base;
// give serialization implementation access to this class
friend class boost::archive::detail::interface_iarchive<Archive>;
friend class boost::archive::basic_text_iarchive<Archive>;
friend class boost::archive::load_access;
public:
text_iarchive(std::istream &is, unsigned int flags = 0)
: text_iarchive_impl<Archive>(is, flags) {}
using base::load_override;
void load_override(boost::archive::object_id_type &t) {}
void load_override(const char *str) {
StringReader sr(basic_text_iprimitive::is);
sr >> str;
}
virtual ~text_iarchive() {}
};
typedef text_iarchive naked_text_iarchive;
class text_oarchive : public boost::archive::text_oarchive_impl<text_oarchive> {
typedef text_oarchive Archive;
typedef boost::archive::text_oarchive_impl<Archive> base;
// give serialization implementation access to this class
friend class boost::archive::detail::interface_oarchive<Archive>;
friend class boost::archive::basic_text_oarchive<Archive>;
friend class boost::archive::save_access;
public:
text_oarchive(std::ostream &os, unsigned int flags = 0)
: boost::archive::text_oarchive_impl<Archive>(os, flags) {}
using basic_text_oarchive::save_override;
void save_override(const char *str) { basic_text_oprimitive::save(str); }
virtual ~text_oarchive() {}
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// SIMPLE HUMAN READABLE TEXT //
class hrt_iarchive : public boost::archive::text_iarchive_impl<hrt_iarchive> {
typedef hrt_iarchive Archive;
typedef boost::archive::text_iarchive_impl<Archive> base;
// give serialization implementation access to this class
friend class boost::archive::detail::interface_iarchive<Archive>;
friend class boost::archive::basic_text_iarchive<Archive>;
friend class boost::archive::load_access;
public:
hrt_iarchive(std::istream &is, unsigned int flags = 0)
: base(is, flags | boost::archive::no_header) {}
using base::load_override;
// hide all archive props //
void load_override(boost::archive::object_id_type &t) {}
void load_override(boost::archive::object_reference_type &t) {}
void load_override(boost::archive::version_type &t) {}
void load_override(boost::archive::class_id_type &t) {}
void load_override(boost::archive::class_id_optional_type &t) {}
void load_override(boost::archive::class_id_reference_type &t) {}
void load_override(boost::archive::class_name_type &t) {}
void load_override(boost::archive::tracking_type &t) {}
void load_override(const char *str) {
StringReader sr(basic_text_iprimitive::is);
sr >> str;
}
virtual ~hrt_iarchive() {}
};
class hrt_oarchive : public boost::archive::text_oarchive_impl<hrt_oarchive> {
typedef hrt_oarchive Archive;
typedef boost::archive::text_oarchive_impl<Archive> base;
// give serialization implementation access to this class
friend class boost::archive::detail::interface_oarchive<Archive>;
friend class boost::archive::basic_text_oarchive<Archive>;
friend class boost::archive::save_access;
public:
hrt_oarchive(std::ostream &os, unsigned int flags = 0)
: base(os, flags | boost::archive::no_header) {}
using basic_text_oarchive::save_override;
void save_override(const boost::archive::object_id_type &t) {}
void save_override(const boost::archive::object_reference_type &t) {}
void save_override(const boost::archive::version_type &t) {}
void save_override(const boost::archive::class_id_type &t) {}
void save_override(const boost::archive::class_id_optional_type &t) {}
void save_override(const boost::archive::class_id_reference_type &t) {}
void save_override(const boost::archive::class_name_type &t) {}
void save_override(const boost::archive::tracking_type &t) {}
void save_override(const char *str) { basic_text_oprimitive::save(str); }
template <class T>
void save_override(const boost::serialization::hrp<T> &t) {
*this << t.name() << ": ";
*this << t.const_value();
*this << "\n";
}
virtual ~hrt_oarchive() {}
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// XML FOR LOG OUTPUT PURPOUSE //
/////////////////////////////////////////////////////////////////////////
// log data to an output stream. This illustrates a simpler implemenation
// of text output which is useful for getting a formatted display of
// any serializable class. Intended to be useful as a debugging aid.
class log_archive :
/* protected ? */
public boost::archive::xml_oarchive_impl<log_archive> {
typedef boost::archive::xml_oarchive_impl<log_archive> base;
typedef log_archive Archive;
// give serialization implementation access to this clas
friend class boost::archive::detail::interface_oarchive<log_archive>;
friend class boost::archive::basic_xml_oarchive<log_archive>;
friend class boost::archive::save_access;
public:
void save_override(const char *str) {
// Do not save any human decoration string //
// basic_text_oprimitive::save(str);
}
template <class T> void save_override(const T &t) {
base::save_override(boost::serialization::make_nvp(nullptr, t));
}
template <class T> void save_override(const boost::serialization::nvp<T> &t) {
base::save_override(t);
}
template <class T> void save_override(const boost::serialization::hrp<T> &t) {
base::save_override(boost::serialization::make_nvp(t.name(), t.const_value()));
}
// specific overrides for attributes - not name value pairs so we
// want to trap them before the above "fall through"
// since we don't want to see these in the output - make them no-ops.
void save_override(const boost::archive::object_id_type &t) {}
void save_override(const boost::archive::object_reference_type &t) {}
void save_override(const boost::archive::version_type &t) {}
void save_override(const boost::archive::class_id_type &t) {}
void save_override(const boost::archive::class_id_optional_type &t) {}
void save_override(const boost::archive::class_id_reference_type &t) {}
void save_override(const boost::archive::class_name_type &t) {}
void save_override(const boost::archive::tracking_type &t) {}
public:
log_archive(std::ostream &os, unsigned int flags = 0)
: boost::archive::xml_oarchive_impl<log_archive>(
os, flags | boost::archive::no_header) {}
virtual ~log_archive() {}
};
} // namespace Archive
} // namespace uLib
ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::xml_iarchive)
ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::xml_oarchive)
ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::text_iarchive)
ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::text_oarchive)
ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::hrt_iarchive)
ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::hrt_oarchive)
ULIB_SERIALIZATION_REGISTER_ARCHIVE(uLib::Archive::log_archive)
#endif // U_CORE_ARCHIVES_H