Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed serialization of boost.variant to use variadic templates #2874

Merged
merged 1 commit into from Sep 6, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
123 changes: 48 additions & 75 deletions hpx/runtime/serialization/variant.hpp
Expand Up @@ -6,122 +6,95 @@
// Distributed under 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)

// make inspect happy: hpxinspect:nodeprecatedinclude hpxinspect:nodeprecatedname

#ifndef HPX_SERIALIZATION_VARIANT_HPP
#define HPX_SERIALIZATION_VARIANT_HPP

#include <hpx/config.hpp>
#include <hpx/runtime/serialization/serialization_fwd.hpp>
#include <hpx/throw_exception.hpp>

#include <boost/mpl/empty.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/size.hpp>

#include <boost/variant.hpp>

#include <utility>

namespace hpx { namespace serialization
{
struct variant_save_visitor :
boost::static_visitor<>
struct variant_save_visitor : boost::static_visitor<>
{
variant_save_visitor(output_archive& ar) :
m_ar(ar)
variant_save_visitor(output_archive& ar)
: m_ar(ar)
{}

template<class T>
void operator()(T const & value) const
template <typename T>
void operator()(T const& value) const
{
m_ar << value;
}

private:
output_archive & m_ar;
};

template<class S>
struct variant_impl {
template <typename ... Ts>
struct variant_impl;

struct load_null {
template<class V>
static void invoke(
input_archive& /*ar*/,
int /*which*/,
V & /*v*/
){}
};

struct load_impl {
template<class V>
static void invoke(
input_archive& ar,
int which,
V & v
){
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.
typedef typename boost::mpl::front<S>::type head_type;
head_type value;
ar >> value;
v = value;
return;
}
typedef typename boost::mpl::pop_front<S>::type type;
variant_impl<type>::load(ar, which - 1, v);
template <typename T, typename ... Ts>
struct variant_impl<T, Ts...>
{
template <typename V>
static void load(input_archive& ar, int which, V& v)
{
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.
T value;
ar >> value;
v = std::move(value);
return;
}
};

template<class V>
static void load(
input_archive& ar,
int which,
V & v
){
typedef typename boost::mpl::eval_if<boost::mpl::empty<S>,
boost::mpl::identity<load_null>,
boost::mpl::identity<load_impl>
>::type typex;
typex::invoke(ar, which, v);
variant_impl<Ts...>::load(ar, which - 1, v);
}
};

template <>
struct variant_impl<>
{
template <typename V>
static void load(input_archive& /*ar*/, int /*which*/, V& /*v*/)
{
}
};

template<BOOST_VARIANT_ENUM_PARAMS(class T)>
void save(output_archive& ar,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const & v, unsigned)
template <typename ... T>
void save(output_archive& ar, boost::variant<T...> const& v, unsigned)
{
int which = v.which();
ar << which;
variant_save_visitor visitor(ar);
v.apply_visitor(visitor);
}

template<BOOST_VARIANT_ENUM_PARAMS(class T)>
void load(input_archive& ar,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& v, unsigned)
template <typename ... T>
void load(input_archive& ar, boost::variant<T...>& v, unsigned)
{
int which;
typedef typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types types;
ar >> which;
if(which >= boost::mpl::size<types>::value)
// this might happen if a type was removed from the list of variant types
if (which >= static_cast<int>(sizeof...(T)))
{
// this might happen if a type was removed from the list of variant
// types
HPX_THROW_EXCEPTION(serialization_error
, "load<Archive, Variant, version>"
, "type was removed from the list of variant types");
variant_impl<types>::load(ar, which, v);
}
variant_impl<T...>::load(ar, which, v);
}

HPX_SERIALIZATION_SPLIT_FREE_TEMPLATE((template
<BOOST_VARIANT_ENUM_PARAMS(class T)>),
(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>));

} // namespace serialization
} // namespace boost
HPX_SERIALIZATION_SPLIT_FREE_TEMPLATE(
(template<typename ... T>), (boost::variant<T...>));
}}

#endif //HPX_SERIALIZATION_VARIANT_HPP