From 5d38b22e2f37d23408cc8c6f3743c733f2691264 Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Wed, 16 Nov 2022 11:02:22 -0700 Subject: [PATCH 01/12] Add stream_serializer --- src/checkpoint/checkpoint_api.h | 9 ++ src/checkpoint/checkpoint_api.impl.h | 25 ++++ .../serializers/serializers_headers.h | 1 + .../serializers/stream_serializer.h | 111 ++++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 src/checkpoint/serializers/stream_serializer.h diff --git a/src/checkpoint/checkpoint_api.h b/src/checkpoint/checkpoint_api.h index 4198d587..b512920f 100644 --- a/src/checkpoint/checkpoint_api.h +++ b/src/checkpoint/checkpoint_api.h @@ -217,6 +217,15 @@ std::unique_ptr deserializeFromFile(std::string const& file); template void deserializeInPlaceFromFile(std::string const& file, T* buf); + +template +void serializeToStream(T& target, StreamT& stream); +template +std::unique_ptr deserializeFromStream(StreamT& stream); +template +void deserializeInPlaceFromStream(StreamT& stream, T* buf); + + } /* end namespace checkpoint */ #endif /*INCLUDED_CHECKPOINT_CHECKPOINT_API_H*/ diff --git a/src/checkpoint/checkpoint_api.impl.h b/src/checkpoint/checkpoint_api.impl.h index e649c5dd..4ac39be8 100644 --- a/src/checkpoint/checkpoint_api.impl.h +++ b/src/checkpoint/checkpoint_api.impl.h @@ -123,6 +123,31 @@ void deserializeInPlaceFromFile(std::string const& file, T* t) { ); } +template +void serializeToStream(T& target, StreamT& stream) { + auto len = getSize(target); + dispatch::Standard::pack>( + target, len, eSerializationMode::Packing, stream + ); +} + +template +std::unique_ptr deserializeFromStream(StreamT& stream) { + auto mem = dispatch::Standard::allocate(); + T* t_buf = dispatch::Standard::construct(mem); + auto t = dispatch::Standard::unpack>( + t_buf, eSerializationMode::Unpacking, stream + ); + return std::unique_ptr(t); +} + +template +void deserializeInPlaceFromStream(StreamT& stream, T* t) { + dispatch::Standard::unpack>( + t, eSerializationMode::Unpacking, stream + ); +} + } /* end namespace checkpoint */ #endif /*INCLUDED_CHECKPOINT_CHECKPOINT_API_IMPL_H*/ diff --git a/src/checkpoint/serializers/serializers_headers.h b/src/checkpoint/serializers/serializers_headers.h index bc6fda64..ff1ff377 100644 --- a/src/checkpoint/serializers/serializers_headers.h +++ b/src/checkpoint/serializers/serializers_headers.h @@ -50,6 +50,7 @@ #include "checkpoint/serializers/sizer.h" #include "checkpoint/serializers/packer.h" #include "checkpoint/serializers/unpacker.h" +#include "checkpoint/serializers/stream_serializer.h" #define checkpoint_serializer_variadic_args() \ checkpoint::Footprinter, \ diff --git a/src/checkpoint/serializers/stream_serializer.h b/src/checkpoint/serializers/stream_serializer.h new file mode 100644 index 00000000..54a8c37a --- /dev/null +++ b/src/checkpoint/serializers/stream_serializer.h @@ -0,0 +1,111 @@ +/* +//@HEADER +// ***************************************************************************** +// +// memory_serializer.h +// 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 +*/ + +#if !defined INCLUDED_CHECKPOINT_SERIALIZERS_STREAM_SERIALIZER_H +#define INCLUDED_CHECKPOINT_SERIALIZERS_STREAM_SERIALIZER_H + +#include "checkpoint/common.h" +#include "checkpoint/serializers/base_serializer.h" + +//Used to always static_assert false without compilation issues. +template struct always_false : std::false_type {}; + +namespace checkpoint { + +template +struct StreamSerializer : Serializer { + //This really doesn't expect to be initialized like this, disabling until someone yells at me. + /*explicit StreamSerializer(ModeType const& in_mode) + : Serializer(in_mode) + { + }*/ + + StreamSerializer(ModeType const& in_mode, StreamT& stream) + : Serializer(in_mode), stream(stream) + { + if constexpr ( mode == eSerializationMode::Packing ) { + start_position = stream.tellp(); + } else if constexpr ( mode == eSerializationMode::Unpacking ){ + start_position = stream.tellg(); + } else static_assert(always_false::value, "StreamSerializer can only be used for packing and unpacking"); + } + + StreamSerializer(SerialSizeType in_size, ModeType const& in_mode, StreamT& stream) + : StreamSerializer(in_mode, stream) {} + + void contiguousBytes(void* ptr, SerialSizeType size, SerialSizeType num_elms){ + SerialSizeType const len = size * num_elms; + if constexpr ( mode == eSerializationMode::Packing ){ + stream.write((char*)ptr, len); + } else if constexpr ( mode == eSerializationMode::Unpacking ){ + stream.read((char*)ptr, len); + } else static_assert(always_false::value, "StreamSerializer can only be used for packing and unpacking"); + } + + SerialSizeType usedBufferSize() { + SerialSizeType current_position; + + if constexpr ( mode == eSerializationMode::Packing ){ + current_position = static_cast(stream.tellp()); + } else if constexpr ( mode == eSerializationMode::Unpacking ){ + current_position = static_cast(stream.tellg()); + } else static_assert(always_false::value, "StreamSerializer can only be used for packing and unpacking"); + + return current_position - start_position; + } + + //TODO: What is the use of this? Is it important for some usecase? + void extractPackedBuffer(){ + return; + } + +protected: + StreamT& stream; + + //Initial position of streams, used for calculating in/out size + SerialSizeType start_position = 0; +}; + +} /* end namespace checkpoint */ + +#endif /*INCLUDED_CHECKPOINT_SERIALIZERS_STREAM_SERIALIZER_H*/ From bc43281e27eb62b50c4f41085c4005068ebfc5bc Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Mon, 21 Nov 2022 11:15:52 -0700 Subject: [PATCH 02/12] Update documentation --- src/checkpoint/checkpoint_api.h | 37 ++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/checkpoint/checkpoint_api.h b/src/checkpoint/checkpoint_api.h index b512920f..0234bd9a 100644 --- a/src/checkpoint/checkpoint_api.h +++ b/src/checkpoint/checkpoint_api.h @@ -217,11 +217,46 @@ std::unique_ptr deserializeFromFile(std::string const& file); template void deserializeInPlaceFromFile(std::string const& file, T* buf); - +/** + * \brief Serialize \c T to a stream + * + * Byte-serializes \c T to stream. Handling of any errors during writing + * to the stream will be handled by the stream itself, e.g. any exceptions + * or status bits to check will depend on stream type. + * + * \param[in] target the \c T to serialize + * \param[in] stream to serialize into, with tellp and write functions. + */ template void serializeToStream(T& target, StreamT& stream); + +/** + * \brief De-serialize and reify \c T from a stream + * + * De-serializes an object recursively by first invoking the reconstruction + * strategy and then \c serialize functions/methods recursively to rebuild the + * state of the object as serialized. During reconstruction, based on trait + * detection, \c T will either be default constructed or reconstructed based on + * a user-defined reconstruct method. + * + * \param[in] stream the stream to read with bytes for \c T, with tellg and read functions + * + * \return unique pointer to the new object \c T + */ template std::unique_ptr deserializeFromStream(StreamT& stream); + +/** + * \brief De-serialize and reify \c T from a stream in place on an existing + * pointer to \c T + * + * De-serializes an object recursively by invoking the \c serialize + * functions/methods recursively to rebuild the state of the object as + * serialized. + * + * \param[in] stream the stream to read with bytes for \c T, with tellg and read functions + * \param[in] t a valid, constructed \c T to deserialize into + */ template void deserializeInPlaceFromStream(StreamT& stream, T* buf); From c672ca9c77b1184c57bd2cb1348794c7453af026 Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Thu, 12 Jan 2023 14:17:00 -0700 Subject: [PATCH 03/12] Add stream serializer tests Also removed deprecated Kokkos header includes. --- src/checkpoint/container/view_equality.h | 4 - tests/unit/test_commons.h | 3 - tests/unit/test_serialize_stream.cc | 188 +++++++++++++++++++++++ 3 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 tests/unit/test_serialize_stream.cc diff --git a/src/checkpoint/container/view_equality.h b/src/checkpoint/container/view_equality.h index 61b95ca4..eb18a468 100644 --- a/src/checkpoint/container/view_equality.h +++ b/src/checkpoint/container/view_equality.h @@ -53,10 +53,6 @@ #if KOKKOS_ENABLED_CHECKPOINT #include -#include -#include -#include -#include #include #include diff --git a/tests/unit/test_commons.h b/tests/unit/test_commons.h index 6d5fe1d6..3424dc46 100644 --- a/tests/unit/test_commons.h +++ b/tests/unit/test_commons.h @@ -51,9 +51,6 @@ #if KOKKOS_ENABLED_CHECKPOINT #include -#include -#include -#include #include diff --git a/tests/unit/test_serialize_stream.cc b/tests/unit/test_serialize_stream.cc new file mode 100644 index 00000000..c96c542b --- /dev/null +++ b/tests/unit/test_serialize_stream.cc @@ -0,0 +1,188 @@ +/* +//@HEADER +// ***************************************************************************** +// +// test_serialize_stream.cc +// 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 "test_harness.h" + +#include +#include + +#include + +#include +#include + +namespace checkpoint { namespace tests { namespace unit { + +template +struct TestSerializeStream : TestHarness { }; +template +struct TestSerializeStreamInPlace : TestHarness { }; + +TYPED_TEST_CASE_P(TestSerializeStream); +TYPED_TEST_CASE_P(TestSerializeStreamInPlace); + +static constexpr int const u_val = 934; + +struct UserObjectA { + UserObjectA() = default; + explicit UserObjectA(int in_u) : u_(in_u) { } + + void check() { + EXPECT_EQ(u_, u_val); + } + + template + void serialize(SerializerT& s) { + s | u_; + } + + int u_; +}; + +struct UserObjectB { + UserObjectB() = default; + explicit UserObjectB(int in_u) : len_(in_u) { + u_.resize(len_); + for (int i = 0; i < len_; i++) { + u_[i] = u_val+i; + } + } + + void check() { + EXPECT_EQ(u_.size(), static_cast(len_)); + int i = 0; + for (auto&& elm : u_) { + EXPECT_EQ(elm, u_val+i++); + } + } + + template + void serialize(SerializerT& s) { + s | u_; + s | len_; + } + + std::vector u_; + int len_ = 0; +}; + +struct UserObjectC { + UserObjectC() = default; + explicit UserObjectC(int in_u) : u_(std::to_string(in_u)) { } + + void check() { + EXPECT_EQ(u_, std::to_string(u_val)); + } + + template + void serialize(SerializerT& s) { + s | u_; + } + + std::string u_ = {}; +}; + +/* + * General test of serialization/deserialization for input object types + */ + +TYPED_TEST_P(TestSerializeStream, test_serialize_stream_multi) { + using TestType = TypeParam; + + TestType in(u_val); + in.check(); + + auto len = checkpoint::getSize(in); + printf("len=%lu\n", len); + + std::ofstream ostream; + ostream.open("hello.txt"); + checkpoint::serializeToStream(in, ostream); + ostream.close(); + + std::ifstream istream; + istream.open("hello.txt"); + auto out = checkpoint::deserializeFromStream(istream); + istream.close(); + + out->check(); +} + +TYPED_TEST_P(TestSerializeStreamInPlace, test_serialize_stream_multi_in_place) { + using TestType = TypeParam; + + TestType in(u_val); + in.check(); + + auto len = checkpoint::getSize(in); + printf("len=%lu\n", len); + + std::ofstream ostream; + ostream.open("hello.txt"); + checkpoint::serializeToStream(in, ostream); + ostream.close(); + + + TestType out{}; + + std::ifstream istream; + istream.open("hello.txt"); + checkpoint::deserializeInPlaceFromStream(istream, &out); + istream.close(); + + out.check(); +} + +using ConstructTypes = ::testing::Types< + UserObjectA, + UserObjectB, + UserObjectC +>; + +REGISTER_TYPED_TEST_CASE_P(TestSerializeStream, test_serialize_stream_multi); +REGISTER_TYPED_TEST_CASE_P(TestSerializeStreamInPlace, test_serialize_stream_multi_in_place); + +INSTANTIATE_TYPED_TEST_CASE_P(test_file, TestSerializeStream, ConstructTypes, ); +INSTANTIATE_TYPED_TEST_CASE_P(test_file_in_place, TestSerializeStreamInPlace, ConstructTypes, ); + +}}} // end namespace checkpoint::tests::unit From 7c599f428afea69ad9c391e9ad17fe3b8e33e793 Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Thu, 12 Jan 2023 14:18:38 -0700 Subject: [PATCH 04/12] Fix header comment --- src/checkpoint/serializers/stream_serializer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/checkpoint/serializers/stream_serializer.h b/src/checkpoint/serializers/stream_serializer.h index 54a8c37a..811c3a1f 100644 --- a/src/checkpoint/serializers/stream_serializer.h +++ b/src/checkpoint/serializers/stream_serializer.h @@ -2,7 +2,7 @@ //@HEADER // ***************************************************************************** // -// memory_serializer.h +// stream_serializer.h // DARMA/checkpoint => Serialization Library // // Copyright 2019 National Technology & Engineering Solutions of Sandia, LLC From 7bd24cd39e3772195b61bb2cb2579adbb4eb26ce Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Thu, 26 Jan 2023 14:18:54 -0700 Subject: [PATCH 05/12] Add optional user traits for serializers. --- src/checkpoint/checkpoint_api.h | 26 ++++----- src/checkpoint/checkpoint_api.impl.h | 54 +++++++++---------- src/checkpoint/container/atomic_serialize.h | 2 +- src/checkpoint/container/function_serialize.h | 5 +- .../kokkos_unordered_map_serialize.h | 4 +- src/checkpoint/container/list_serialize.h | 6 +-- src/checkpoint/container/map_serialize.h | 4 +- src/checkpoint/container/queue_serialize.h | 5 +- src/checkpoint/container/raw_ptr_serialize.h | 6 +-- .../container/shared_ptr_serialize.h | 4 +- src/checkpoint/container/thread_serialize.h | 2 +- src/checkpoint/container/vector_serialize.h | 10 ++-- src/checkpoint/dispatch/dispatch.h | 8 +-- src/checkpoint/dispatch/dispatch.impl.h | 20 +++---- .../dispatch/dispatch_serializer_nonbyte.h | 4 +- .../dispatch/vrt/virtual_serialize.h | 4 +- src/checkpoint/serializers/base_serializer.h | 26 +++++++++ src/checkpoint/serializers/footprinter.h | 21 +++++++- .../serializers/memory_serializer.h | 9 ++-- src/checkpoint/serializers/packer.h | 4 +- src/checkpoint/serializers/packer.impl.h | 38 ++++++------- .../serializers/serializers_headers.h | 4 +- src/checkpoint/serializers/sizer.cc | 10 ---- src/checkpoint/serializers/sizer.h | 16 ++++-- .../serializers/stream_serializer.h | 14 ++--- src/checkpoint/serializers/unpacker.h | 4 +- src/checkpoint/serializers/unpacker.impl.h | 24 ++++----- src/checkpoint/traits/serializable_traits.h | 2 +- tests/unit/test_footprinter.cc | 2 +- tests/unit/test_traversal.cc | 8 +-- 30 files changed, 192 insertions(+), 154 deletions(-) diff --git a/src/checkpoint/checkpoint_api.h b/src/checkpoint/checkpoint_api.h index 0234bd9a..37e91d78 100644 --- a/src/checkpoint/checkpoint_api.h +++ b/src/checkpoint/checkpoint_api.h @@ -78,7 +78,7 @@ using SerializedReturnType = std::unique_ptr; * \return a \c std::unique_ptr to a \c SerializedInfo containing the buffer * with serialized data and the size of the buffer */ -template +template SerializedReturnType serialize(T& target, BufferCallbackType fn = nullptr); /** @@ -101,7 +101,7 @@ SerializedReturnType serialize(T& target, BufferCallbackType fn = nullptr); * * \return a pointer to the newly reified \c T based on bytes in \c buf */ -template +template T* deserialize(char* buf, char* object_buf); /** @@ -118,7 +118,7 @@ T* deserialize(char* buf, char* object_buf); * * \return a unique pointer to the newly reified \c T based on bytes in \c buf */ -template +template std::unique_ptr deserialize(char* buf); /** @@ -132,7 +132,7 @@ std::unique_ptr deserialize(char* buf); * \param[in] t a valid pointer to a \c T that has been user-allocated and * constructed */ -template +template void deserializeInPlace(char* buf, T* t); /** @@ -143,7 +143,7 @@ void deserializeInPlace(char* buf, T* t); * * \return a unique pointer to \c T that must be deallocated */ -template +template std::unique_ptr deserialize(SerializedReturnType&& in); /** @@ -153,7 +153,7 @@ std::unique_ptr deserialize(SerializedReturnType&& in); * * \return number of bytes for the \c target */ -template +template std::size_t getSize(T& target); /** @@ -170,7 +170,7 @@ std::size_t getSize(T& target); * * \return memory footprint of the \c target */ -template +template std::size_t getMemoryFootprint(T& target, std::size_t size_offset = 0); /** @@ -184,7 +184,7 @@ std::size_t getMemoryFootprint(T& target, std::size_t size_offset = 0); * \param[in] target the \c T to serialize * \param[in] file name of the file to create */ -template +template void serializeToFile(T& target, std::string const& file); /** @@ -200,7 +200,7 @@ void serializeToFile(T& target, std::string const& file); * * \return unique pointer to the new object \c T */ -template +template std::unique_ptr deserializeFromFile(std::string const& file); /** @@ -214,7 +214,7 @@ std::unique_ptr deserializeFromFile(std::string const& file); * \param[in] file the filename to read with bytes for \c T * \param[in] t a valid, constructed \c T to deserialize into */ -template +template void deserializeInPlaceFromFile(std::string const& file, T* buf); /** @@ -227,7 +227,7 @@ void deserializeInPlaceFromFile(std::string const& file, T* buf); * \param[in] target the \c T to serialize * \param[in] stream to serialize into, with tellp and write functions. */ -template +template void serializeToStream(T& target, StreamT& stream); /** @@ -243,7 +243,7 @@ void serializeToStream(T& target, StreamT& stream); * * \return unique pointer to the new object \c T */ -template +template std::unique_ptr deserializeFromStream(StreamT& stream); /** @@ -257,7 +257,7 @@ std::unique_ptr deserializeFromStream(StreamT& stream); * \param[in] stream the stream to read with bytes for \c T, with tellg and read functions * \param[in] t a valid, constructed \c T to deserialize into */ -template +template void deserializeInPlaceFromStream(StreamT& stream, T* buf); diff --git a/src/checkpoint/checkpoint_api.impl.h b/src/checkpoint/checkpoint_api.impl.h index 4ac39be8..82841b50 100644 --- a/src/checkpoint/checkpoint_api.impl.h +++ b/src/checkpoint/checkpoint_api.impl.h @@ -53,9 +53,9 @@ namespace checkpoint { -template +template SerializedReturnType serialize(T& target, BufferCallbackType fn) { - auto ret = dispatch::serializeType(target, fn); + auto ret = dispatch::serializeType(target, fn); auto& buf = std::get<0>(ret); std::unique_ptr base_ptr( static_cast(buf.release()) @@ -63,87 +63,87 @@ SerializedReturnType serialize(T& target, BufferCallbackType fn) { return base_ptr; } -template +template T* deserialize(char* buf, char* object_buf) { - return dispatch::deserializeType(buf, object_buf); + return dispatch::deserializeType(buf, object_buf); } -template +template std::unique_ptr deserialize(char* buf) { - auto t = dispatch::deserializeType(buf); + auto t = dispatch::deserializeType(buf); return std::unique_ptr(t); } -template +template std::unique_ptr deserialize(SerializedReturnType&& in) { - auto t = dispatch::deserializeType(in->getBuffer()); + auto t = dispatch::deserializeType(in->getBuffer()); return std::unique_ptr(t); } -template +template void deserializeInPlace(char* buf, T* t) { - return dispatch::deserializeType(dispatch::InPlaceTag{}, buf, t); + return dispatch::deserializeType(dispatch::InPlaceTag{}, buf, t); } -template +template std::size_t getSize(T& target) { - return dispatch::Standard::size(target); + return dispatch::Standard::size>(target); } -template +template std::size_t getMemoryFootprint(T& target, std::size_t size_offset) { return size_offset + std::max( - dispatch::Standard::footprint(target), + dispatch::Standard::footprint>(target), sizeof(target) ); } -template +template void serializeToFile(T& target, std::string const& file) { - auto len = getSize(target); - dispatch::Standard::pack>( + auto len = getSize(target); + dispatch::Standard::pack>( target, len, buffer::IOBuffer::WriteToFileTag{}, len, file ); } -template +template std::unique_ptr deserializeFromFile(std::string const& file) { auto mem = dispatch::Standard::allocate(); T* t_buf = dispatch::Standard::construct(mem); - auto t = dispatch::Standard::unpack>( + auto t = dispatch::Standard::unpack>( t_buf, buffer::IOBuffer::ReadFromFileTag{}, file ); return std::unique_ptr(t); } -template +template void deserializeInPlaceFromFile(std::string const& file, T* t) { - dispatch::Standard::unpack>( + dispatch::Standard::unpack>( t, buffer::IOBuffer::ReadFromFileTag{}, file ); } -template +template void serializeToStream(T& target, StreamT& stream) { auto len = getSize(target); - dispatch::Standard::pack>( + dispatch::Standard::pack>( target, len, eSerializationMode::Packing, stream ); } -template +template std::unique_ptr deserializeFromStream(StreamT& stream) { auto mem = dispatch::Standard::allocate(); T* t_buf = dispatch::Standard::construct(mem); - auto t = dispatch::Standard::unpack>( + auto t = dispatch::Standard::unpack>( t_buf, eSerializationMode::Unpacking, stream ); return std::unique_ptr(t); } -template +template void deserializeInPlaceFromStream(StreamT& stream, T* t) { - dispatch::Standard::unpack>( + dispatch::Standard::unpack>( t, eSerializationMode::Unpacking, stream ); } diff --git a/src/checkpoint/container/atomic_serialize.h b/src/checkpoint/container/atomic_serialize.h index b639712d..53b8b97b 100644 --- a/src/checkpoint/container/atomic_serialize.h +++ b/src/checkpoint/container/atomic_serialize.h @@ -54,7 +54,7 @@ template < typename SerializerT, typename T, typename = std::enable_if_t< - std::is_same::value + checkpoint::is_footprinter::value > > void serialize(SerializerT& s, const std::atomic& atomic) { diff --git a/src/checkpoint/container/function_serialize.h b/src/checkpoint/container/function_serialize.h index aac19ab5..168e447f 100644 --- a/src/checkpoint/container/function_serialize.h +++ b/src/checkpoint/container/function_serialize.h @@ -68,9 +68,8 @@ template < typename Res, typename... ArgTypes, typename = std::enable_if_t< - std::is_same< - SerializerT, - checkpoint::Footprinter + checkpoint::is_footprinter< + SerializerT >::value > > diff --git a/src/checkpoint/container/kokkos_unordered_map_serialize.h b/src/checkpoint/container/kokkos_unordered_map_serialize.h index 6d230872..d2b72751 100644 --- a/src/checkpoint/container/kokkos_unordered_map_serialize.h +++ b/src/checkpoint/container/kokkos_unordered_map_serialize.h @@ -117,7 +117,7 @@ template < typename Hasher, typename EqualTo > typename std::enable_if_t< - not std::is_same::value, void + not checkpoint::is_footprinter::value, void > serialize( SerializerT& s, Kokkos::UnorderedMap& map @@ -140,7 +140,7 @@ template < typename Hasher, typename EqualTo > typename std::enable_if_t< - std::is_same::value, void + checkpoint::is_footprinter::value, void > serialize( SerializerT& s, Kokkos::UnorderedMap& map diff --git a/src/checkpoint/container/list_serialize.h b/src/checkpoint/container/list_serialize.h index c1bda13d..5855ce82 100644 --- a/src/checkpoint/container/list_serialize.h +++ b/src/checkpoint/container/list_serialize.h @@ -56,7 +56,7 @@ namespace checkpoint { template inline typename std::enable_if_t< - not std::is_same::value, void + not checkpoint::is_footprinter::value, void > deserializeOrderedElems( Serializer& s, ContainerT& cont, typename ContainerT::size_type size, @@ -76,7 +76,7 @@ deserializeOrderedElems( template inline typename std::enable_if_t< - not std::is_same::value, void + not checkpoint::is_footprinter::value, void > deserializeOrderedElems( Serializer& s, ContainerT& cont, typename ContainerT::size_type size, @@ -96,7 +96,7 @@ deserializeOrderedElems( template inline typename std::enable_if_t< - std::is_same::value, void + checkpoint::is_footprinter::value, void > deserializeOrderedElems( Serializer& s, ContainerT& cont, typename ContainerT::size_type size diff --git a/src/checkpoint/container/map_serialize.h b/src/checkpoint/container/map_serialize.h index 8ace2172..f663567e 100644 --- a/src/checkpoint/container/map_serialize.h +++ b/src/checkpoint/container/map_serialize.h @@ -58,7 +58,7 @@ namespace checkpoint { template inline typename std::enable_if_t< - not std::is_same::value, + not checkpoint::is_footprinter::value, void > deserializeEmplaceElems( Serializer& s, ContainerT& cont, typename ContainerT::size_type size @@ -77,7 +77,7 @@ inline typename std::enable_if_t< template inline typename std::enable_if_t< - std::is_same::value, + checkpoint::is_footprinter::value, void > deserializeEmplaceElems( Serializer& s, ContainerT& cont, typename ContainerT::size_type size diff --git a/src/checkpoint/container/queue_serialize.h b/src/checkpoint/container/queue_serialize.h index a1e88db2..3088b48c 100644 --- a/src/checkpoint/container/queue_serialize.h +++ b/src/checkpoint/container/queue_serialize.h @@ -70,9 +70,8 @@ template < typename SerializerT, typename Q, typename = std::enable_if_t< - std::is_same< - SerializerT, - checkpoint::Footprinter + checkpoint::is_footprinter< + SerializerT >::value > > diff --git a/src/checkpoint/container/raw_ptr_serialize.h b/src/checkpoint/container/raw_ptr_serialize.h index be83cfb5..3e096069 100644 --- a/src/checkpoint/container/raw_ptr_serialize.h +++ b/src/checkpoint/container/raw_ptr_serialize.h @@ -62,8 +62,8 @@ template < typename T, typename = std::enable_if_t< std::is_same< - SerializerT, - checkpoint::Footprinter + checkpoint::Footprinter<>, + SerializerT >::value > > @@ -95,7 +95,7 @@ void serializeRawPtr(SerializerT& s, void* ptr) { #define CHECKPOINT_FOOTPRINT_PIMPL_WITH_SIZEOF_PTR(PIMPL_TYPE) \ template < \ typename SerializerT, \ - typename = std::enable_if_t< std::is_same::value > \ + typename = std::enable_if_t< checkpoint::is_footprinter::value > \ > \ void serialize(SerializerT &s, PIMPL_TYPE *t) { \ s.countBytes(t); \ diff --git a/src/checkpoint/container/shared_ptr_serialize.h b/src/checkpoint/container/shared_ptr_serialize.h index a2554f02..31efd331 100644 --- a/src/checkpoint/container/shared_ptr_serialize.h +++ b/src/checkpoint/container/shared_ptr_serialize.h @@ -53,8 +53,8 @@ template < typename T, typename = std::enable_if_t< std::is_same< - SerializerT, - checkpoint::Footprinter + checkpoint::Footprinter<>, + SerializerT >::value > > diff --git a/src/checkpoint/container/thread_serialize.h b/src/checkpoint/container/thread_serialize.h index 5ecefc85..87765906 100644 --- a/src/checkpoint/container/thread_serialize.h +++ b/src/checkpoint/container/thread_serialize.h @@ -53,7 +53,7 @@ namespace checkpoint { template < typename SerializerT, typename = std::enable_if_t< - std::is_same::value + checkpoint::is_footprinter::value > > void serialize(SerializerT& s, const std::thread& t) { diff --git a/src/checkpoint/container/vector_serialize.h b/src/checkpoint/container/vector_serialize.h index 238e793d..ed8f109b 100644 --- a/src/checkpoint/container/vector_serialize.h +++ b/src/checkpoint/container/vector_serialize.h @@ -56,7 +56,7 @@ namespace checkpoint { template typename std::enable_if_t< - not std::is_same::value, SerialSizeType + not checkpoint::is_footprinter::value, SerialSizeType > serializeVectorMeta(SerializerT& s, std::vector& vec) { SerialSizeType vec_capacity = vec.capacity(); @@ -108,7 +108,7 @@ void constructVectorData( template typename std::enable_if_t< - not std::is_same::value, void + not checkpoint::is_footprinter::value, void > serialize(SerializerT& s, std::vector& vec) { auto const vec_size = serializeVectorMeta(s, vec); @@ -122,7 +122,7 @@ serialize(SerializerT& s, std::vector& vec) { template typename std::enable_if_t< - not std::is_same::value, void + not checkpoint::is_footprinter::value, void > serialize(SerializerT& s, std::vector& vec) { auto const vec_size = serializeVectorMeta(s, vec); @@ -146,7 +146,7 @@ serialize(SerializerT& s, std::vector& vec) { template typename std::enable_if_t< - std::is_same::value, void + checkpoint::is_footprinter::value, void > serialize(SerializerT& s, std::vector& vec) { s.countBytes(vec); @@ -156,7 +156,7 @@ serialize(SerializerT& s, std::vector& vec) { template typename std::enable_if_t< - std::is_same::value, void + checkpoint::is_footprinter::value, void > serialize(SerializerT& s, std::vector& vec) { s.countBytes(vec); diff --git a/src/checkpoint/dispatch/dispatch.h b/src/checkpoint/dispatch/dispatch.h index 3bf10e55..78b47874 100644 --- a/src/checkpoint/dispatch/dispatch.h +++ b/src/checkpoint/dispatch/dispatch.h @@ -188,7 +188,7 @@ struct Standard { static SerialByteType* allocate(); }; -template +template buffer::ImplReturnType packBuffer( T& target, SerialSizeType size, BufferObtainFnType fn ); @@ -196,13 +196,13 @@ buffer::ImplReturnType packBuffer( template inline void serializeArray(Serializer& s, T* array, SerialSizeType const len); -template +template buffer::ImplReturnType serializeType(T& target, BufferObtainFnType fn = nullptr); -template +template T* deserializeType(SerialByteType* data, SerialByteType* allocBuf = nullptr); -template +template void deserializeType(InPlaceTag, SerialByteType* data, T* t); template diff --git a/src/checkpoint/dispatch/dispatch.impl.h b/src/checkpoint/dispatch/dispatch.impl.h index 420d0577..ddb0e776 100644 --- a/src/checkpoint/dispatch/dispatch.impl.h +++ b/src/checkpoint/dispatch/dispatch.impl.h @@ -247,17 +247,17 @@ validatePackerBufferSize(PackerT const& p, SerialSizeType bufferSize) { } } -template +template buffer::ImplReturnType packBuffer(T& target, SerialSizeType size, BufferObtainFnType fn) { SerialByteType* user_buf = fn ? fn(size) : nullptr; if (user_buf == nullptr) { auto p = - Standard::pack>(target, size); + Standard::pack>(target, size); validatePackerBufferSize(p, size); return std::make_tuple(std::move(p.extractPackedBuffer()), size); } else { - auto p = Standard::pack>( + auto p = Standard::pack>( target, size, std::make_unique(user_buf, size) ); validatePackerBufferSize(p, size); @@ -265,26 +265,26 @@ packBuffer(T& target, SerialSizeType size, BufferObtainFnType fn) { } } -template +template buffer::ImplReturnType serializeType(T& target, BufferObtainFnType fn) { - auto len = Standard::size(target); + auto len = Standard::size>(target); debug_checkpoint("serializeType: len=%ld\n", len); - return packBuffer(target, len, fn); + return packBuffer(target, len, fn); } -template +template T* deserializeType(SerialByteType* data, SerialByteType* allocBuf) { auto mem = allocBuf ? allocBuf : Standard::allocate(); auto t_buf = std::unique_ptr(Standard::construct(mem)); T* traverser = - Standard::unpack>(t_buf.get(), data); + Standard::unpack>(t_buf.get(), data); t_buf.release(); return traverser; } -template +template void deserializeType(InPlaceTag, SerialByteType* data, T* t) { - Standard::unpack>(t, data); + Standard::unpack>(t, data); } }} /* end namespace checkpoint::dispatch */ diff --git a/src/checkpoint/dispatch/dispatch_serializer_nonbyte.h b/src/checkpoint/dispatch/dispatch_serializer_nonbyte.h index 5da80f9b..1739e4c9 100644 --- a/src/checkpoint/dispatch/dispatch_serializer_nonbyte.h +++ b/src/checkpoint/dispatch/dispatch_serializer_nonbyte.h @@ -91,7 +91,7 @@ struct SerializerDispatchNonByte { template using hasInSerialize = - typename std::enable_if::has_serialize_instrusive, T>::type; + typename std::enable_if::has_serialize_instrusive && !SerializableTraits::has_serialize_noninstrusive, T>::type; template using hasNoninSerialize = @@ -112,7 +112,7 @@ struct SerializerDispatchNonByte { template using justFootprint = typename std::enable_if< - std::is_same::value and + checkpoint::is_footprinter::value and not SerializableTraits::is_traversable and not std::is_enum::value, T diff --git a/src/checkpoint/dispatch/vrt/virtual_serialize.h b/src/checkpoint/dispatch/vrt/virtual_serialize.h index 426352e9..ad1b40cb 100644 --- a/src/checkpoint/dispatch/vrt/virtual_serialize.h +++ b/src/checkpoint/dispatch/vrt/virtual_serialize.h @@ -146,7 +146,7 @@ struct ReconstructAsVirtualIfNeeded< SerializerT, typename std::enable_if_t< dispatch::vrt::VirtualSerializeTraits::has_not_virtual_serialize and - not std::is_same::value + not checkpoint::is_footprinter::value > > { static T* apply(SerializerT& s, dispatch::vrt::TypeIdx entry) { @@ -162,7 +162,7 @@ struct ReconstructAsVirtualIfNeeded< SerializerT, typename std::enable_if_t< dispatch::vrt::VirtualSerializeTraits::has_not_virtual_serialize and - std::is_same::value + checkpoint::is_footprinter::value > > { static T* apply(SerializerT& s, dispatch::vrt::TypeIdx entry) { return nullptr; } diff --git a/src/checkpoint/serializers/base_serializer.h b/src/checkpoint/serializers/base_serializer.h index 723c0bde..352cf725 100644 --- a/src/checkpoint/serializers/base_serializer.h +++ b/src/checkpoint/serializers/base_serializer.h @@ -67,11 +67,29 @@ struct BasicDispatcher; } /* end namespace dispatch */ +namespace { + + template + struct checkTraitImpl : std::false_type {}; + + template + struct checkTraitImpl::value>*, Type, UserTrait, UserTraits...> : + std::true_type {}; + + template + struct checkTraitImpl::value>*, Type, UserTrait, UserTraits...> : + checkTraitImpl {}; + + template + struct checkTrait : checkTraitImpl {}; +} + /** * \struct Serializer * * \brief General base class for serialiers */ +template struct Serializer { using ModeType = eSerializationMode; @@ -203,11 +221,19 @@ struct Serializer { */ void setVirtualDisabled(bool val) { virtual_disabled_ = val; } + /*template + static constexpr bool hasTrait(void) { + return checkTrait::value; + }*/ + template + using hasTrait = checkTrait; + protected: ModeType cur_mode_ = ModeType::Invalid; /**< The current mode */ bool virtual_disabled_ = false; /**< Virtual serialization disabled */ }; + } /* end namespace checkpoint */ #endif /*INCLUDED_CHECKPOINT_SERIALIZERS_BASE_SERIALIZER_H*/ diff --git a/src/checkpoint/serializers/footprinter.h b/src/checkpoint/serializers/footprinter.h index 334f7b9f..44b57f4f 100644 --- a/src/checkpoint/serializers/footprinter.h +++ b/src/checkpoint/serializers/footprinter.h @@ -49,8 +49,11 @@ namespace checkpoint { -struct Footprinter : Serializer { - Footprinter() : Serializer(ModeType::Footprinting) { } +template +struct Footprinter : Serializer { + using ModeType = eSerializationMode; + + Footprinter() : Serializer(ModeType::Footprinting) { } SerialSizeType getMemoryFootprint() const { return num_bytes_; @@ -72,6 +75,20 @@ struct Footprinter : Serializer { SerialSizeType num_bytes_ = 0; }; +namespace { + template + struct is_footprinter_impl : public std::false_type {}; + + template + struct is_footprinter_impl> : std::true_type {}; + + template <> + struct is_footprinter_impl> : std::true_type {}; +} + +template +using is_footprinter = is_footprinter_impl>; + } /* end namespace checkpoint */ #endif /*INCLUDED_CHECKPOINT_SERIALIZERS_FOOTPRINTER_H*/ diff --git a/src/checkpoint/serializers/memory_serializer.h b/src/checkpoint/serializers/memory_serializer.h index 284da449..10af77d5 100644 --- a/src/checkpoint/serializers/memory_serializer.h +++ b/src/checkpoint/serializers/memory_serializer.h @@ -49,13 +49,16 @@ namespace checkpoint { -struct MemorySerializer : Serializer { +template +struct MemorySerializer : Serializer { + using ModeType = eSerializationMode; + MemorySerializer(ModeType const& in_mode, SerialByteType* in_start) - : Serializer(in_mode), start_(in_start), cur_(in_start) + : Serializer(in_mode), start_(in_start), cur_(in_start) { } explicit MemorySerializer(ModeType const& in_mode) - : Serializer(in_mode) + : Serializer(in_mode) { } SerialByteType* getBuffer() const { diff --git a/src/checkpoint/serializers/packer.h b/src/checkpoint/serializers/packer.h index 0502c64f..7e4f6f0f 100644 --- a/src/checkpoint/serializers/packer.h +++ b/src/checkpoint/serializers/packer.h @@ -53,8 +53,8 @@ namespace checkpoint { -template -struct PackerBuffer : MemorySerializer { +template +struct PackerBuffer : MemorySerializer { using BufferTPtrType = std::unique_ptr; using PackerReturnType = std::tuple; diff --git a/src/checkpoint/serializers/packer.impl.h b/src/checkpoint/serializers/packer.impl.h index dfffaf15..098eaa44 100644 --- a/src/checkpoint/serializers/packer.impl.h +++ b/src/checkpoint/serializers/packer.impl.h @@ -52,12 +52,12 @@ namespace checkpoint { -template -PackerBuffer::PackerBuffer(SerialSizeType const& in_size) - : MemorySerializer(ModeType::Packing), size_(in_size), +template +PackerBuffer::PackerBuffer(SerialSizeType const& in_size) + : MemorySerializer(eSerializationMode::Packing), size_(in_size), buffer_(std::make_unique(size_)) { - MemorySerializer::initializeBuffer(buffer_->getBuffer()); + MemorySerializer::initializeBuffer(buffer_->getBuffer()); debug_checkpoint( "PackerBuffer: size=%ld, start_=%p, cur_=%p\n", @@ -67,13 +67,13 @@ PackerBuffer::PackerBuffer(SerialSizeType const& in_size) ); } -template -PackerBuffer::PackerBuffer( +template +PackerBuffer::PackerBuffer( SerialSizeType const& in_size, BufferTPtrType buf_ptr -) : MemorySerializer(ModeType::Packing), size_(in_size), +) : MemorySerializer(eSerializationMode::Packing), size_(in_size), buffer_(std::move(buf_ptr)) { - MemorySerializer::initializeBuffer(buffer_->getBuffer()); + MemorySerializer::initializeBuffer(buffer_->getBuffer()); debug_checkpoint( "PackerBuffer: size=%ld, start_=%p, cur_=%p\n", @@ -83,15 +83,15 @@ PackerBuffer::PackerBuffer( ); } -template +template template -PackerBuffer::PackerBuffer( +PackerBuffer::PackerBuffer( SerialSizeType const& in_size, Args&&... args -) : MemorySerializer(ModeType::Packing), +) : MemorySerializer(eSerializationMode::Packing), size_(in_size), buffer_(std::make_unique(std::forward(args)...)) { - MemorySerializer::initializeBuffer(buffer_->getBuffer()); + MemorySerializer::initializeBuffer(buffer_->getBuffer()); debug_checkpoint( "PackerBuffer: size=%ld, start_=%p, cur_=%p\n", @@ -101,16 +101,16 @@ PackerBuffer::PackerBuffer( ); } -template -typename PackerBuffer::BufferTPtrType -PackerBuffer::extractPackedBuffer() { +template +typename PackerBuffer::BufferTPtrType +PackerBuffer::extractPackedBuffer() { auto ret = std::move(buffer_); buffer_ = nullptr; return ret; } -template -void PackerBuffer::contiguousBytes( +template +void PackerBuffer::contiguousBytes( void* ptr, SerialSizeType size, SerialSizeType num_elms ) { debug_checkpoint( @@ -132,8 +132,8 @@ void PackerBuffer::contiguousBytes( usedSize_ += len; } -template -SerialSizeType PackerBuffer::usedBufferSize() const { +template +SerialSizeType PackerBuffer::usedBufferSize() const { return usedSize_; } diff --git a/src/checkpoint/serializers/serializers_headers.h b/src/checkpoint/serializers/serializers_headers.h index ff1ff377..24358fea 100644 --- a/src/checkpoint/serializers/serializers_headers.h +++ b/src/checkpoint/serializers/serializers_headers.h @@ -53,12 +53,12 @@ #include "checkpoint/serializers/stream_serializer.h" #define checkpoint_serializer_variadic_args() \ - checkpoint::Footprinter, \ + checkpoint::Footprinter<>, \ checkpoint::Packer, \ checkpoint::PackerUserBuf, \ checkpoint::PackerIO, \ checkpoint::Unpacker, \ checkpoint::UnpackerIO, \ - checkpoint::Sizer \ + checkpoint::Sizer<> \ #endif /*INCLUDED_CHECKPOINT_SERIALIZERS_SERIALIZERS_HEADERS_H*/ diff --git a/src/checkpoint/serializers/sizer.cc b/src/checkpoint/serializers/sizer.cc index 43257212..92f4a3eb 100644 --- a/src/checkpoint/serializers/sizer.cc +++ b/src/checkpoint/serializers/sizer.cc @@ -47,14 +47,4 @@ namespace checkpoint { -Sizer::Sizer() : Serializer(ModeType::Sizing) { } - -SerialSizeType Sizer::getSize() const { - return num_bytes_; -} - -void Sizer::contiguousBytes(void*, SerialSizeType size, SerialSizeType num_elms) { - num_bytes_ += size * num_elms; -} - } /* end namespace checkpoint */ diff --git a/src/checkpoint/serializers/sizer.h b/src/checkpoint/serializers/sizer.h index 447319d7..3e5cd205 100644 --- a/src/checkpoint/serializers/sizer.h +++ b/src/checkpoint/serializers/sizer.h @@ -56,18 +56,24 @@ namespace checkpoint { * preprocessing pass before packing content so a properly sized buffer can be * allocated. */ -struct Sizer : Serializer { +template +struct Sizer : Serializer { + using ModeType = eSerializationMode; /** * \internal \brief Construct a sizer */ - Sizer(); + Sizer() : Serializer(ModeType::Sizing){ + + } /** * \brief Get the current size * * \return The current size */ - SerialSizeType getSize() const; + SerialSizeType getSize() const{ + return num_bytes_; + } /** * \brief Add contiguous bytes to the sizer @@ -76,7 +82,9 @@ struct Sizer : Serializer { * \param[in] size the number of bytes for each element * \param[in] num_elms the number of elements */ - void contiguousBytes(void* ptr, SerialSizeType size, SerialSizeType num_elms); + void contiguousBytes(void* ptr, SerialSizeType size, SerialSizeType num_elms){ + num_bytes_ += size*num_elms; + }; private: SerialSizeType num_bytes_ = 0; /**< Count of bytes */ diff --git a/src/checkpoint/serializers/stream_serializer.h b/src/checkpoint/serializers/stream_serializer.h index 811c3a1f..40adb399 100644 --- a/src/checkpoint/serializers/stream_serializer.h +++ b/src/checkpoint/serializers/stream_serializer.h @@ -52,16 +52,12 @@ template struct always_false : std::false_type {}; namespace checkpoint { -template -struct StreamSerializer : Serializer { - //This really doesn't expect to be initialized like this, disabling until someone yells at me. - /*explicit StreamSerializer(ModeType const& in_mode) - : Serializer(in_mode) - { - }*/ - +template +struct StreamSerializer : Serializer { + using ModeType = eSerializationMode; + StreamSerializer(ModeType const& in_mode, StreamT& stream) - : Serializer(in_mode), stream(stream) + : Serializer(in_mode), stream(stream) { if constexpr ( mode == eSerializationMode::Packing ) { start_position = stream.tellp(); diff --git a/src/checkpoint/serializers/unpacker.h b/src/checkpoint/serializers/unpacker.h index 77d34439..bda77b46 100644 --- a/src/checkpoint/serializers/unpacker.h +++ b/src/checkpoint/serializers/unpacker.h @@ -50,8 +50,8 @@ namespace checkpoint { -template -struct UnpackerBuffer : MemorySerializer { +template +struct UnpackerBuffer : MemorySerializer { using BufferPtrType = std::unique_ptr; explicit UnpackerBuffer(SerialByteType* buf); diff --git a/src/checkpoint/serializers/unpacker.impl.h b/src/checkpoint/serializers/unpacker.impl.h index c6c835c1..7e27364b 100644 --- a/src/checkpoint/serializers/unpacker.impl.h +++ b/src/checkpoint/serializers/unpacker.impl.h @@ -53,12 +53,12 @@ namespace checkpoint { -template -UnpackerBuffer::UnpackerBuffer(SerialByteType* buf) - : MemorySerializer(ModeType::Unpacking), +template +UnpackerBuffer::UnpackerBuffer(SerialByteType* buf) + : MemorySerializer(eSerializationMode::Unpacking), buffer_(std::make_unique(buf, 0)) { - MemorySerializer::initializeBuffer(buffer_->getBuffer()); + MemorySerializer::initializeBuffer(buffer_->getBuffer()); debug_checkpoint( "UnpackerBuffer: start_=%p, cur_=%p\n", @@ -67,13 +67,13 @@ UnpackerBuffer::UnpackerBuffer(SerialByteType* buf) ); } -template +template template -UnpackerBuffer::UnpackerBuffer(Args&&... args) - : MemorySerializer(ModeType::Unpacking), +UnpackerBuffer::UnpackerBuffer(Args&&... args) + : MemorySerializer(eSerializationMode::Unpacking), buffer_(std::make_unique(std::forward(args)...)) { - MemorySerializer::initializeBuffer(buffer_->getBuffer()); + MemorySerializer::initializeBuffer(buffer_->getBuffer()); debug_checkpoint( "UnpackerBuffer: start_=%p, cur_=%p\n", @@ -82,8 +82,8 @@ UnpackerBuffer::UnpackerBuffer(Args&&... args) ); } -template -void UnpackerBuffer::contiguousBytes( +template +void UnpackerBuffer::contiguousBytes( void* ptr, SerialSizeType size, SerialSizeType num_elms ) { debug_checkpoint( @@ -98,8 +98,8 @@ void UnpackerBuffer::contiguousBytes( usedSize_ += len; } -template -SerialSizeType UnpackerBuffer::usedBufferSize() const { +template +SerialSizeType UnpackerBuffer::usedBufferSize() const { return usedSize_; } diff --git a/src/checkpoint/traits/serializable_traits.h b/src/checkpoint/traits/serializable_traits.h index 44f625a5..363e5dbb 100644 --- a/src/checkpoint/traits/serializable_traits.h +++ b/src/checkpoint/traits/serializable_traits.h @@ -79,7 +79,7 @@ struct isByteCopyableImpl { template struct isByteCopyable : detail::isByteCopyableImpl::has_byteCopyTraitTrue {}; -template +template > struct SerializableTraits { /** * Start with detection of "serialize" overloads, intrusive and non-intrusive. diff --git a/tests/unit/test_footprinter.cc b/tests/unit/test_footprinter.cc index 25448c8f..2b8af8ab 100644 --- a/tests/unit/test_footprinter.cc +++ b/tests/unit/test_footprinter.cc @@ -107,7 +107,7 @@ struct TestDerived2 : TestBase { typename = std::enable_if_t< std::is_same< SerializerT, - checkpoint::Footprinter + checkpoint::Footprinter<> >::value > > diff --git a/tests/unit/test_traversal.cc b/tests/unit/test_traversal.cc index c12deaac..213bfc98 100644 --- a/tests/unit/test_traversal.cc +++ b/tests/unit/test_traversal.cc @@ -99,8 +99,8 @@ struct TestObject { TestObject2 obj2; }; -struct TestTraverse : checkpoint::Serializer { - TestTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { } +struct TestTraverse : checkpoint::Serializer<> { + TestTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { } void contiguousBytes(void* ptr, std::size_t size, std::size_t num_elms) { printf("size=%zu, num=%zu\n", size, num_elms); @@ -139,13 +139,13 @@ struct CustomDispatch> { } }; -struct TestTraverse2 : checkpoint::Serializer { +struct TestTraverse2 : checkpoint::Serializer<> { template using DispatcherType = CustomDispatch; void contiguousBytes(void* ptr, std::size_t size, std::size_t num_elms) { } - TestTraverse2() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { } + TestTraverse2() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { } }; From 7f6f3ba3227d632d4f73c670c8d01d43bb7b5d2a Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Tue, 7 Feb 2023 10:47:13 -0700 Subject: [PATCH 06/12] Simplify UserTraits API, add example --- examples/checkpoint_example_traversal.cc | 8 +- ...eckpoint_example_traversal_nonintrusive.cc | 10 +- examples/checkpoint_example_user_traits.cc | 15 +++ examples/checkpoint_example_user_traits.hpp | 44 +++++++ src/CMakeLists.txt | 2 +- src/checkpoint/checkpoint_api.h | 49 ++++++++ src/checkpoint/checkpoint_api.impl.h | 14 +++ src/checkpoint/serializers/base_serializer.h | 24 ---- src/checkpoint/traits/user_traits.h | 108 ++++++++++++++++++ 9 files changed, 240 insertions(+), 34 deletions(-) create mode 100644 examples/checkpoint_example_user_traits.cc create mode 100644 examples/checkpoint_example_user_traits.hpp create mode 100644 src/checkpoint/traits/user_traits.h diff --git a/examples/checkpoint_example_traversal.cc b/examples/checkpoint_example_traversal.cc index 1660af6d..00d305db 100644 --- a/examples/checkpoint_example_traversal.cc +++ b/examples/checkpoint_example_traversal.cc @@ -80,8 +80,8 @@ struct TestObject { }}} // end namespace magistrate::intrusive::examples /// Custom traverser for printing raw bytes -struct PrintBytesTraverse : checkpoint::Serializer { - PrintBytesTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { } +struct PrintBytesTraverse : checkpoint::Serializer<> { + PrintBytesTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { } void contiguousBytes(void* ptr, std::size_t size, std::size_t num_elms) { printf("PrintBytesTraverse: size=%zu, num_elms=%zu\n", size, num_elms); @@ -125,11 +125,11 @@ struct CustomDispatch> { }; /// Custom traverser for printing typed ranges -struct TypedTraverse : checkpoint::Serializer { +struct TypedTraverse : checkpoint::Serializer<> { template using DispatcherType = CustomDispatch; - TypedTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { } + TypedTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { } template void contiguousTyped(SerializerT&, T*, std::size_t num_elms) { diff --git a/examples/checkpoint_example_traversal_nonintrusive.cc b/examples/checkpoint_example_traversal_nonintrusive.cc index 7b22157b..3c8ef9b7 100644 --- a/examples/checkpoint_example_traversal_nonintrusive.cc +++ b/examples/checkpoint_example_traversal_nonintrusive.cc @@ -92,8 +92,8 @@ void serialize(Serializer& s, TestObject& obj) { } /// Custom traverser for printing raw bytes -struct PrintBytesTraverse : checkpoint::Serializer { - PrintBytesTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { } +struct PrintBytesTraverse : checkpoint::Serializer<> { + PrintBytesTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { } void contiguousBytes(void* ptr, std::size_t size, std::size_t num_elms) { printf("PrintBytesTraverse: size=%zu, num_elms=%zu\n", size, num_elms); @@ -136,12 +136,12 @@ struct CustomDispatch> { } }; -/// Custom traverser for printing typed ranges -struct TypedTraverse : checkpoint::Serializer { +/// Custom traverser for printing typed range<>s +struct TypedTraverse : checkpoint::Serializer<> { template using DispatcherType = CustomDispatch; - TypedTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { } + TypedTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { } template void contiguousTyped(SerializerT&, T*, std::size_t num_elms) { diff --git a/examples/checkpoint_example_user_traits.cc b/examples/checkpoint_example_user_traits.cc new file mode 100644 index 00000000..8a9a49ec --- /dev/null +++ b/examples/checkpoint_example_user_traits.cc @@ -0,0 +1,15 @@ +#include "checkpoint/checkpoint.h" + +#include "checkpoint_example_user_traits.hpp" + +int main(int argc, char *argv[]){ + test::TestObj obj; + + auto s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); +} diff --git a/examples/checkpoint_example_user_traits.hpp b/examples/checkpoint_example_user_traits.hpp new file mode 100644 index 00000000..1bd26c2a --- /dev/null +++ b/examples/checkpoint_example_user_traits.hpp @@ -0,0 +1,44 @@ +#include "checkpoint/checkpoint.h" + +struct CheckpointingTrait {}; +struct RandomTrait {}; + +struct ShallowTrait {}; + +namespace test { + struct TestObj { + int a = 1; + + TestObj() {} + + template + void serialize(SerializerT& s){ + if constexpr (checkpoint::hasTrait::value){ + if(s.isSizing()) printf("Customizing serialization for checkpoint\n"); + s | a; + } else { + if(s.isSizing()) printf("Default serializing testObj\n"); + } + + static_assert(not checkpoint::hasTrait::value, "ShallowTrait should have been removed!\n"); + } + }; +} + + +namespace test { + template::value >* = nullptr> + void serialize(SerializerT& s, TestObj& myObj){ + if(s.isSizing()) printf("Inserting random extra object serialization step! "); + myObj.serialize(s); + } + + template::value >* = nullptr> + void serialize(SerializerT& s, TestObj& myObj){ + if(s.isSizing()) printf("Removing shallow trait before passing along!\n"); + + auto& newS = checkpoint::withoutTrait(s); + + myObj.serialize(newS); + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 87e4044f..d410d322 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,7 +75,7 @@ add_library( add_library(${CHECKPOINT_LIBRARY_NS} ALIAS ${CHECKPOINT_LIBRARY}) target_compile_options(${CHECKPOINT_LIBRARY} PUBLIC "-fPIC") -target_compile_features(${CHECKPOINT_LIBRARY} PUBLIC cxx_std_14) +target_compile_features(${CHECKPOINT_LIBRARY} PUBLIC cxx_std_17) include(CMakePrintHelpers) diff --git a/src/checkpoint/checkpoint_api.h b/src/checkpoint/checkpoint_api.h index 37e91d78..471917db 100644 --- a/src/checkpoint/checkpoint_api.h +++ b/src/checkpoint/checkpoint_api.h @@ -260,6 +260,55 @@ std::unique_ptr deserializeFromStream(StreamT& stream); template void deserializeInPlaceFromStream(StreamT& stream, T* buf); +/** + * \brief Checks for \c Trait in the template parameters of \c SerializerT. + * + * Assumes \c SerializerT is a valid template and + * checks for existence of \c Trait within \c UserTraits... + * \c Trait is considered found if std::is_same<> returns true on \c Trait + * and any \c UserTrait within \c UserTraits... + * Some Serializer types may use template parameters of their own, caller should + * use unique types for \c Trait. + * May also use statically as hasTrait::value. + * + * \return extends std::true_type if \c Trait is within \c UserTraits..., else std::false_type. + */ +template +struct hasTrait : std::false_type {}; + +/** + * \brief Returns a \c SerializerT with no instances of \c Trait in its + * template parameters. + * + * Assumes \c SerializerT is a valid template and + * recursively checks for \c Trait within \c UserTraits..., removing all + * instances, then uses std::reinterpret_cast to return a \c SerializerT + * reference without template parameter \c Trait. + * Some Serializer types may use template parameters of their own, caller should + * use unique types for \c Trait. + * + * \param[in] Serializer of type \c SerializerT. + * + * \return Serializer of type \c SerializerT, where \c UserTraits... + * does not contain \c Trait + */ +template +auto& withoutTrait(SerializerT& s); + +/** + * \brief Returns a \c SerializerT with \c Trait added to its list of + * \c UserTraits... + * + * Assumes SerializerT is a valid template and + * uses std::reinterpret_cast to create a new reference to + * \c SerializerT. + * + * \param[in] Serializer of type \c SerializerT + * + * \return Serializer of type \c SerializerT + */ +template +auto& withTrait(SerializerT& s); } /* end namespace checkpoint */ diff --git a/src/checkpoint/checkpoint_api.impl.h b/src/checkpoint/checkpoint_api.impl.h index 82841b50..8169e448 100644 --- a/src/checkpoint/checkpoint_api.impl.h +++ b/src/checkpoint/checkpoint_api.impl.h @@ -48,6 +48,7 @@ #include #include "checkpoint/checkpoint_api.h" #include "buffer/buffer.h" +#include "traits/user_traits.h" #include @@ -148,6 +149,19 @@ void deserializeInPlaceFromStream(StreamT& stream, T* t) { ); } +template typename SerializerT, typename... UserTraits> +struct hasTrait> : SerializerUserTraits::hasTrait {}; + +template +auto& withoutTrait(SerializerT& s){ + return SerializerUserTraits::withoutTrait(s); +} + +template +auto& withTrait(SerializerT& s){ + return SerializerUserTraits::withTrait(s); +} + } /* end namespace checkpoint */ #endif /*INCLUDED_CHECKPOINT_CHECKPOINT_API_IMPL_H*/ diff --git a/src/checkpoint/serializers/base_serializer.h b/src/checkpoint/serializers/base_serializer.h index 352cf725..78b6143a 100644 --- a/src/checkpoint/serializers/base_serializer.h +++ b/src/checkpoint/serializers/base_serializer.h @@ -67,23 +67,6 @@ struct BasicDispatcher; } /* end namespace dispatch */ -namespace { - - template - struct checkTraitImpl : std::false_type {}; - - template - struct checkTraitImpl::value>*, Type, UserTrait, UserTraits...> : - std::true_type {}; - - template - struct checkTraitImpl::value>*, Type, UserTrait, UserTraits...> : - checkTraitImpl {}; - - template - struct checkTrait : checkTraitImpl {}; -} - /** * \struct Serializer * @@ -221,13 +204,6 @@ struct Serializer { */ void setVirtualDisabled(bool val) { virtual_disabled_ = val; } - /*template - static constexpr bool hasTrait(void) { - return checkTrait::value; - }*/ - template - using hasTrait = checkTrait; - protected: ModeType cur_mode_ = ModeType::Invalid; /**< The current mode */ bool virtual_disabled_ = false; /**< Virtual serialization disabled */ diff --git a/src/checkpoint/traits/user_traits.h b/src/checkpoint/traits/user_traits.h new file mode 100644 index 00000000..6699fb58 --- /dev/null +++ b/src/checkpoint/traits/user_traits.h @@ -0,0 +1,108 @@ +/* +//@HEADER +// ***************************************************************************** +// +// user_traits.h +// 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 +*/ + +#if !defined INCLUDED_USER_TRAITS_CHECKPOINT_TRAITS_H +#define INCLUDED_USER_TRAITS_CHECKPOINT_TRAITS_H + +namespace checkpoint { + +namespace { + //Pass around a list of types via storage in the parameters of a tuple + template + struct addToTuple {}; + + template + struct addToTuple> { + using type = std::tuple; + }; + + //Take types from a tuple and template our Serializer type on those. + template typename SerializerT, typename... UserTraits> + struct fromTuple {}; + + template typename SerializerT, typename... UserTraits> + struct fromTuple> { + using type = SerializerT; + }; + + + //Get a SerializerT with all the same template parameters except all instances of a given type. + //No change if ToRemove is not present in UserTraits. + template + struct removeTraitImpl { + using Traits = std::tuple; + }; + + template + struct removeTraitImpl { + using Traits = typename removeTraitImpl::Traits; + }; + + template + struct removeTraitImpl{ + using Traits = typename addToTuple::Traits>::type; + }; + + template typename SerializerT, typename... UserTraits> + struct removeTrait { + using type = typename fromTuple::Traits>::type; + }; +} + +namespace SerializerUserTraits { + template typename SerializerT, typename... UserTraits> + using hasTrait = std::disjunction...>; + + template typename SerializerT, typename... UserTraits> + auto& withoutTrait(SerializerT& obj){ + return reinterpret_cast::type&>(obj); + } + + template typename SerializerT, typename... UserTraits> + auto& withTrait(SerializerT& obj){ + return reinterpret_cast::type&>(obj); + } +} // end namespace UserTraits +} // end namespace checkpoint + +#endif /*INCLUDED_USER_TRAITS_CHECKPOINT_TRAITS_H*/ From b603e7bbcf3b7a22496c12f27776f42f616d4826 Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Wed, 8 Mar 2023 15:45:24 -0700 Subject: [PATCH 07/12] Replace constexpr uses --- .../serializers/stream_serializer.h | 107 ++++++++++-------- 1 file changed, 60 insertions(+), 47 deletions(-) diff --git a/src/checkpoint/serializers/stream_serializer.h b/src/checkpoint/serializers/stream_serializer.h index 811c3a1f..a7227f65 100644 --- a/src/checkpoint/serializers/stream_serializer.h +++ b/src/checkpoint/serializers/stream_serializer.h @@ -47,63 +47,76 @@ #include "checkpoint/common.h" #include "checkpoint/serializers/base_serializer.h" -//Used to always static_assert false without compilation issues. -template struct always_false : std::false_type {}; - namespace checkpoint { -template +namespace { + //template + //struct false_type : std::false_type {}; + + template + struct StreamHolder { + template + using false_type = std::false_type; + + StreamHolder(StreamT& stream){ + static_assert(false_type<>::value, "Unsupported serialization mode"); + } + }; + + template + struct StreamHolder { + StreamT& stream; + + StreamHolder(StreamT& stream) : stream(stream) {}; + + void copy(char* ptr, SerialSizeType len){ + stream.write(ptr, len); + } + + SerialSizeType position(){ + return stream.tellp(); + } + }; + + template + struct StreamHolder { + StreamT& stream; + + StreamHolder(StreamT& stream) : stream(stream) {}; + + void copy(char* ptr, SerialSizeType len){ + stream.read(ptr, len); + } + + SerialSizeType position(){ + return stream.tellg(); + } + }; +} + +template struct StreamSerializer : Serializer { - //This really doesn't expect to be initialized like this, disabling until someone yells at me. - /*explicit StreamSerializer(ModeType const& in_mode) - : Serializer(in_mode) - { - }*/ - - StreamSerializer(ModeType const& in_mode, StreamT& stream) - : Serializer(in_mode), stream(stream) - { - if constexpr ( mode == eSerializationMode::Packing ) { - start_position = stream.tellp(); - } else if constexpr ( mode == eSerializationMode::Unpacking ){ - start_position = stream.tellg(); - } else static_assert(always_false::value, "StreamSerializer can only be used for packing and unpacking"); + StreamSerializer(ModeType const& in_mode, StreamT& in_stream) + : Serializer(mode), stream(in_stream), stream_start_position(stream.position()) { +#ifdef DEBUG + assert(in_mode == mode); +#endif } - StreamSerializer(SerialSizeType in_size, ModeType const& in_mode, StreamT& stream) - : StreamSerializer(in_mode, stream) {} - - void contiguousBytes(void* ptr, SerialSizeType size, SerialSizeType num_elms){ - SerialSizeType const len = size * num_elms; - if constexpr ( mode == eSerializationMode::Packing ){ - stream.write((char*)ptr, len); - } else if constexpr ( mode == eSerializationMode::Unpacking ){ - stream.read((char*)ptr, len); - } else static_assert(always_false::value, "StreamSerializer can only be used for packing and unpacking"); - } + StreamSerializer(SerialSizeType size, ModeType const& in_mode, StreamT& in_stream) + : StreamSerializer(in_mode, in_stream) {} - SerialSizeType usedBufferSize() { - SerialSizeType current_position; - - if constexpr ( mode == eSerializationMode::Packing ){ - current_position = static_cast(stream.tellp()); - } else if constexpr ( mode == eSerializationMode::Unpacking ){ - current_position = static_cast(stream.tellg()); - } else static_assert(always_false::value, "StreamSerializer can only be used for packing and unpacking"); - - return current_position - start_position; + void contiguousBytes(void* ptr, SerialSizeType size, SerialSizeType num_elms) { + stream.copy(static_cast(ptr), size*num_elms); } - //TODO: What is the use of this? Is it important for some usecase? - void extractPackedBuffer(){ - return; + SerialSizeType usedBufferSize() { + return stream.position() - stream_start_position; } -protected: - StreamT& stream; - - //Initial position of streams, used for calculating in/out size - SerialSizeType start_position = 0; +private: + StreamHolder stream; + const SerialSizeType stream_start_position; }; } /* end namespace checkpoint */ From afb0645d34ac88b756d1a028e4af5b54d110a8cf Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Tue, 11 Apr 2023 09:11:08 -0700 Subject: [PATCH 08/12] Improved api, explicitly template serialization functions --- examples/checkpoint_example_user_traits.cc | 14 +- examples/checkpoint_example_user_traits.hpp | 37 ++++- src/checkpoint/checkpoint_api.h | 104 +++++++----- src/checkpoint/checkpoint_api.impl.h | 44 +++-- src/checkpoint/traits/serializable_traits.h | 4 +- src/checkpoint/traits/user_traits.h | 174 ++++++++++++++------ 6 files changed, 259 insertions(+), 118 deletions(-) diff --git a/examples/checkpoint_example_user_traits.cc b/examples/checkpoint_example_user_traits.cc index 8a9a49ec..1a83971a 100644 --- a/examples/checkpoint_example_user_traits.cc +++ b/examples/checkpoint_example_user_traits.cc @@ -6,10 +6,12 @@ int main(int argc, char *argv[]){ test::TestObj obj; auto s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); } diff --git a/examples/checkpoint_example_user_traits.hpp b/examples/checkpoint_example_user_traits.hpp index 1bd26c2a..f90376f3 100644 --- a/examples/checkpoint_example_user_traits.hpp +++ b/examples/checkpoint_example_user_traits.hpp @@ -1,11 +1,12 @@ #include "checkpoint/checkpoint.h" struct CheckpointingTrait {}; -struct RandomTrait {}; struct ShallowTrait {}; namespace test { + struct RandomTrait {}; + struct TestObj { int a = 1; @@ -13,32 +14,56 @@ namespace test { template void serialize(SerializerT& s){ - if constexpr (checkpoint::hasTrait::value){ + if (checkpoint::hasTrait(s)){ if(s.isSizing()) printf("Customizing serialization for checkpoint\n"); s | a; } else { if(s.isSizing()) printf("Default serializing testObj\n"); } - static_assert(not checkpoint::hasTrait::value, "ShallowTrait should have been removed!\n"); + static_assert(not checkpoint::has_trait_v, "ShallowTrait should have been removed!\n"); } }; } namespace test { - template::value >* = nullptr> + template >* = nullptr> void serialize(SerializerT& s, TestObj& myObj){ if(s.isSizing()) printf("Inserting random extra object serialization step! "); myObj.serialize(s); } - template::value >* = nullptr> + template>* = nullptr> void serialize(SerializerT& s, TestObj& myObj){ if(s.isSizing()) printf("Removing shallow trait before passing along!\n"); - auto& newS = checkpoint::withoutTrait(s); + auto& newS = checkpoint::withoutTraits(s); myObj.serialize(newS); } } + +namespace misc { + template >* = nullptr> + void serialize(SerializerT& s, test::TestObj& myObj){ + if(s.isSizing()) printf("Serializers in other namespaces don't usually get found "); + myObj.serialize(s); + } + + + struct NamespaceTrait {}; + template >* = nullptr> + void serialize(SerializerT& s, test::TestObj& myObj){ + if(s.isSizing()) printf("A misc:: trait means we can serialize from misc:: too: "); + myObj.serialize(s); + } + + + struct HookAllTrait {}; + template >* = nullptr> + void serialize(SerializerT& s, T& myObj){ + if(s.isSizing()) printf("We can even add on a generic pre-serialize hook: "); + myObj.serialize(s); + } +} diff --git a/src/checkpoint/checkpoint_api.h b/src/checkpoint/checkpoint_api.h index 471917db..dfbf51ec 100644 --- a/src/checkpoint/checkpoint_api.h +++ b/src/checkpoint/checkpoint_api.h @@ -78,7 +78,7 @@ using SerializedReturnType = std::unique_ptr; * \return a \c std::unique_ptr to a \c SerializedInfo containing the buffer * with serialized data and the size of the buffer */ -template +template SerializedReturnType serialize(T& target, BufferCallbackType fn = nullptr); /** @@ -132,7 +132,7 @@ std::unique_ptr deserialize(char* buf); * \param[in] t a valid pointer to a \c T that has been user-allocated and * constructed */ -template +template void deserializeInPlace(char* buf, T* t); /** @@ -153,7 +153,7 @@ std::unique_ptr deserialize(SerializedReturnType&& in); * * \return number of bytes for the \c target */ -template +template std::size_t getSize(T& target); /** @@ -170,7 +170,7 @@ std::size_t getSize(T& target); * * \return memory footprint of the \c target */ -template +template std::size_t getMemoryFootprint(T& target, std::size_t size_offset = 0); /** @@ -184,7 +184,7 @@ std::size_t getMemoryFootprint(T& target, std::size_t size_offset = 0); * \param[in] target the \c T to serialize * \param[in] file name of the file to create */ -template +template void serializeToFile(T& target, std::string const& file); /** @@ -214,7 +214,7 @@ std::unique_ptr deserializeFromFile(std::string const& file); * \param[in] file the filename to read with bytes for \c T * \param[in] t a valid, constructed \c T to deserialize into */ -template +template void deserializeInPlaceFromFile(std::string const& file, T* buf); /** @@ -227,7 +227,7 @@ void deserializeInPlaceFromFile(std::string const& file, T* buf); * \param[in] target the \c T to serialize * \param[in] stream to serialize into, with tellp and write functions. */ -template +template void serializeToStream(T& target, StreamT& stream); /** @@ -243,7 +243,7 @@ void serializeToStream(T& target, StreamT& stream); * * \return unique pointer to the new object \c T */ -template +template std::unique_ptr deserializeFromStream(StreamT& stream); /** @@ -257,58 +257,78 @@ std::unique_ptr deserializeFromStream(StreamT& stream); * \param[in] stream the stream to read with bytes for \c T, with tellg and read functions * \param[in] t a valid, constructed \c T to deserialize into */ -template -void deserializeInPlaceFromStream(StreamT& stream, T* buf); +template +void deserializeInPlaceFromStream(StreamT& stream, T* t); /** - * \brief Checks for \c Trait in the template parameters of \c SerializerT. + * \brief Returns whether serializer has the traits this function + * is templated on. + * + * Traits are compared via std::is_same<> + * + * Equivalently, use has_trait::value or + * has_trait_v * - * Assumes \c SerializerT is a valid template and - * checks for existence of \c Trait within \c UserTraits... - * \c Trait is considered found if std::is_same<> returns true on \c Trait - * and any \c UserTrait within \c UserTraits... - * Some Serializer types may use template parameters of their own, caller should - * use unique types for \c Trait. - * May also use statically as hasTrait::value. + * \param[in] serializer to check for the trait within. * - * \return extends std::true_type if \c Trait is within \c UserTraits..., else std::false_type. + * \return whether the trait is found. */ template -struct hasTrait : std::false_type {}; +constexpr bool hasTrait(const SerializerT& s); + +template +struct has_trait; + +template +inline constexpr bool has_trait_v = has_trait::value; + /** - * \brief Returns a \c SerializerT with no instances of \c Trait in its - * template parameters. + * \brief Returns a reinterpreted serializer without any of the traits + * this function is templated on. + * + * NOTE: Some serializers may use template parameters of their own, + * caller should use unique types for traits. * - * Assumes \c SerializerT is a valid template and - * recursively checks for \c Trait within \c UserTraits..., removing all - * instances, then uses std::reinterpret_cast to return a \c SerializerT - * reference without template parameter \c Trait. - * Some Serializer types may use template parameters of their own, caller should - * use unique types for \c Trait. + * You may also statically get the type of \c SerializerT without these + * traits using without_traits::type or + * without_traits_t * - * \param[in] Serializer of type \c SerializerT. + * \param[in] serializer to reinterpret * - * \return Serializer of type \c SerializerT, where \c UserTraits... - * does not contain \c Trait + * \return The reinterpreted serializer. */ -template -auto& withoutTrait(SerializerT& s); +template +auto& withoutTraits(SerializerT& s); + +template +struct without_traits; + +template +using without_traits_t = + typename without_traits::type; + /** - * \brief Returns a \c SerializerT with \c Trait added to its list of - * \c UserTraits... + * \brief Returns a reinterpreted serializer with all of the traits + * this function is templated on. * - * Assumes SerializerT is a valid template and - * uses std::reinterpret_cast to create a new reference to - * \c SerializerT. + * You may also statically get the type of \c SerializerT with these + * traits using with_traits::type or + * with_traits_t. * - * \param[in] Serializer of type \c SerializerT + * \param[in] serializer to reinterpret * - * \return Serializer of type \c SerializerT + * \return a reference to the serializer with trait \c Trait */ -template -auto& withTrait(SerializerT& s); +template +auto& withTraits(SerializerT& s); + +template +struct with_traits; + +template +using with_traits_t = typename with_traits::type; } /* end namespace checkpoint */ diff --git a/src/checkpoint/checkpoint_api.impl.h b/src/checkpoint/checkpoint_api.impl.h index 8169e448..bcb13292 100644 --- a/src/checkpoint/checkpoint_api.impl.h +++ b/src/checkpoint/checkpoint_api.impl.h @@ -54,7 +54,7 @@ namespace checkpoint { -template +template SerializedReturnType serialize(T& target, BufferCallbackType fn) { auto ret = dispatch::serializeType(target, fn); auto& buf = std::get<0>(ret); @@ -81,17 +81,17 @@ std::unique_ptr deserialize(SerializedReturnType&& in) { return std::unique_ptr(t); } -template +template void deserializeInPlace(char* buf, T* t) { return dispatch::deserializeType(dispatch::InPlaceTag{}, buf, t); } -template +template std::size_t getSize(T& target) { return dispatch::Standard::size>(target); } -template +template std::size_t getMemoryFootprint(T& target, std::size_t size_offset) { return size_offset + std::max( dispatch::Standard::footprint>(target), @@ -99,7 +99,7 @@ std::size_t getMemoryFootprint(T& target, std::size_t size_offset) { ); } -template +template void serializeToFile(T& target, std::string const& file) { auto len = getSize(target); dispatch::Standard::pack>( @@ -117,14 +117,14 @@ std::unique_ptr deserializeFromFile(std::string const& file) { return std::unique_ptr(t); } -template +template void deserializeInPlaceFromFile(std::string const& file, T* t) { dispatch::Standard::unpack>( t, buffer::IOBuffer::ReadFromFileTag{}, file ); } -template +template void serializeToStream(T& target, StreamT& stream) { auto len = getSize(target); dispatch::Standard::pack>( @@ -132,7 +132,7 @@ void serializeToStream(T& target, StreamT& stream) { ); } -template +template std::unique_ptr deserializeFromStream(StreamT& stream) { auto mem = dispatch::Standard::allocate(); T* t_buf = dispatch::Standard::construct(mem); @@ -142,24 +142,36 @@ std::unique_ptr deserializeFromStream(StreamT& stream) { return std::unique_ptr(t); } -template +template void deserializeInPlaceFromStream(StreamT& stream, T* t) { dispatch::Standard::unpack>( t, eSerializationMode::Unpacking, stream ); } -template typename SerializerT, typename... UserTraits> -struct hasTrait> : SerializerUserTraits::hasTrait {}; + +template +struct has_trait : public SerializerUserTraits::has_trait {}; template -auto& withoutTrait(SerializerT& s){ - return SerializerUserTraits::withoutTrait(s); +constexpr bool hasTrait(const SerializerT& s){ + return has_trait_v; } -template -auto& withTrait(SerializerT& s){ - return SerializerUserTraits::withTrait(s); +template +struct without_traits : public SerializerUserTraits::without_traits {}; + +template +auto& withoutTraits(SerializerT& s){ + return *reinterpret_cast::type*>(&s); +} + +template +struct with_traits : SerializerUserTraits::with_trait {}; + +template +auto& withTraits(SerializerT& s){ + return *reinterpret_cast*>(&s); } } /* end namespace checkpoint */ diff --git a/src/checkpoint/traits/serializable_traits.h b/src/checkpoint/traits/serializable_traits.h index 363e5dbb..2e49db81 100644 --- a/src/checkpoint/traits/serializable_traits.h +++ b/src/checkpoint/traits/serializable_traits.h @@ -93,12 +93,12 @@ struct SerializableTraits { // Regular serialize detection template using serialize_t = decltype( - std::declval().serialize(std::declval()) + std::declval().template serialize(std::declval()) ); using has_serialize = detection::is_detected; template - using nonintrustive_serialize_t = decltype(serialize( + using nonintrustive_serialize_t = decltype(serialize( std::declval(), std::declval() )); diff --git a/src/checkpoint/traits/user_traits.h b/src/checkpoint/traits/user_traits.h index 6699fb58..29b08d53 100644 --- a/src/checkpoint/traits/user_traits.h +++ b/src/checkpoint/traits/user_traits.h @@ -44,65 +44,147 @@ #if !defined INCLUDED_USER_TRAITS_CHECKPOINT_TRAITS_H #define INCLUDED_USER_TRAITS_CHECKPOINT_TRAITS_H +//"api" pre-declare namespace checkpoint { +namespace SerializerUserTraits { + template + struct has_trait; + -namespace { - //Pass around a list of types via storage in the parameters of a tuple - template - struct addToTuple {}; + template + struct with_trait; + template + struct with_traits; - template - struct addToTuple> { - using type = std::tuple; - }; - - //Take types from a tuple and template our Serializer type on those. - template typename SerializerT, typename... UserTraits> - struct fromTuple {}; + template + struct without_trait; + template + struct without_traits; +}} // end namespace checkpoint::SerializerUserTraits - template typename SerializerT, typename... UserTraits> - struct fromTuple> { - using type = SerializerT; - }; - - //Get a SerializerT with all the same template parameters except all instances of a given type. - //No change if ToRemove is not present in UserTraits. - template - struct removeTraitImpl { - using Traits = std::tuple; - }; - template - struct removeTraitImpl { - using Traits = typename removeTraitImpl::Traits; +namespace { //anon = filescope + + template< + typename TraitToRemove, + template typename SerializerT, + typename UserTraits, + typename... PassedTraits + > + struct without_trait_impl { + using type = SerializerT; }; - template - struct removeTraitImpl{ - using Traits = typename addToTuple::Traits>::type; + template< + typename ToRemove, + template typename SerializerT, + typename... Passed, + typename... Remaining + > + struct without_trait_impl< + ToRemove, + SerializerT, + std::tuple, + Passed... + > + { + using type = typename without_trait_impl< + ToRemove, SerializerT, std::tuple, Passed... + >::type; }; - template typename SerializerT, typename... UserTraits> - struct removeTrait { - using type = typename fromTuple::Traits>::type; + + template< + typename ToRemove, + template typename SerializerT, + typename... Passed, + typename ToKeep, + typename... Remaining + > + struct without_trait_impl< + ToRemove, + SerializerT, + std::tuple, + Passed... + > + { + using type = typename without_trait_impl< + ToRemove, SerializerT, std::tuple, Passed..., ToKeep + >::type; }; } + + +namespace checkpoint { namespace SerializerUserTraits { - template typename SerializerT, typename... UserTraits> - using hasTrait = std::disjunction...>; - - template typename SerializerT, typename... UserTraits> - auto& withoutTrait(SerializerT& obj){ - return reinterpret_cast::type&>(obj); - } - - template typename SerializerT, typename... UserTraits> - auto& withTrait(SerializerT& obj){ - return reinterpret_cast::type&>(obj); - } -} // end namespace UserTraits -} // end namespace checkpoint + template< + template typename SerializerT, + typename... UserTraits, + typename Trait + > + struct has_trait, Trait> + : std::disjunction...> { }; + + + template< + template typename SerializerT, + typename... UserTraits, + typename Trait + > + struct with_trait, Trait> + : std::conditional, Trait>::value, + SerializerT, + SerializerT + > { }; + + + template + struct with_traits + : with_trait {}; + + template< + typename SerializerT, + typename TraitOne, + typename TraitTwo, + typename... Remaining + > + struct with_traits + : with_traits::type, TraitTwo, Remaining...> {}; + + + + template< + typename SerializerT, + typename Trait + > + struct without_trait { + using type = SerializerT; + }; + + template< + template typename SerializerT, + typename... UserTraits, + typename Trait + > + struct without_trait, Trait> + : without_trait_impl> { }; + + + template + struct without_traits + : without_trait {}; + + template< + typename SerializerT, + typename TraitOne, + typename TraitTwo, + typename... Remaining + > + struct without_traits + : without_traits::type, TraitTwo, Remaining...> {}; + +}} // end namespace checkpoint::SerializerUserTraits #endif /*INCLUDED_USER_TRAITS_CHECKPOINT_TRAITS_H*/ From 7c1e4edd19c6a22d12eac82b2976cc0159c8f171 Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Tue, 11 Apr 2023 09:41:59 -0700 Subject: [PATCH 09/12] Add virtual support for StreamSerializer --- src/checkpoint/serializers/serializers_headers.h | 4 +++- src/checkpoint/serializers/stream_serializer.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/checkpoint/serializers/serializers_headers.h b/src/checkpoint/serializers/serializers_headers.h index ff1ff377..1e88f5cb 100644 --- a/src/checkpoint/serializers/serializers_headers.h +++ b/src/checkpoint/serializers/serializers_headers.h @@ -59,6 +59,8 @@ checkpoint::PackerIO, \ checkpoint::Unpacker, \ checkpoint::UnpackerIO, \ - checkpoint::Sizer \ + checkpoint::Sizer, \ + checkpoint::IStreamSerializer, \ + checkpoint::OStreamSerializer \ #endif /*INCLUDED_CHECKPOINT_SERIALIZERS_SERIALIZERS_HEADERS_H*/ diff --git a/src/checkpoint/serializers/stream_serializer.h b/src/checkpoint/serializers/stream_serializer.h index a7227f65..485e6a75 100644 --- a/src/checkpoint/serializers/stream_serializer.h +++ b/src/checkpoint/serializers/stream_serializer.h @@ -119,6 +119,9 @@ struct StreamSerializer : Serializer { const SerialSizeType stream_start_position; }; +using IStreamSerializer = StreamSerializer; +using OStreamSerializer = StreamSerializer; + } /* end namespace checkpoint */ #endif /*INCLUDED_CHECKPOINT_SERIALIZERS_STREAM_SERIALIZER_H*/ From 53a793bb85cf669efaa03c707351c86fd2a9aa05 Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Mon, 15 May 2023 15:49:31 -0700 Subject: [PATCH 10/12] More cleanly separate UserTraits code and improve UserTrait functionality with CRTP --- examples/checkpoint_example_traversal.cc | 8 +- ...eckpoint_example_traversal_nonintrusive.cc | 8 +- examples/checkpoint_example_user_traits.cc | 16 +- examples/checkpoint_example_user_traits.hpp | 45 ++- src/checkpoint/checkpoint.h | 1 + src/checkpoint/checkpoint_api.h | 70 ---- src/checkpoint/checkpoint_api.impl.h | 79 ++--- .../dispatch/vrt/serializer_registry.h | 2 +- .../dispatch/vrt/virtual_serialize.h | 13 + src/checkpoint/serializers/base_serializer.h | 2 +- src/checkpoint/serializers/footprinter.h | 8 +- .../serializers/memory_serializer.h | 9 +- src/checkpoint/serializers/packer.h | 5 +- src/checkpoint/serializers/packer.impl.h | 38 +-- .../serializers/serializers_headers.h | 6 +- src/checkpoint/serializers/sizer.h | 6 +- .../serializers/stream_serializer.h | 45 ++- src/checkpoint/serializers/unpacker.h | 4 +- src/checkpoint/serializers/unpacker.impl.h | 24 +- src/checkpoint/traits/serializable_traits.h | 6 +- src/checkpoint/traits/user_traits.h | 320 +++++++++++------- tests/unit/test_traversal.cc | 8 +- 22 files changed, 346 insertions(+), 377 deletions(-) diff --git a/examples/checkpoint_example_traversal.cc b/examples/checkpoint_example_traversal.cc index 00d305db..1660af6d 100644 --- a/examples/checkpoint_example_traversal.cc +++ b/examples/checkpoint_example_traversal.cc @@ -80,8 +80,8 @@ struct TestObject { }}} // end namespace magistrate::intrusive::examples /// Custom traverser for printing raw bytes -struct PrintBytesTraverse : checkpoint::Serializer<> { - PrintBytesTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { } +struct PrintBytesTraverse : checkpoint::Serializer { + PrintBytesTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { } void contiguousBytes(void* ptr, std::size_t size, std::size_t num_elms) { printf("PrintBytesTraverse: size=%zu, num_elms=%zu\n", size, num_elms); @@ -125,11 +125,11 @@ struct CustomDispatch> { }; /// Custom traverser for printing typed ranges -struct TypedTraverse : checkpoint::Serializer<> { +struct TypedTraverse : checkpoint::Serializer { template using DispatcherType = CustomDispatch; - TypedTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { } + TypedTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { } template void contiguousTyped(SerializerT&, T*, std::size_t num_elms) { diff --git a/examples/checkpoint_example_traversal_nonintrusive.cc b/examples/checkpoint_example_traversal_nonintrusive.cc index 3c8ef9b7..2585fd8f 100644 --- a/examples/checkpoint_example_traversal_nonintrusive.cc +++ b/examples/checkpoint_example_traversal_nonintrusive.cc @@ -92,8 +92,8 @@ void serialize(Serializer& s, TestObject& obj) { } /// Custom traverser for printing raw bytes -struct PrintBytesTraverse : checkpoint::Serializer<> { - PrintBytesTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { } +struct PrintBytesTraverse : checkpoint::Serializer { + PrintBytesTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { } void contiguousBytes(void* ptr, std::size_t size, std::size_t num_elms) { printf("PrintBytesTraverse: size=%zu, num_elms=%zu\n", size, num_elms); @@ -137,11 +137,11 @@ struct CustomDispatch> { }; /// Custom traverser for printing typed range<>s -struct TypedTraverse : checkpoint::Serializer<> { +struct TypedTraverse : checkpoint::Serializer { template using DispatcherType = CustomDispatch; - TypedTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { } + TypedTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { } template void contiguousTyped(SerializerT&, T*, std::size_t num_elms) { diff --git a/examples/checkpoint_example_user_traits.cc b/examples/checkpoint_example_user_traits.cc index 1a83971a..4c97933c 100644 --- a/examples/checkpoint_example_user_traits.cc +++ b/examples/checkpoint_example_user_traits.cc @@ -6,12 +6,12 @@ int main(int argc, char *argv[]){ test::TestObj obj; auto s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); - s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); + s_info = checkpoint::serialize(obj); } diff --git a/examples/checkpoint_example_user_traits.hpp b/examples/checkpoint_example_user_traits.hpp index f90376f3..259c0e78 100644 --- a/examples/checkpoint_example_user_traits.hpp +++ b/examples/checkpoint_example_user_traits.hpp @@ -1,69 +1,66 @@ #include "checkpoint/checkpoint.h" -struct CheckpointingTrait {}; - -struct ShallowTrait {}; +const struct checkpoint_trait {} CheckpointTrait; +const struct shallow_trait {} ShallowTrait; namespace test { - struct RandomTrait {}; + const struct random_trait {} RandomTrait; struct TestObj { int a = 1; TestObj() {} - template - void serialize(SerializerT& s){ - if (checkpoint::hasTrait(s)){ + template* = nullptr> + void serialize(SerT& s){ + if (s.hasTraits(CheckpointTrait)){ if(s.isSizing()) printf("Customizing serialization for checkpoint\n"); s | a; } else { if(s.isSizing()) printf("Default serializing testObj\n"); } - static_assert(not checkpoint::has_trait_v, "ShallowTrait should have been removed!\n"); + static_assert(not s.hasTraits(ShallowTrait), "ShallowTrait should have been removed!\n"); } }; } namespace test { - template >* = nullptr> - void serialize(SerializerT& s, TestObj& myObj){ + template* = nullptr> + void serialize(SerT& s, TestObj& myObj){ if(s.isSizing()) printf("Inserting random extra object serialization step! "); myObj.serialize(s); } - template>* = nullptr> - void serialize(SerializerT& s, TestObj& myObj){ + template* = nullptr> + void serialize(SerT& s, TestObj& myObj){ if(s.isSizing()) printf("Removing shallow trait before passing along!\n"); - auto& newS = checkpoint::withoutTraits(s); - - myObj.serialize(newS); + myObj.serialize(s.withoutTraits(ShallowTrait)); } } namespace misc { - template >* = nullptr> - void serialize(SerializerT& s, test::TestObj& myObj){ + template* = nullptr> + void serialize(SerT& s, test::TestObj& myObj){ if(s.isSizing()) printf("Serializers in other namespaces don't usually get found "); myObj.serialize(s); } - struct NamespaceTrait {}; - template >* = nullptr> - void serialize(SerializerT& s, test::TestObj& myObj){ + const struct namespace_trait {} NamespaceTrait; + template* = nullptr> + void serialize(SerT& s, test::TestObj& myObj){ if(s.isSizing()) printf("A misc:: trait means we can serialize from misc:: too: "); myObj.serialize(s); } - struct HookAllTrait {}; - template >* = nullptr> - void serialize(SerializerT& s, T& myObj){ + const struct hook_all_trait {} HookAllTrait; + template* = nullptr> + void serialize(SerT& s, T& myObj){ if(s.isSizing()) printf("We can even add on a generic pre-serialize hook: "); - myObj.serialize(s); + myObj.serialize(s.withoutTraits(HookAllTrait)); } } diff --git a/src/checkpoint/checkpoint.h b/src/checkpoint/checkpoint.h index 72692288..97f20b51 100644 --- a/src/checkpoint/checkpoint.h +++ b/src/checkpoint/checkpoint.h @@ -47,6 +47,7 @@ #include "checkpoint/serializers/serializers_headers.h" #include "checkpoint/dispatch/dispatch.h" #include "checkpoint/traits/serializable_traits.h" +#include "checkpoint/traits/user_traits.h" #include "checkpoint/container/array_serialize.h" #include "checkpoint/container/atomic_serialize.h" diff --git a/src/checkpoint/checkpoint_api.h b/src/checkpoint/checkpoint_api.h index dfbf51ec..012f8779 100644 --- a/src/checkpoint/checkpoint_api.h +++ b/src/checkpoint/checkpoint_api.h @@ -260,76 +260,6 @@ std::unique_ptr deserializeFromStream(StreamT& stream); template void deserializeInPlaceFromStream(StreamT& stream, T* t); -/** - * \brief Returns whether serializer has the traits this function - * is templated on. - * - * Traits are compared via std::is_same<> - * - * Equivalently, use has_trait::value or - * has_trait_v - * - * \param[in] serializer to check for the trait within. - * - * \return whether the trait is found. - */ -template -constexpr bool hasTrait(const SerializerT& s); - -template -struct has_trait; - -template -inline constexpr bool has_trait_v = has_trait::value; - - -/** - * \brief Returns a reinterpreted serializer without any of the traits - * this function is templated on. - * - * NOTE: Some serializers may use template parameters of their own, - * caller should use unique types for traits. - * - * You may also statically get the type of \c SerializerT without these - * traits using without_traits::type or - * without_traits_t - * - * \param[in] serializer to reinterpret - * - * \return The reinterpreted serializer. - */ -template -auto& withoutTraits(SerializerT& s); - -template -struct without_traits; - -template -using without_traits_t = - typename without_traits::type; - - -/** - * \brief Returns a reinterpreted serializer with all of the traits - * this function is templated on. - * - * You may also statically get the type of \c SerializerT with these - * traits using with_traits::type or - * with_traits_t. - * - * \param[in] serializer to reinterpret - * - * \return a reference to the serializer with trait \c Trait - */ -template -auto& withTraits(SerializerT& s); - -template -struct with_traits; - -template -using with_traits_t = typename with_traits::type; - } /* end namespace checkpoint */ #endif /*INCLUDED_CHECKPOINT_CHECKPOINT_API_H*/ diff --git a/src/checkpoint/checkpoint_api.impl.h b/src/checkpoint/checkpoint_api.impl.h index bcb13292..0fb969c2 100644 --- a/src/checkpoint/checkpoint_api.impl.h +++ b/src/checkpoint/checkpoint_api.impl.h @@ -54,9 +54,9 @@ namespace checkpoint { -template +template SerializedReturnType serialize(T& target, BufferCallbackType fn) { - auto ret = dispatch::serializeType(target, fn); + auto ret = dispatch::serializeType>(target, fn); auto& buf = std::get<0>(ret); std::unique_ptr base_ptr( static_cast(buf.release()) @@ -64,116 +64,91 @@ SerializedReturnType serialize(T& target, BufferCallbackType fn) { return base_ptr; } -template +template T* deserialize(char* buf, char* object_buf) { - return dispatch::deserializeType(buf, object_buf); + return dispatch::deserializeType>(buf, object_buf); } -template +template std::unique_ptr deserialize(char* buf) { - auto t = dispatch::deserializeType(buf); + auto t = dispatch::deserializeType>(buf); return std::unique_ptr(t); } -template +template std::unique_ptr deserialize(SerializedReturnType&& in) { - auto t = dispatch::deserializeType(in->getBuffer()); + auto t = dispatch::deserializeType>(in->getBuffer()); return std::unique_ptr(t); } -template +template void deserializeInPlace(char* buf, T* t) { - return dispatch::deserializeType(dispatch::InPlaceTag{}, buf, t); + return dispatch::deserializeType>(dispatch::InPlaceTag{}, buf, t); } -template +template std::size_t getSize(T& target) { - return dispatch::Standard::size>(target); + return dispatch::Standard::size>>(target); } -template +template std::size_t getMemoryFootprint(T& target, std::size_t size_offset) { return size_offset + std::max( - dispatch::Standard::footprint>(target), + dispatch::Standard::footprint>>(target), sizeof(target) ); } -template +template void serializeToFile(T& target, std::string const& file) { - auto len = getSize(target); - dispatch::Standard::pack>( + auto len = getSize>(target); + dispatch::Standard::pack>>( target, len, buffer::IOBuffer::WriteToFileTag{}, len, file ); } -template +template std::unique_ptr deserializeFromFile(std::string const& file) { auto mem = dispatch::Standard::allocate(); T* t_buf = dispatch::Standard::construct(mem); - auto t = dispatch::Standard::unpack>( + auto t = dispatch::Standard::unpack>>( t_buf, buffer::IOBuffer::ReadFromFileTag{}, file ); return std::unique_ptr(t); } -template +template void deserializeInPlaceFromFile(std::string const& file, T* t) { - dispatch::Standard::unpack>( + dispatch::Standard::unpack>>( t, buffer::IOBuffer::ReadFromFileTag{}, file ); } -template +template void serializeToStream(T& target, StreamT& stream) { auto len = getSize(target); - dispatch::Standard::pack>( + dispatch::Standard::pack>>( target, len, eSerializationMode::Packing, stream ); } -template +template std::unique_ptr deserializeFromStream(StreamT& stream) { auto mem = dispatch::Standard::allocate(); T* t_buf = dispatch::Standard::construct(mem); - auto t = dispatch::Standard::unpack>( + auto t = dispatch::Standard::unpack>>( t_buf, eSerializationMode::Unpacking, stream ); return std::unique_ptr(t); } -template +template void deserializeInPlaceFromStream(StreamT& stream, T* t) { - dispatch::Standard::unpack>( + dispatch::Standard::unpack>>( t, eSerializationMode::Unpacking, stream ); } - -template -struct has_trait : public SerializerUserTraits::has_trait {}; - -template -constexpr bool hasTrait(const SerializerT& s){ - return has_trait_v; -} - -template -struct without_traits : public SerializerUserTraits::without_traits {}; - -template -auto& withoutTraits(SerializerT& s){ - return *reinterpret_cast::type*>(&s); -} - -template -struct with_traits : SerializerUserTraits::with_trait {}; - -template -auto& withTraits(SerializerT& s){ - return *reinterpret_cast*>(&s); -} - } /* end namespace checkpoint */ #endif /*INCLUDED_CHECKPOINT_CHECKPOINT_API_IMPL_H*/ diff --git a/src/checkpoint/dispatch/vrt/serializer_registry.h b/src/checkpoint/dispatch/vrt/serializer_registry.h index e0772411..93372556 100644 --- a/src/checkpoint/dispatch/vrt/serializer_registry.h +++ b/src/checkpoint/dispatch/vrt/serializer_registry.h @@ -94,7 +94,7 @@ inline RegistryType& getRegistry() { template inline TypeIdx makeObjIdx() { - return Type::idx; + return Type::idx; } template diff --git a/src/checkpoint/dispatch/vrt/virtual_serialize.h b/src/checkpoint/dispatch/vrt/virtual_serialize.h index ad1b40cb..2c96daf2 100644 --- a/src/checkpoint/dispatch/vrt/virtual_serialize.h +++ b/src/checkpoint/dispatch/vrt/virtual_serialize.h @@ -49,6 +49,14 @@ namespace checkpoint { namespace dispatch { namespace vrt { +void warn_once(std::string warning){ + static bool once = false; + if(!once){ + once = true; + fprintf(stderr, "%s\n", warning.c_str()); + } +} + /** * \brief A function to handle serialization of objects of a mix of * types in a virtual inheritance hierarchy @@ -62,6 +70,11 @@ void virtualSerialize(T*& base, SerializerT& s) { // Get the real base in case this is called on a derived type using BaseT = ::checkpoint::dispatch::vrt::checkpoint_base_type_t; auto serializer_idx = serializer_registry::makeObjIdx(); + + if constexpr (not std::is_same_v){ + warn_once("Warning: Magistrate cannot support UserTraits being visible to virtually serialized objects."); + } + base->_checkpointDynamicSerialize(&s, serializer_idx, no_type_idx); } diff --git a/src/checkpoint/serializers/base_serializer.h b/src/checkpoint/serializers/base_serializer.h index 78b6143a..77ba82c9 100644 --- a/src/checkpoint/serializers/base_serializer.h +++ b/src/checkpoint/serializers/base_serializer.h @@ -45,6 +45,7 @@ #define INCLUDED_CHECKPOINT_SERIALIZERS_BASE_SERIALIZER_H #include "checkpoint/common.h" +#include "checkpoint/traits/user_traits.h" #include #include @@ -72,7 +73,6 @@ struct BasicDispatcher; * * \brief General base class for serialiers */ -template struct Serializer { using ModeType = eSerializationMode; diff --git a/src/checkpoint/serializers/footprinter.h b/src/checkpoint/serializers/footprinter.h index 44b57f4f..283bd7f8 100644 --- a/src/checkpoint/serializers/footprinter.h +++ b/src/checkpoint/serializers/footprinter.h @@ -49,11 +49,11 @@ namespace checkpoint { -template -struct Footprinter : Serializer { - using ModeType = eSerializationMode; +template> +struct Footprinter : Serializer, UserTraitedType { + using Serializer::ModeType; - Footprinter() : Serializer(ModeType::Footprinting) { } + Footprinter() : Serializer(ModeType::Footprinting) { } SerialSizeType getMemoryFootprint() const { return num_bytes_; diff --git a/src/checkpoint/serializers/memory_serializer.h b/src/checkpoint/serializers/memory_serializer.h index 10af77d5..3e7366c9 100644 --- a/src/checkpoint/serializers/memory_serializer.h +++ b/src/checkpoint/serializers/memory_serializer.h @@ -49,16 +49,15 @@ namespace checkpoint { -template -struct MemorySerializer : Serializer { - using ModeType = eSerializationMode; +struct MemorySerializer : Serializer { + using Serializer::ModeType; MemorySerializer(ModeType const& in_mode, SerialByteType* in_start) - : Serializer(in_mode), start_(in_start), cur_(in_start) + : Serializer(in_mode), start_(in_start), cur_(in_start) { } explicit MemorySerializer(ModeType const& in_mode) - : Serializer(in_mode) + : Serializer(in_mode) { } SerialByteType* getBuffer() const { diff --git a/src/checkpoint/serializers/packer.h b/src/checkpoint/serializers/packer.h index 7e4f6f0f..3d628ca6 100644 --- a/src/checkpoint/serializers/packer.h +++ b/src/checkpoint/serializers/packer.h @@ -52,9 +52,8 @@ #include "checkpoint/buffer/io_buffer.h" namespace checkpoint { - -template -struct PackerBuffer : MemorySerializer { +template > +struct PackerBuffer : MemorySerializer, public UserTraitedType { using BufferTPtrType = std::unique_ptr; using PackerReturnType = std::tuple; diff --git a/src/checkpoint/serializers/packer.impl.h b/src/checkpoint/serializers/packer.impl.h index 098eaa44..93a2ce87 100644 --- a/src/checkpoint/serializers/packer.impl.h +++ b/src/checkpoint/serializers/packer.impl.h @@ -52,12 +52,12 @@ namespace checkpoint { -template -PackerBuffer::PackerBuffer(SerialSizeType const& in_size) - : MemorySerializer(eSerializationMode::Packing), size_(in_size), +template +PackerBuffer::PackerBuffer(SerialSizeType const& in_size) + : MemorySerializer(Serializer::ModeType::Packing), size_(in_size), buffer_(std::make_unique(size_)) { - MemorySerializer::initializeBuffer(buffer_->getBuffer()); + MemorySerializer::initializeBuffer(buffer_->getBuffer()); debug_checkpoint( "PackerBuffer: size=%ld, start_=%p, cur_=%p\n", @@ -67,13 +67,13 @@ PackerBuffer::PackerBuffer(SerialSizeType const& in_size ); } -template -PackerBuffer::PackerBuffer( +template +PackerBuffer::PackerBuffer( SerialSizeType const& in_size, BufferTPtrType buf_ptr -) : MemorySerializer(eSerializationMode::Packing), size_(in_size), +) : MemorySerializer(Serializer::ModeType::Packing), size_(in_size), buffer_(std::move(buf_ptr)) { - MemorySerializer::initializeBuffer(buffer_->getBuffer()); + MemorySerializer::initializeBuffer(buffer_->getBuffer()); debug_checkpoint( "PackerBuffer: size=%ld, start_=%p, cur_=%p\n", @@ -83,15 +83,15 @@ PackerBuffer::PackerBuffer( ); } -template +template template -PackerBuffer::PackerBuffer( +PackerBuffer::PackerBuffer( SerialSizeType const& in_size, Args&&... args -) : MemorySerializer(eSerializationMode::Packing), +) : MemorySerializer(Serializer::ModeType::Packing), size_(in_size), buffer_(std::make_unique(std::forward(args)...)) { - MemorySerializer::initializeBuffer(buffer_->getBuffer()); + MemorySerializer::initializeBuffer(buffer_->getBuffer()); debug_checkpoint( "PackerBuffer: size=%ld, start_=%p, cur_=%p\n", @@ -101,16 +101,16 @@ PackerBuffer::PackerBuffer( ); } -template -typename PackerBuffer::BufferTPtrType -PackerBuffer::extractPackedBuffer() { +template +typename PackerBuffer::BufferTPtrType +PackerBuffer::extractPackedBuffer() { auto ret = std::move(buffer_); buffer_ = nullptr; return ret; } -template -void PackerBuffer::contiguousBytes( +template +void PackerBuffer::contiguousBytes( void* ptr, SerialSizeType size, SerialSizeType num_elms ) { debug_checkpoint( @@ -132,8 +132,8 @@ void PackerBuffer::contiguousBytes( usedSize_ += len; } -template -SerialSizeType PackerBuffer::usedBufferSize() const { +template +SerialSizeType PackerBuffer::usedBufferSize() const { return usedSize_; } diff --git a/src/checkpoint/serializers/serializers_headers.h b/src/checkpoint/serializers/serializers_headers.h index b2f22abe..e01a9e3f 100644 --- a/src/checkpoint/serializers/serializers_headers.h +++ b/src/checkpoint/serializers/serializers_headers.h @@ -59,8 +59,8 @@ checkpoint::PackerIO, \ checkpoint::Unpacker, \ checkpoint::UnpackerIO, \ - checkpoint::Sizer<> \ - checkpoint::IStreamSerializer, \ - checkpoint::OStreamSerializer \ + checkpoint::Sizer<>, \ + checkpoint::StreamPacker<>, \ + checkpoint::StreamUnpacker<> \ #endif /*INCLUDED_CHECKPOINT_SERIALIZERS_SERIALIZERS_HEADERS_H*/ diff --git a/src/checkpoint/serializers/sizer.h b/src/checkpoint/serializers/sizer.h index 3e5cd205..82d2c4d9 100644 --- a/src/checkpoint/serializers/sizer.h +++ b/src/checkpoint/serializers/sizer.h @@ -56,13 +56,13 @@ namespace checkpoint { * preprocessing pass before packing content so a properly sized buffer can be * allocated. */ -template -struct Sizer : Serializer { +template> +struct Sizer : Serializer, public UserTraitedType { using ModeType = eSerializationMode; /** * \internal \brief Construct a sizer */ - Sizer() : Serializer(ModeType::Sizing){ + Sizer() : Serializer(ModeType::Sizing){ } diff --git a/src/checkpoint/serializers/stream_serializer.h b/src/checkpoint/serializers/stream_serializer.h index ffd3e0e3..665ba429 100644 --- a/src/checkpoint/serializers/stream_serializer.h +++ b/src/checkpoint/serializers/stream_serializer.h @@ -50,21 +50,11 @@ namespace checkpoint { namespace { - //template - //struct false_type : std::false_type {}; - - template - struct StreamHolder { - template - using false_type = std::false_type; - - StreamHolder(StreamT& stream){ - static_assert(false_type<>::value, "Unsupported serialization mode"); - } - }; + template + struct StreamHolder {}; template - struct StreamHolder { + struct StreamHolder { StreamT& stream; StreamHolder(StreamT& stream) : stream(stream) {}; @@ -79,7 +69,7 @@ namespace { }; template - struct StreamHolder { + struct StreamHolder { StreamT& stream; StreamHolder(StreamT& stream) : stream(stream) {}; @@ -94,17 +84,18 @@ namespace { }; } -template -struct StreamSerializer : Serializer { - StreamSerializer(ModeType const& in_mode, StreamT& in_stream) - : Serializer(mode), stream(in_stream), stream_start_position(stream.position()) { -#ifdef DEBUG - assert(in_mode == mode); -#endif +template > +struct StreamSerializerImpl : Serializer, public UserTraitedType { + using Serializer::ModeType; + + StreamSerializerImpl(ModeType const& in_mode, StreamT& in_stream) + : Serializer(in_mode), stream(in_stream), stream_start_position(stream.position()) { + assert(( IsPacking::value && (in_mode == ModeType::Packing)) || + (!IsPacking::value && (in_mode == ModeType::Unpacking))); } - StreamSerializer(SerialSizeType size, ModeType const& in_mode, StreamT& in_stream) - : StreamSerializer(in_mode, in_stream) {} + StreamSerializerImpl(SerialSizeType size, ModeType const& in_mode, StreamT& in_stream) + : StreamSerializerImpl(in_mode, in_stream) {} void contiguousBytes(void* ptr, SerialSizeType size, SerialSizeType num_elms) { stream.copy(static_cast(ptr), size*num_elms); @@ -115,12 +106,14 @@ struct StreamSerializer : Serializer { } private: - StreamHolder stream; + StreamHolder stream; const SerialSizeType stream_start_position; }; -using IStreamSerializer = StreamSerializer; -using OStreamSerializer = StreamSerializer; +template +using StreamPacker = StreamSerializerImpl; +template +using StreamUnpacker = StreamSerializerImpl; } /* end namespace checkpoint */ diff --git a/src/checkpoint/serializers/unpacker.h b/src/checkpoint/serializers/unpacker.h index bda77b46..02279695 100644 --- a/src/checkpoint/serializers/unpacker.h +++ b/src/checkpoint/serializers/unpacker.h @@ -50,8 +50,8 @@ namespace checkpoint { -template -struct UnpackerBuffer : MemorySerializer { +template > +struct UnpackerBuffer : MemorySerializer, public UserTraitedType { using BufferPtrType = std::unique_ptr; explicit UnpackerBuffer(SerialByteType* buf); diff --git a/src/checkpoint/serializers/unpacker.impl.h b/src/checkpoint/serializers/unpacker.impl.h index 7e27364b..e3521153 100644 --- a/src/checkpoint/serializers/unpacker.impl.h +++ b/src/checkpoint/serializers/unpacker.impl.h @@ -53,12 +53,12 @@ namespace checkpoint { -template -UnpackerBuffer::UnpackerBuffer(SerialByteType* buf) - : MemorySerializer(eSerializationMode::Unpacking), +template +UnpackerBuffer::UnpackerBuffer(SerialByteType* buf) + : MemorySerializer(Serializer::ModeType::Unpacking), buffer_(std::make_unique(buf, 0)) { - MemorySerializer::initializeBuffer(buffer_->getBuffer()); + MemorySerializer::initializeBuffer(buffer_->getBuffer()); debug_checkpoint( "UnpackerBuffer: start_=%p, cur_=%p\n", @@ -67,13 +67,13 @@ UnpackerBuffer::UnpackerBuffer(SerialByteType* buf) ); } -template +template template -UnpackerBuffer::UnpackerBuffer(Args&&... args) - : MemorySerializer(eSerializationMode::Unpacking), +UnpackerBuffer::UnpackerBuffer(Args&&... args) + : MemorySerializer(Serializer::ModeType::Unpacking), buffer_(std::make_unique(std::forward(args)...)) { - MemorySerializer::initializeBuffer(buffer_->getBuffer()); + MemorySerializer::initializeBuffer(buffer_->getBuffer()); debug_checkpoint( "UnpackerBuffer: start_=%p, cur_=%p\n", @@ -82,8 +82,8 @@ UnpackerBuffer::UnpackerBuffer(Args&&... args) ); } -template -void UnpackerBuffer::contiguousBytes( +template +void UnpackerBuffer::contiguousBytes( void* ptr, SerialSizeType size, SerialSizeType num_elms ) { debug_checkpoint( @@ -98,8 +98,8 @@ void UnpackerBuffer::contiguousBytes( usedSize_ += len; } -template -SerialSizeType UnpackerBuffer::usedBufferSize() const { +template +SerialSizeType UnpackerBuffer::usedBufferSize() const { return usedSize_; } diff --git a/src/checkpoint/traits/serializable_traits.h b/src/checkpoint/traits/serializable_traits.h index 2a32957c..2693e9d2 100644 --- a/src/checkpoint/traits/serializable_traits.h +++ b/src/checkpoint/traits/serializable_traits.h @@ -81,7 +81,7 @@ struct isByteCopyableImpl { template struct isByteCopyable : detail::isByteCopyableImpl::has_byteCopyTraitTrue {}; -template > +template struct SerializableTraits { /** * Start with detection of "serialize" overloads, intrusive and non-intrusive. @@ -95,12 +95,12 @@ struct SerializableTraits { // Regular serialize detection template using serialize_t = decltype( - std::declval().template serialize(std::declval()) + std::declval().serialize(std::declval()) ); using has_serialize = detection::is_detected; template - using nonintrustive_serialize_t = decltype(serialize( + using nonintrustive_serialize_t = decltype(serialize( std::declval(), std::declval() )); diff --git a/src/checkpoint/traits/user_traits.h b/src/checkpoint/traits/user_traits.h index 29b08d53..62ec637e 100644 --- a/src/checkpoint/traits/user_traits.h +++ b/src/checkpoint/traits/user_traits.h @@ -44,147 +44,209 @@ #if !defined INCLUDED_USER_TRAITS_CHECKPOINT_TRAITS_H #define INCLUDED_USER_TRAITS_CHECKPOINT_TRAITS_H -//"api" pre-declare -namespace checkpoint { -namespace SerializerUserTraits { - template - struct has_trait; - - - template - struct with_trait; - template - struct with_traits; - - template - struct without_trait; - template - struct without_traits; -}} // end namespace checkpoint::SerializerUserTraits - - +namespace { + struct NoTrait; -namespace { //anon = filescope - - template< - typename TraitToRemove, - template typename SerializerT, - typename UserTraits, - typename... PassedTraits - > - struct without_trait_impl { - using type = SerializerT; + template + struct without_helper { + using type = typename without_helper, U...>::type; }; - - template< - typename ToRemove, - template typename SerializerT, - typename... Passed, - typename... Remaining - > - struct without_trait_impl< - ToRemove, - SerializerT, - std::tuple, - Passed... - > - { - using type = typename without_trait_impl< - ToRemove, SerializerT, std::tuple, Passed... - >::type; - }; - - - template< - typename ToRemove, - template typename SerializerT, - typename... Passed, - typename ToKeep, - typename... Remaining - > - struct without_trait_impl< - ToRemove, - SerializerT, - std::tuple, - Passed... - > - { - using type = typename without_trait_impl< - ToRemove, SerializerT, std::tuple, Passed..., ToKeep - >::type; + template + struct without_helper { + using type = typename Traits::_without_trait; }; } - - namespace checkpoint { namespace SerializerUserTraits { - template< - template typename SerializerT, - typename... UserTraits, - typename Trait - > - struct has_trait, Trait> - : std::disjunction...> { }; - - - template< - template typename SerializerT, - typename... UserTraits, - typename Trait - > - struct with_trait, Trait> - : std::conditional, Trait>::value, - SerializerT, - SerializerT - > { }; - - - template - struct with_traits - : with_trait {}; - - template< - typename SerializerT, - typename TraitOne, - typename TraitTwo, - typename... Remaining - > - struct with_traits - : with_traits::type, TraitTwo, Remaining...> {}; + template + struct is_base_or_derived + : std::disjunction, std::is_base_of> {}; + + template + struct is_same_template + : std::false_type {}; + template