Skip to content

Commit

Permalink
imported/implemented boost/serialization/variant and test_variant
Browse files Browse the repository at this point in the history
imported/implemented boost/serialization/variant now contains code for serialization of boost::variant, boost::variant2 and std::variant. Care has been taken to depend only on the public interfaces of these types. Hence, it is reasonable to hope that the archives are compatible in that one type could be saved and subsequently loaded into a compatible type.  Hopefully this will be useful in some way.  At a minimum it minimizes code duplication.
  • Loading branch information
robertramey committed Sep 18, 2023
1 parent 61a2b12 commit 897dec4
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 481 deletions.
20 changes: 10 additions & 10 deletions CMake/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CMake build control file for Serialization Library tests

cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)

if (POLICY CMP0054)
cmake_policy (SET CMP0054 NEW)
Expand All @@ -16,27 +16,28 @@ project("serialization")
# Compiler settings
#

message(STATUS "compiler is ${CMAKE_CXX_COMPILER_ID}" )
message(STATUS "C++ compiler is ${CMAKE_CXX_COMPILER_ID}" )
add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS})
message(STATUS "C compiler is ${CMAKE_C_COMPILER_ID}" )

if( CMAKE_CXX_COMPILER_ID STREQUAL "GNU" )
add_definitions( -std=c++11 )
add_definitions( -ftemplate-depth=255 )
# we use gcc to test for C++03 compatibility
add_definitions( -std=c++03 )
message(STATUS "compiler is g++ c++03")
set(COMPILER_SUPPORTS_CXX11 FALSE)
elseif( CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" )
add_definitions( /wd4996 )
message(STATUS "compiler is MSVC")
set(COMPILER_SUPPORTS_CXX11 TRUE)
elseif( CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" )
add_definitions( -std=c++17 )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth=300")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0" )
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -O3" )
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -dead_strip")
set(COMPILER_SUPPORTS_CXX11 FALSE)
set(COMPILER_SUPPORTS_CXX11 TRUE)
endif()

#
Expand All @@ -46,14 +47,14 @@ endif()
# Boost

# note: we're assuming that boost has been built with:
# ./b2 toolset=clang-darwin link=static,shared variant=debug,release stage
# ./b2 toolset=clang-17 link=static,shared variant=debug,release stage

#
# Project settings
#
option(BUILD_SHARED_LIBS "Build Shared Libraries" true)

find_package(Boost 1.74 REQUIRED COMPONENTS system filesystem)
find_package(Boost 1.82 REQUIRED COMPONENTS system filesystem)

if(NOT Boost_FOUND)
message("Boost NOT Found!")
Expand Down Expand Up @@ -335,7 +336,6 @@ archive_test(test_unregistered)
archive_test(test_unique_ptr)
archive_test(test_valarray)
archive_test(test_variant A)
archive_test(test_std_variant A)
archive_test(test_vector A)

polymorphic_archive_test(test_dll_exported polymorphic_derived1)
Expand Down
183 changes: 161 additions & 22 deletions include/boost/serialization/variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
// troy d. straszheim <[email protected]>
// http://www.resophonic.com
//
// copyright (c) 2019 Samuel Debionne, ESRF
//
// copyright (c) 2023
// Robert Ramey <[email protected]>
// http://www.rrsd.com
//
// 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)
Expand All @@ -31,27 +37,57 @@

#include <boost/serialization/throw_exception.hpp>

#include <boost/variant.hpp>
// Boost Variant supports all C++ versions back to C++03
#include <boost/variant/variant.hpp>
#include <boost/variant/get.hpp>

// Boost Variant2 supports all C++ versions back to C++11
#if BOOST_CXX_VERSION >= 201103L
#include <boost/variant2/variant.hpp>
#include <type_traits>
#endif

// Boost Variant2 supports all C++ versions back to C++11
#ifndef BOOST_NO_CXX17_HDR_VARIANT
#include <variant>
//#include <type_traits>
#endif

#include <boost/archive/archive_exception.hpp>

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

// use visitor from boost::variant
template<class Visitor, BOOST_VARIANT_ENUM_PARAMS(class T)>
typename Visitor::result_type visit(
Visitor visitor,
const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & t
){
return boost::apply_visitor(visitor, t);
}
template<class Visitor, BOOST_VARIANT_ENUM_PARAMS(class T)>
typename Visitor::result_type visit(
Visitor visitor,
const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & t,
const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & u
){
return boost::apply_visitor(visitor, t, u);
}

namespace boost {
namespace serialization {

template<class Archive>
struct variant_save_visitor :
boost::static_visitor<>
boost::static_visitor<void>
{
variant_save_visitor(Archive& ar) :
m_ar(ar)
{}
template<class T>
void operator()(T const & value) const
{
void operator()(T const & value) const {
m_ar << BOOST_SERIALIZATION_NVP(value);
}
private:
Expand All @@ -67,27 +103,55 @@ void save(
int which = v.which();
ar << BOOST_SERIALIZATION_NVP(which);
variant_save_visitor<Archive> visitor(ar);
v.apply_visitor(visitor);
visit(visitor, v);
}

#if BOOST_CXX_VERSION >= 201103L
template<class Archive, class ...Types>
void save(
Archive & ar,
boost::variant2::variant<Types...> const & v,
unsigned int /*version*/
){
int which = v.index();
ar << BOOST_SERIALIZATION_NVP(which);
const variant_save_visitor<Archive> visitor(ar);
visit(visitor, v);
}
#endif

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

template<class S>
struct variant_impl {

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

struct load_impl {
struct load_member {
template<class Archive, class V>
static void invoke(
Archive & ar,
int which,
std::size_t which,
V & v,
const unsigned int version
){
Expand All @@ -99,31 +163,30 @@ struct variant_impl {
typedef typename mpl::front<S>::type head_type;
head_type value;
ar >> BOOST_SERIALIZATION_NVP(value);
v = value;
head_type * new_address = & boost::get<head_type>(v);
v = std::move(value);;
head_type * new_address = & get<head_type>(v);
ar.reset_object_address(new_address, & value);
return;
}
typedef typename mpl::pop_front<S>::type type;
variant_impl<type>::load(ar, which - 1, v, version);
variant_impl<type>::load_impl(ar, which - 1, v, version);
}
};

template<class Archive, class V>
static void load(
static void load_impl(
Archive & ar,
int which,
std::size_t which,
V & v,
const unsigned int version
){
typedef typename mpl::eval_if<mpl::empty<S>,
mpl::identity<load_null>,
mpl::identity<load_impl>
mpl::identity<load_member>
>::type typex;
typex::invoke(ar, which, v, version);
}

};
}; // variant_impl

template<class Archive, BOOST_VARIANT_ENUM_PARAMS(/* typename */ class T)>
void load(
Expand All @@ -134,34 +197,99 @@ void load(
int which;
typedef typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types types;
ar >> BOOST_SERIALIZATION_NVP(which);
if(which >= mpl::size<types>::value)
if(which >= mpl::size<types>::value){
// 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<types>::load_impl(ar, which, v, version);
}

#if BOOST_CXX_VERSION >= 201103L
template<class Archive, class ... Types>
void load(
Archive & ar,
boost::variant2::variant<Types...> & v,
const unsigned int version
){
int which;
typedef typename boost::variant<Types...>::types types;
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<types>::load_impl(ar, which, v, version);
}
#endif

#ifndef BOOST_NO_CXX17_HDR_VARIANT
template<class Archive, class ... Types>
void load(
Archive & ar,
std::variant<Types...> & v,
const unsigned int version
){
int which;
typedef typename boost::variant<Types...>::types types;
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<types>::load(ar, which, v, version);
}
variant_impl<types>::load_impl(ar, which, v, version);
}
#endif

template<class Archive,BOOST_VARIANT_ENUM_PARAMS(/* typename */ class T)>
inline void serialize(
Archive & ar,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & v,
const unsigned int file_version
){
split_free(ar,v,file_version);
boost::serialization::split_free(ar,v,file_version);
}

#if BOOST_CXX_VERSION >= 201103L
template<class Archive, class ... Types>
inline void serialize(
Archive & ar,
boost::variant2::variant<Types...> & v,
const unsigned int file_version
){
boost::serialization::split_free(ar,v,file_version);
}
#endif

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

} // namespace serialization
} // namespace boost

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

#include <boost/serialization/tracking.hpp>

namespace boost {
namespace serialization {
namespace serialization {

template<BOOST_VARIANT_ENUM_PARAMS(/* typename */ class T)>
struct tracking_level<
Expand All @@ -172,6 +300,17 @@ struct tracking_level<
BOOST_STATIC_CONSTANT(int, value = type::value);
};

#ifndef BOOST_NO_CXX17_HDR_VARIANT
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);
};
#endif

} // namespace serialization
} // namespace boost

Expand Down
6 changes: 3 additions & 3 deletions include/boost/serialization/variant2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void save(
std::visit(visitor, v);
}

template<std::size_t N, class Seq>
template<class Seq>
struct variant_impl
{
template<class Archive, class V>
Expand All @@ -103,12 +103,12 @@ struct variant_impl
}
//typedef typename mpl::pop_front<S>::type type;
using types = mp11::mp_pop_front<Seq>;
variant_impl<N - 1, types>::load(ar, which - 1, v, version);
variant_impl<types>::load(ar, which - 1, v, version);
}
};

template<class Seq>
struct variant_impl<0, Seq>
struct variant_impl<Seq>
{
template<class Archive, class V>
static void load (
Expand Down
1 change: 0 additions & 1 deletion test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ test-suite "serialization" :
[ test-bsl-run_files test_unique_ptr ]
[ test-bsl-run_files test_valarray ]
[ test-bsl-run_files test_variant : A ]
[ test-bsl-run_files test_std_variant : A : : [ requires cxx17_hdr_variant ] ] # BOOST_NO_CXX17_HDR_VARIANT
[ test-bsl-run_files test_vector : A ]
[ test-bsl-run_files test_shared_ptr ]
[ test-bsl-run_files test_shared_ptr_multi_base ]
Expand Down
Loading

0 comments on commit 897dec4

Please sign in to comment.