Skip to content

Commit

Permalink
altered boost optional to depend only public interface functions decl…
Browse files Browse the repository at this point in the history
…ared in std::optional.

adjusted test_optional to test serialization of both boost::optional and std::optional
  • Loading branch information
robertramey committed Sep 8, 2023
1 parent 5ba9e77 commit 61a2b12
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 46 deletions.
110 changes: 87 additions & 23 deletions include/boost/serialization/optional.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@

// Provides non-intrusive serialization for boost::optional.

#ifndef BOOST_SERIALIZATION_OPTIONAL_HPP_
#define BOOST_SERIALIZATION_OPTIONAL_HPP_
#ifndef BOOST_SERIALIZATION_OPTIONAL_HPP
#define BOOST_SERIALIZATION_OPTIONAL_HPP

#if defined(_MSC_VER)
# pragma once
#endif

#include <boost/config.hpp>

#include <boost/optional.hpp>
#ifdef BOOST_NO_CXX17_HDR_OPTIONAL
#include <optional>
#endif

#include <boost/serialization/item_version_type.hpp>
#include <boost/serialization/library_version_type.hpp>
Expand All @@ -30,41 +32,43 @@
// namespace - boost::serialization
namespace boost {
namespace serialization {
namespace detail {

template<class Archive, class T>
void save(
// OT is of the form optional<T>
template<class Archive, class OT>
void save_impl(
Archive & ar,
const boost::optional< T > & t,
const unsigned int /*version*/
const OT & ot
){
// It is an inherent limitation to the serialization of optional.hpp
// that the underlying type must be either a pointer or must have a
// default constructor. It's possible that this could change sometime
// in the future, but for now, one will have to work around it. This can
// be done by serialization the optional<T> as optional<T *>
#if ! defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
BOOST_STATIC_ASSERT(
boost::serialization::detail::is_default_constructible<T>::value
|| boost::is_pointer<T>::value
boost::serialization::detail::is_default_constructible<typename OT::value_type>::value
|| boost::is_pointer<typename OT::value_type>::value
);
#endif
const bool tflag = t.is_initialized();
const bool tflag(ot);
ar << boost::serialization::make_nvp("initialized", tflag);
if (tflag){
ar << boost::serialization::make_nvp("value", *t);
ar << boost::serialization::make_nvp("value", *ot);
}
}

template<class Archive, class T>
void load(
// OT is of the form optional<T>
template<class Archive, class OT>
void load_impl(
Archive & ar,
boost::optional< T > & t,
OT & ot,
const unsigned int version
){
bool tflag;
ar >> boost::serialization::make_nvp("initialized", tflag);
if(! tflag){
t.reset();
ot.reset();
return;
}

Expand All @@ -77,26 +81,86 @@ void load(
ar >> BOOST_SERIALIZATION_NVP(item_version);
}
}
if(! t.is_initialized())
t = T();
ar >> boost::serialization::make_nvp("value", *t);
typename OT::value_type t;
ar >> boost::serialization::make_nvp("value",t);
ot = t;
}

} // detail

template<class Archive, class T>
void save(
Archive & ar,
const boost::optional< T > & ot,
const unsigned int /*version*/
){
detail::save_impl(ar, ot);
}

#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
template<class Archive, class T>
void save(
Archive & ar,
const std::optional< T > & ot,
const unsigned int /*version*/
){
detail::save_impl(ar, ot);
}
#endif

template<class Archive, class T>
void load(
Archive & ar,
boost::optional< T > & ot,
const unsigned int version
){
detail::load_impl(ar, ot, version);
}

#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
template<class Archive, class T>
void load(
Archive & ar,
std::optional< T > & ot,
const unsigned int version
){
detail::load_impl(ar, ot, version);
}
#endif

template<class Archive, class T>
void serialize(
Archive & ar,
boost::optional< T > & t,
boost::optional< T > & ot,
const unsigned int version
){
boost::serialization::split_free(ar, t, version);
boost::serialization::split_free(ar, ot, version);
}

#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
template<class Archive, class T>
void serialize(
Archive & ar,
std::optional< T > & ot,
const unsigned int version
){
boost::serialization::split_free(ar, ot, version);
}
#endif

template<class T>
struct version<boost::optional<T> >{
BOOST_STATIC_CONSTANT(int, value = 1);
};

#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
template<class T>
struct version<boost::optional<T> > {
struct version<std::optional<T> >{
BOOST_STATIC_CONSTANT(int, value = 1);
};
#endif

} // serialization
} // boost

#endif // BOOST_SERIALIZATION_OPTIONAL_HPP_
#endif // BOOST_SERIALIZATION_OPTIONAL_HPP
4 changes: 1 addition & 3 deletions include/boost/serialization/split_free.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@ namespace archive {

namespace serialization {

//namespace detail {
template<class Archive, class T>
struct free_saver {
static void invoke(
Archive & ar,
const T & t,
const T & t,
const unsigned int file_version
){
// use function overload (version_type) to workaround
Expand All @@ -58,7 +57,6 @@ struct free_loader {
load(ar, t, v);
}
};
//} // namespace detail

template<class Archive, class T>
inline void split_free(
Expand Down
50 changes: 30 additions & 20 deletions test/test_optional.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ namespace std{
#include <boost/archive/archive_exception.hpp>
#include "test_tools.hpp"

#include <boost/serialization/optional.hpp>
#include <boost/serialization/string.hpp>

struct A {
int m_x;
Expand All @@ -44,18 +42,19 @@ struct A {
{}
};

int test_main( int /* argc */, char* /* argv */[] )
{
// Optional is the class optional implementation you use
template<template<class> class Optional>
int test(){
const char * testfile = boost::archive::tmpnam(NULL);
BOOST_REQUIRE(NULL != testfile);

const boost::optional<int> aoptional1;
const boost::optional<int> aoptional2(123);
const boost::optional<A> aoptional3;
const Optional<int> aoptional1;
const Optional<int> aoptional2(123);
const Optional<A> aoptional3;
A a(1);
const boost::optional<A> aoptional4(a);
const boost::optional<A *> aoptional5;
const boost::optional<A *> aoptional6(& a);
const Optional<A> aoptional4(a);
const Optional<A *> aoptional5;
const Optional<A *> aoptional6(& a);
{
test_ostream os(testfile, TEST_STREAM_FLAGS);
test_oarchive oa(os, TEST_ARCHIVE_FLAGS);
Expand All @@ -66,12 +65,12 @@ int test_main( int /* argc */, char* /* argv */[] )
oa << boost::serialization::make_nvp("aoptional5",aoptional5);
oa << boost::serialization::make_nvp("aoptional6",aoptional6);
}
boost::optional<int> aoptional1a(999);
boost::optional<int> aoptional2a;
boost::optional<A> aoptional3a;
boost::optional<A> aoptional4a;
boost::optional<A *> aoptional5a;
boost::optional<A *> aoptional6a;
Optional<int> aoptional1a(999);
Optional<int> aoptional2a;
Optional<A> aoptional3a;
Optional<A> aoptional4a;
Optional<A *> aoptional5a;
Optional<A *> aoptional6a;
{
test_istream is(testfile, TEST_STREAM_FLAGS);
test_iarchive ia(is, TEST_ARCHIVE_FLAGS);
Expand All @@ -85,12 +84,23 @@ int test_main( int /* argc */, char* /* argv */[] )
BOOST_CHECK(aoptional1 == aoptional1a);
BOOST_CHECK(aoptional2 == aoptional2a);
BOOST_CHECK(aoptional3 == aoptional3a);
BOOST_CHECK(aoptional4.get() == aoptional4a.get());
BOOST_CHECK(aoptional5 == aoptional5a);
BOOST_CHECK(*aoptional6.get() == *aoptional6a.get());
BOOST_CHECK(aoptional4 == aoptional4a);
BOOST_CHECK(aoptional5 == aoptional5a); // not initialized
BOOST_CHECK(**aoptional6 == **aoptional6a);

std::remove(testfile);
return EXIT_SUCCESS;
}

// EOF
#include <boost/serialization/optional.hpp>
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
#include <optional>
#endif

int test_main( int /* argc */, char* /* argv */[] ){
test<boost::optional>();
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
test<std::optional>();
#endif
return EXIT_SUCCESS;
}

0 comments on commit 61a2b12

Please sign in to comment.