From c5fef7c2143b7f05ae36354a1cba1d4df2c93fef Mon Sep 17 00:00:00 2001 From: Jakub Strzebonski Date: Mon, 14 Jun 2021 23:52:48 +0200 Subject: [PATCH] #161 use reconstruction logic for std::vector --- src/checkpoint/container/vector_serialize.h | 95 ++++++++++- tests/unit/test_vector_serializer.cc | 180 ++++++++++++++++++++ 2 files changed, 266 insertions(+), 9 deletions(-) create mode 100644 tests/unit/test_vector_serializer.cc diff --git a/src/checkpoint/container/vector_serialize.h b/src/checkpoint/container/vector_serialize.h index 98675725..09dd2b1b 100644 --- a/src/checkpoint/container/vector_serialize.h +++ b/src/checkpoint/container/vector_serialize.h @@ -45,6 +45,7 @@ #define INCLUDED_CHECKPOINT_CONTAINER_VECTOR_SERIALIZE_H #include "checkpoint/common.h" +#include "checkpoint/dispatch/reconstructor.h" #include "checkpoint/serializers/serializers_headers.h" #include @@ -53,29 +54,104 @@ namespace checkpoint { template typename std::enable_if_t< - not std::is_same::value, - void -> serializeVectorMeta(SerializerT& s, std::vector& vec) { + not std::is_same::value, SerialSizeType +> +serializeVectorMeta(SerializerT& s, std::vector& vec) { SerialSizeType vec_capacity = vec.capacity(); s | vec_capacity; vec.reserve(vec_capacity); SerialSizeType vec_size = vec.size(); s | vec_size; - vec.resize(vec_size); + return vec_size; } template typename std::enable_if_t< - std::is_same::value, - void -> serializeVectorMeta(SerializerT& s, std::vector& vec) { + std::is_same::value, SerialSizeType +> +serializeVectorMeta(SerializerT& s, std::vector& vec) { s.countBytes(vec); + return vec.size(); +} + +template +void constructVectorDataWithResize( + SerialSizeType const vec_size, std::vector& vec, + typename dispatch::Reconstructor::template isDefaultConsType* = nullptr +) { + vec.resize(vec_size); +} + +template +void constructVectorDataWithResize( + SerialSizeType const, std::vector& vec, + typename dispatch::Reconstructor::template isNotDefaultConsType* = nullptr +) { + static_assert( + SerializableTraits::is_tagged_constructible or + SerializableTraits::is_reconstructible or + std::is_default_constructible::value, + "Either a default constructor, reconstruct() function, or tagged " + "constructor are required for std::vector de-serialization" + ); +} + +template +void constructVectorDataReconstruct( + SerialSizeType const vec_size, std::vector& vec, + typename dispatch::Reconstructor::template isReconstructibleType* = nullptr +) { + auto buf = dispatch::Standard::template allocate(); + for (SerialSizeType i = 0; i < vec_size; ++i) { + auto& t = T::reconstruct(buf); + vec.emplace_back(std::move(t)); + } +} + +template +void constructVectorDataReconstruct( + SerialSizeType const vec_size, std::vector& vec, + typename dispatch::Reconstructor::template isNonIntReconstructibleType* = nullptr +) { + auto buf = dispatch::Standard::allocate(); + for (SerialSizeType i = 0; i < vec_size; ++i) { + T* t = nullptr; + reconstruct(t, buf); + vec.emplace_back(std::move(*t)); + } +} + +template +void constructVectorDataReconstruct( + SerialSizeType const vec_size, std::vector& vec, + typename dispatch::Reconstructor::template isNotReconstructibleType* = nullptr +) { + constructVectorDataWithResize(vec_size, vec); +} + +template +void constructVectorData( + SerialSizeType const vec_size, std::vector& vec, + typename dispatch::Reconstructor::template isTaggedConstructibleType* = nullptr +) { + for (SerialSizeType i = 0; i < vec_size; ++i) { + vec.emplace_back(SERIALIZE_CONSTRUCT_TAG{}); + } +} + +template +void constructVectorData( + SerialSizeType const vec_size, std::vector& vec, + typename dispatch::Reconstructor::template isNotTaggedConstructibleType* = nullptr +) { + constructVectorDataReconstruct(vec_size, vec); } template void serialize(Serializer& s, std::vector& vec) { - serializeVectorMeta(s, vec); + auto const vec_size = serializeVectorMeta(s, vec); + constructVectorData(vec_size, vec); dispatch::serializeArray(s, vec.data(), vec.size()); // make sure to account for reserved space when footprinting @@ -89,7 +165,8 @@ void serialize(Serializer& s, std::vector& vec) { return; } - serializeVectorMeta(s, vec); + auto const vec_size = serializeVectorMeta(s, vec); + constructVectorData(vec_size, vec); if (!s.isUnpacking()) { for (bool elt : vec) { diff --git a/tests/unit/test_vector_serializer.cc b/tests/unit/test_vector_serializer.cc new file mode 100644 index 00000000..e4fa4766 --- /dev/null +++ b/tests/unit/test_vector_serializer.cc @@ -0,0 +1,180 @@ +/* +//@HEADER +// ***************************************************************************** +// +// test_vector_serialize.cc +// DARMA Toolkit v. 1.0.0 +// DARMA/checkpoint => Serialization Library +// +// Copyright 2019 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact darma@sandia.gov +// +// ***************************************************************************** +//@HEADER +*/ + +#include +#include "test_harness.h" +#include + +namespace checkpoint { namespace tests { namespace unit { + +struct VectorTest : TestHarness { }; + +struct DefCtor { + static constexpr int val_ctor = 101; + + int i; + + DefCtor() { i = val_ctor; }; + + template + void serialize(Serializer& s) { + s | i; + } +}; + +constexpr int DefCtor::val_ctor; + +TEST_F(VectorTest, test_vector_default_ctor) { + std::vector dcs{DefCtor{}, DefCtor{}, DefCtor{}}; + auto ret = serialize>(dcs); + auto deser = deserialize>(ret->getBuffer()); + + for (auto const& dc : *deser) { + EXPECT_EQ(dc.i, DefCtor::val_ctor); + } +} + +struct IntrReconstruct { + static constexpr int val_ctor = 2; + static constexpr int val_reconstruct = 102; + + int i; + + IntrReconstruct() = delete; + explicit IntrReconstruct(int ii) : i{ii} { } + + static IntrReconstruct& reconstruct(void* buf) { + auto b = new (buf) IntrReconstruct{val_reconstruct}; + return *b; + } + + template + void serialize(Serializer& s) { + s | i; + } +}; + +constexpr int IntrReconstruct::val_ctor; +constexpr int IntrReconstruct::val_reconstruct; + +TEST_F(VectorTest, test_vector_intr_reconstruct) { + std::vector irs{ + IntrReconstruct{IntrReconstruct::val_ctor}, + IntrReconstruct{IntrReconstruct::val_ctor}, + IntrReconstruct{IntrReconstruct::val_ctor}}; + auto ret = serialize>(irs); + auto deser = deserialize>(ret->getBuffer()); + + for (auto const& ir : *deser) { + EXPECT_EQ(ir.i, IntrReconstruct::val_ctor); + } +} + +struct NonIntrReconstruct { + static constexpr int val_ctor = 3; + static constexpr int val_reconstruct = 103; + + int i; + + NonIntrReconstruct() = delete; + explicit NonIntrReconstruct(int ii) : i{ii} { } + + template + void serialize(Serializer& s) { + s | i; + } +}; + +constexpr int NonIntrReconstruct::val_ctor; +constexpr int NonIntrReconstruct::val_reconstruct; + +void reconstruct(NonIntrReconstruct*& nir, void* buf) { + nir = new (buf) NonIntrReconstruct{NonIntrReconstruct::val_reconstruct}; +} + +TEST_F(VectorTest, test_vector_non_intr_reconstruct) { + std::vector nirs{ + NonIntrReconstruct{NonIntrReconstruct::val_ctor}, + NonIntrReconstruct{NonIntrReconstruct::val_ctor}, + NonIntrReconstruct{NonIntrReconstruct::val_ctor}}; + auto ret = serialize>(nirs); + auto deser = deserialize>(ret->getBuffer()); + + for (auto const& nir : *deser) { + EXPECT_EQ(nir.i, NonIntrReconstruct::val_ctor); + } +} + +struct TaggedCtor { + static constexpr int val_ctor = 4; + static constexpr int val_tagged_ctor = 104; + + int i; + + TaggedCtor() = delete; + explicit TaggedCtor(int ii) : i{ii} { } + explicit TaggedCtor(SERIALIZE_CONSTRUCT_TAG) : i{val_tagged_ctor} { } + + template + void serialize(Serializer& s) { + s | i; + } +}; + +constexpr int TaggedCtor::val_ctor; +constexpr int TaggedCtor::val_tagged_ctor; + +TEST_F(VectorTest, test_vector_tagged_ctor) { + std::vector tcs{ + TaggedCtor{TaggedCtor::val_ctor}, TaggedCtor{TaggedCtor::val_ctor}, + TaggedCtor{TaggedCtor::val_ctor}}; + auto ret = serialize>(tcs); + auto deser = deserialize>(ret->getBuffer()); + + for (auto const& tc : *deser) { + EXPECT_EQ(tc.i, TaggedCtor::val_ctor); + } +} + +}}}