Skip to content

Commit

Permalink
Add std::variant boost serialization support
Browse files Browse the repository at this point in the history
  • Loading branch information
Levi-Armstrong committed Sep 22, 2023
1 parent 49c9497 commit 9f836ef
Showing 1 changed file with 205 additions and 0 deletions.
205 changes: 205 additions & 0 deletions tesseract_common/include/tesseract_common/std_variant_serialization.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
#ifndef TESSERACT_COMMON_STD_VARIANT_SERIALIZATION_H
#define TESSERACT_COMMON_STD_VARIANT_SERIALIZATION_H

#if BOOST_VERSION > 108300
#include <boost/serialization/std_variant.hpp>
#else

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// variant.hpp - non-intrusive serialization of variant types
//
// copyright (c) 2019 Samuel Debionne, ESRF
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org for updates, documentation, and revision history.
//
// Widely inspired form boost::variant serialization
//

#include <boost/serialization/throw_exception.hpp>

#include <variant>

#include <boost/archive/archive_exception.hpp>

#include <boost/serialization/split_free.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>

namespace boost {
namespace serialization {

template<class Archive>
struct std_variant_save_visitor
{
std_variant_save_visitor(Archive& ar) :
m_ar(ar)
{}
template<class T>
void operator()(T const & value) const
{
m_ar << BOOST_SERIALIZATION_NVP(value);
}
private:
Archive & m_ar;
};


template<class Archive>
struct std_variant_load_visitor
{
std_variant_load_visitor(Archive& ar) :
m_ar(ar)
{}
template<class T>
void operator()(T & value) const
{
m_ar >> BOOST_SERIALIZATION_NVP(value);
}
private:
Archive & m_ar;
};

template<class Archive, class ...Types>
void save(
Archive & ar,
std::variant<Types...> const & v,
unsigned int /*version*/
){
const std::size_t which = v.index();
ar << BOOST_SERIALIZATION_NVP(which);
std_variant_save_visitor<Archive> visitor(ar);
std::visit(visitor, v);
}

// Minimalist metaprogramming for handling parameter pack
namespace mp {
namespace detail {
template <typename Seq>
struct front_impl;

template <template <typename...> class Seq, typename T, typename... Ts>
struct front_impl<Seq<T, Ts...>> {
using type = T;
};

template <typename Seq>
struct pop_front_impl;

template <template <typename...> class Seq, typename T, typename... Ts>
struct pop_front_impl<Seq<T, Ts...>> {
using type = Seq<Ts...>;
};
} //namespace detail

template <typename... Ts>
struct typelist {};

template <typename Seq>
using front = typename detail::front_impl<Seq>::type;

template <typename Seq>
using pop_front = typename detail::pop_front_impl<Seq>::type;
} // namespace mp

template<std::size_t N, class Seq>
struct variant_impl
{
template<class Archive, class V>
static void load (
Archive & ar,
std::size_t which,
V & v,
const unsigned int version
){
if(which == 0){
// note: A non-intrusive implementation (such as this one)
// necessary has to copy the value. This wouldn't be necessary
// with an implementation that de-serialized to the address of the
// aligned storage included in the variant.
using type = mp::front<Seq>;
type value;
ar >> BOOST_SERIALIZATION_NVP(value);
v = std::move(value);
type * new_address = & std::get<type>(v);
ar.reset_object_address(new_address, & value);
return;
}
//typedef typename mpl::pop_front<S>::type type;
using types = mp::pop_front<Seq>;
variant_impl<N - 1, types>::load(ar, which - 1, v, version);
}
};

template<class Seq>
struct variant_impl<0, Seq>
{
template<class Archive, class V>
static void load (
Archive & /*ar*/,
std::size_t /*which*/,
V & /*v*/,
const unsigned int /*version*/
){}
};

template<class Archive, class... Types>
void load(
Archive & ar,
std::variant<Types...>& v,
const unsigned int version
){
std::size_t which;
ar >> BOOST_SERIALIZATION_NVP(which);
if(which >= sizeof...(Types))
// this might happen if a type was removed from the list of variant types
boost::serialization::throw_exception(
boost::archive::archive_exception(
boost::archive::archive_exception::unsupported_version
)
);
variant_impl<sizeof...(Types), mp::typelist<Types...>>::load(ar, which, v, version);
}

template<class Archive,class... Types>
inline void serialize(
Archive & ar,
std::variant<Types...> & v,
const unsigned int file_version
){
split_free(ar,v,file_version);
}

// Specialization for std::monostate
template<class Archive>
void serialize(Archive &ar, std::monostate &, const unsigned int /*version*/)
{}

} // namespace serialization
} // namespace boost

//template<typename T0_, BOOST_VARIANT_ENUM_SHIFTED_PARAMS(typename T)>

#include <boost/serialization/tracking.hpp>

namespace boost {
namespace serialization {

template<class... Types>
struct tracking_level<
std::variant<Types...>
>{
typedef mpl::integral_c_tag tag;
typedef mpl::int_< ::boost::serialization::track_always> type;
BOOST_STATIC_CONSTANT(int, value = type::value);
};

} // namespace serialization
} // namespace boost

#endif

#endif // TESSERACT_COMMON_STD_VARIANT_SERIALIZATION_H

0 comments on commit 9f836ef

Please sign in to comment.