Skip to content

Commit

Permalink
Unify serialization of non-default-constructable types
Browse files Browse the repository at this point in the history
- this fixes #2846
- flyby: fixed a couple of warnings in tests
  • Loading branch information
hkaiser committed Aug 18, 2017
1 parent a17f3e8 commit 670d01f
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 36 deletions.
Expand Up @@ -30,6 +30,23 @@

namespace hpx { namespace serialization { namespace detail
{
///////////////////////////////////////////////////////////////////////////
// default fall-backs for constructing non-default-constructable types
template <class Archive, class T>
void save_construct_data(Archive&, T*, unsigned)
{
// a user is not required to provide their own adl-overload
}

template <class Archive, class T>
void load_construct_data(Archive& ar, T* t, unsigned)
{
// this function is never supposed to be called
HPX_ASSERT(false);
::new (t) T;
}

///////////////////////////////////////////////////////////////////////////
template <typename T>
struct get_serialization_name
#ifdef HPX_DISABLE_AUTOMATIC_SERIALIZATION_REGISTRATION
Expand Down Expand Up @@ -65,25 +82,59 @@ namespace hpx { namespace serialization { namespace detail
class constructor_selector
{
public:
static T *create(input_archive& ar)
static T* create(input_archive& ar)
{
return create(
ar, typename std::is_default_constructible<T>::type());
}

// is default-constructible
static T* create(input_archive& ar, std::true_type)
{
T* t = new T;
try
{
load_polymorphic(
t, ar, hpx::traits::is_nonintrusive_polymorphic<T>());
}
catch (...)
{
delete t;
throw;
}
return t;
}

// is non-default-constructible
static T* create(input_archive& ar, std::false_type)
{
T *t = new T;
try {
load_polymorphic(t, ar, hpx::traits::is_nonintrusive_polymorphic<T>());
} catch (...) {
using storage_type = typename std::aligned_storage<
sizeof(T), alignof(T)>::type;

storage_type* storage = new storage_type;
T* t = reinterpret_cast<T*>(storage);
load_construct_data(ar, t, 0);

try
{
load_polymorphic(
t, ar, hpx::traits::is_nonintrusive_polymorphic<T>());
}
catch (...)
{
delete t;
throw;
}
return t;
}

private:
static void load_polymorphic(T *t, input_archive& ar, std::true_type)
static void load_polymorphic(T* t, input_archive& ar, std::true_type)
{
serialize(ar, *t, 0);
}

static void load_polymorphic(T *t, input_archive& ar, std::false_type)
static void load_polymorphic(T* t, input_archive& ar, std::false_type)
{
ar >> *t;
}
Expand Down
31 changes: 7 additions & 24 deletions hpx/runtime/serialization/detail/serialize_collection.hpp
Expand Up @@ -8,27 +8,14 @@

#include <hpx/config.hpp>
#include <hpx/traits/detail/reserve.hpp>
#include <hpx/runtime/serialization/detail/polymorphic_nonintrusive_factory.hpp>

#include <memory>
#include <type_traits>
#include <utility>

namespace hpx { namespace serialization { namespace detail {

// default fallbacks
template <class Archive, class T>
void save_construct_data(Archive&, T*, unsigned)
{
// a user is not required to provide their own adl-overload
}

template <class Archive, class T>
void load_construct_data(Archive&, T* t, unsigned)
{
// this function is never supposed to be called
HPX_ASSERT(false);
::new (t) T;
}

namespace hpx { namespace serialization { namespace detail
{
template <class Value>
class save_collection_impl
{
Expand Down Expand Up @@ -86,19 +73,15 @@ namespace hpx { namespace serialization { namespace detail {
typename Collection::size_type size)
{
using value_type = typename Collection::value_type;
using storage_type = typename std::aligned_storage<
sizeof(value_type), alignof(value_type)>::type;

collection.clear();
hpx::traits::detail::reserve_if_reservable(collection, size);

while (size-- > 0)
{
storage_type storage;
value_type& ref = reinterpret_cast<value_type&>(storage);
load_construct_data(ar, &ref, 0);
ar >> ref;
collection.push_back(std::move(ref));
std::unique_ptr<value_type> data(
constructor_selector<value_type>::create(ar));
collection.push_back(std::move(*data));
}
}
};
Expand Down
Expand Up @@ -92,7 +92,7 @@ void serialize(Archive& ar, C<T>& c, unsigned)
}

template<typename T>
C<T> *c_factory(hpx::serialization::input_archive& ar, C<T> */*unused*/)
C<T> *c_factory(hpx::serialization::input_archive& ar, C<T> * /*unused*/)
{
C<T> *c = new C<T>(999);
serialize(ar, *c, 0);
Expand Down Expand Up @@ -129,7 +129,7 @@ namespace hpx { namespace serialization {
} }

template<typename T>
E<T> *e_factory(hpx::serialization::input_archive& ar, E<T> */*unused*/)
E<T> *e_factory(hpx::serialization::input_archive& ar, E<T> * /*unused*/)
{
E<T> *e = new E<T>(99, 9999);
serialize(ar, *e, 0);
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/serialization/serialization_array.cpp
Expand Up @@ -236,7 +236,7 @@ void test_plain_array()
T oarray[N];

for(std::size_t i = 0; i < N; ++i) {
iarray[i] = i * i;
iarray[i] = static_cast<T>(i * i);
oarray[i] = -1;
}

Expand All @@ -261,7 +261,7 @@ void test_array_of_vectors()

for(std::size_t i = 0; i < N; ++i) {
for (std::size_t j = 0; j < i; ++j) {
iarray[i].push_back(i * i);
iarray[i].push_back(static_cast<T>(i * i));
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/serialization/serialize_buffer.cpp
Expand Up @@ -90,7 +90,7 @@ void test_fixed_size_initialization_for_persistent_buffers(std::size_t max_size)
std::vector<T> recv_vec;
send_vec.reserve(size);
for (std::size_t i = 0; i < size; ++i) {
send_vec.push_back(size - i);
send_vec.push_back(static_cast<int>(size - i));
}

hpx::serialization::serialize_buffer<T> send_buffer(size);
Expand Down

0 comments on commit 670d01f

Please sign in to comment.