From 218cf0e6741071f1a5f1828e0fbfb3c47f8e86bd Mon Sep 17 00:00:00 2001 From: Matthew Whitlock Date: Thu, 30 May 2024 11:19:41 -0700 Subject: [PATCH] #344 Implement user traits mechanisms --- examples/checkpoint_example_user_traits.cc | 60 ++++++ examples/checkpoint_example_user_traits.hpp | 66 ++++++ src/checkpoint/checkpoint_api.h | 26 +-- src/checkpoint/checkpoint_api.impl.h | 54 ++--- src/checkpoint/dispatch/dispatch.h | 8 +- src/checkpoint/dispatch/dispatch.impl.h | 28 +-- .../dispatch/vrt/serializer_registry.h | 2 +- .../dispatch/vrt/virtual_serialize.h | 9 + src/checkpoint/serializers/footprinter.h | 3 + src/checkpoint/serializers/reference.h | 178 ++++++++++++++++ .../serializers/serializers_headers.h | 21 +- src/checkpoint/traits/serializable_traits.h | 2 +- src/checkpoint/traits/user_traits.h | 196 ++++++++++++++++++ tests/unit/test_byte_macro.cc | 2 +- tests/unit/test_bytecopy_trait.cc | 2 +- tests/unit/test_commons.h | 2 +- tests/unit/test_interface.cc | 2 +- tests/unit/test_kokkos_serialize_complex.cc | 2 +- .../unit/test_kokkos_serialize_integration.cc | 10 +- tests/unit/test_kokkos_serialize_pair.cc | 2 +- tests/unit/test_kokkos_serialize_special.cc | 2 +- .../test_kokkos_serialize_unordered_map.cc | 2 +- tests/unit/test_object.cc | 2 +- tests/unit/test_reconstruct.cc | 2 +- .../unit/test_serialization_error_checking.cc | 16 +- tests/unit/test_tagged_construct.cc | 2 +- tests/unit/test_vector_bool_serialize.cc | 2 +- tests/unit/test_vector_serializer.cc | 10 +- tests/unit/test_virtual_serialize.cc | 2 +- tests/unit/tests_mpi/test_commons_mpi.h | 2 +- .../test_kokkos_serialize_integration_mpi.cc | 2 +- 31 files changed, 616 insertions(+), 103 deletions(-) create mode 100644 examples/checkpoint_example_user_traits.cc create mode 100644 examples/checkpoint_example_user_traits.hpp create mode 100644 src/checkpoint/serializers/reference.h create mode 100644 src/checkpoint/traits/user_traits.h diff --git a/examples/checkpoint_example_user_traits.cc b/examples/checkpoint_example_user_traits.cc new file mode 100644 index 00000000..bf2ef9b2 --- /dev/null +++ b/examples/checkpoint_example_user_traits.cc @@ -0,0 +1,60 @@ +/* +//@HEADER +// ***************************************************************************** +// +// checkpoint_example_user_traits.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 "checkpoint/checkpoint.h" + +#include "checkpoint_example_user_traits.hpp" + +int main(int, char**){ + test::TestObj obj; + + //Each invocation will be handled based on the traits attached + auto s_info_a = checkpoint::serialize(obj); + auto s_info_b = checkpoint::serialize(obj); + auto s_info_c = checkpoint::serialize(obj); + auto s_info_d = checkpoint::serialize(obj); + auto s_info_e = checkpoint::serialize(obj); + auto s_info_f = checkpoint::serialize(obj); + auto s_info_g = checkpoint::serialize(obj); + auto s_info_h = checkpoint::serialize(obj); + auto s_info_i = 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..8add6179 --- /dev/null +++ b/examples/checkpoint_example_user_traits.hpp @@ -0,0 +1,66 @@ +#include "checkpoint/checkpoint.h" + +struct checkpoint_trait {} CheckpointTrait; +struct shallow_trait {} ShallowTrait; + +namespace test { + struct random_trait {} RandomTrait; + + struct TestObj { + int a = 1; + + TestObj() {} + + template::value>* = nullptr> + void serialize(SerT& s){ + if constexpr(SerT::template has_traits::value){ + if(s.isSizing()) printf("Customizing serialization for checkpoint\n"); + s | a; + } else { + if(s.isSizing()) printf("Default serializing testObj\n"); + } + + static_assert(SerT::template has_not_traits::value, "ShallowTrait should have been removed!\n"); + } + }; +} + +namespace test { + template::value>* = nullptr> + void serialize(SerT& s, TestObj& myObj){ + if(s.isSizing()) printf("Inserting random extra object serialization step! "); + myObj.serialize(s); + } + + template::value>* = nullptr> + void serialize(SerT& s, TestObj& myObj){ + if(s.isSizing()) printf("Removing shallow trait before passing along!\n"); + auto newS = s.template withoutTraits(); + myObj.serialize(newS); + } +} + +namespace misc { + template::value>* = nullptr> + void serialize(SerT& s, test::TestObj& myObj){ + if(s.isSizing()) printf("Serializers in other namespaces don't usually get found "); + myObj.serialize(s); + } + + + const struct namespace_trait {} NamespaceTrait; + template::value>* = 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); + } + + + const struct hook_all_trait {} HookAllTrait; + template::value>* = nullptr> + void serialize(SerT& s, T& myObj){ + if(s.isSizing()) printf("We can even add on a generic pre-serialize hook: "); + auto newS = s.template withoutTraits(); + myObj.serialize(newS); + } +} diff --git a/src/checkpoint/checkpoint_api.h b/src/checkpoint/checkpoint_api.h index cd123cf4..83162753 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 863472e9..e78c92a6 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, Traits...>>( 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, Traits...>>( 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, Traits...>>( t, buffer::IOBuffer::ReadFromFileTag{}, file ); } -template +template void serializeToStream(T& target, StreamT& stream) { auto len = getSize(target); - dispatch::Standard::pack>( + dispatch::Standard::pack, Traits...>>( target, len, 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, Traits...>>( t_buf, stream ); return std::unique_ptr(t); } -template +template void deserializeInPlaceFromStream(StreamT& stream, T* t) { - dispatch::Standard::unpack>( + dispatch::Standard::unpack, Traits...>>( t, stream ); } diff --git a/src/checkpoint/dispatch/dispatch.h b/src/checkpoint/dispatch/dispatch.h index e5c6da1b..08e613b8 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 44aac6a2..451938c2 100644 --- a/src/checkpoint/dispatch/dispatch.impl.h +++ b/src/checkpoint/dispatch/dispatch.impl.h @@ -195,14 +195,14 @@ T* Traverse::reconstruct(SerialByteType* mem) { template SerialSizeType Standard::size(T& target, Args&&... args) { auto sizer = Traverse::with(target, std::forward(args)...); - return sizer.getSize(); + return sizer->getSize(); } template SerialSizeType Standard::footprint(T& target, Args&&... args) { auto footprinter = Traverse::with(target, std::forward(args)...); - return footprinter.getMemoryFootprint(); + return footprinter->getMemoryFootprint(); } template @@ -247,44 +247,44 @@ 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, UserTraits...>>(target, size); validatePackerBufferSize(p, size); - return std::make_tuple(std::move(p.extractPackedBuffer()), size); + return std::make_tuple(std::move(p->extractPackedBuffer()), size); } else { - auto p = Standard::pack>( + auto p = Standard::pack, UserTraits...>>( target, size, std::make_unique(user_buf, size) ); validatePackerBufferSize(p, size); - return std::make_tuple(std::move(p.extractPackedBuffer()), size); + return std::make_tuple(std::move(p->extractPackedBuffer()), size); } } -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, UserTraits...>>(t_buf.get(), data); t_buf.release(); return traverser; } -template +template void deserializeType(InPlaceTag, SerialByteType* data, T* t) { - Standard::unpack>(t, data); + Standard::unpack, UserTraits...>>(t, data); } }} /* end namespace checkpoint::dispatch */ diff --git a/src/checkpoint/dispatch/vrt/serializer_registry.h b/src/checkpoint/dispatch/vrt/serializer_registry.h index 9ec3860c..81e70669 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 52f8ef03..5196d4c5 100644 --- a/src/checkpoint/dispatch/vrt/virtual_serialize.h +++ b/src/checkpoint/dispatch/vrt/virtual_serialize.h @@ -62,6 +62,15 @@ 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){ + static bool warned_once = false; + if(!warned_once){ + fprintf(stderr, "Warning: Magistrate cannot support UserTraits being visible to virtually serialized objects.\n"); + warned_once = true; + } + } + base->_checkpointDynamicSerialize(&s, serializer_idx, no_type_idx); } diff --git a/src/checkpoint/serializers/footprinter.h b/src/checkpoint/serializers/footprinter.h index 1818410b..dbd027b7 100644 --- a/src/checkpoint/serializers/footprinter.h +++ b/src/checkpoint/serializers/footprinter.h @@ -76,6 +76,9 @@ 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 {}; } diff --git a/src/checkpoint/serializers/reference.h b/src/checkpoint/serializers/reference.h new file mode 100644 index 00000000..7e402c62 --- /dev/null +++ b/src/checkpoint/serializers/reference.h @@ -0,0 +1,178 @@ +/* +//@HEADER +// ***************************************************************************** +// +// reference.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_REFERENCE_H +#define INCLUDED_CHECKPOINT_SERIALIZERS_REFERENCE_H + +#include "checkpoint/common.h" +#include "checkpoint/serializers/base_serializer.h" +#include "checkpoint/traits/user_traits.h" + +#include +#include +#include + +namespace checkpoint { + +namespace { + template + struct first_type_matches : public std::false_type {}; + template + struct first_type_matches : public std::true_type {}; +} + +template +struct SerializerRef +{ + using TraitHolder = typename UserTraitHolder::BaseTraits; + + //Passing initialization to the serializer implementation + template + explicit SerializerRef(Args&&... args) + { + if constexpr(first_type_matches, std::decay_t...>::value and sizeof...(Args) == 1) { + //If only 1 arg which is a shared pointer to the base serializer, use that instead of initializing a new serializer. + impl = {std::forward(args)...}; + } else { + impl = std::make_shared(std::forward(args)...); + } + } + + //Now forward along Serializer function calls and types + using ModeType = eSerializationMode; + template + using DispatcherType = typename SerT::template DispatcherType; + ModeType getMode() const { return impl->getMode(); } + bool isSizing() const { return impl->isSizing(); } + bool isPacking() const { return impl->isPacking(); } + bool isUnpacking() const { return impl->isUnpacking(); } + bool isFootprinting() const { return impl->isFootprinting(); } + template + void countBytes(const T& t) { impl->countBytes(t); } + void addBytes(std::size_t s) { impl->addBytes(s); } + void contiguousBytes(void* ptr, SerialSizeType size, SerialSizeType num_elms) { + impl->contiguousBytes(ptr, size, num_elms); + } + SerialSizeType usedBufferSize() const { return impl->usedBufferSize(); } + template + void contiguousTyped(SerializerT& serdes, T* ptr, SerialSizeType num_elms) { + serdes.contiguousBytes(static_cast(ptr), sizeof(T), num_elms); + } + template + void skip(Args&&... args){ + impl->skip( std::forward(args)... ); + } + SerialByteType* getBuffer() const { return impl->getBuffer(); } + SerialByteType* getSpotIncrement(const SerialSizeType inc) { return impl->getSpotIncrement(inc); } + bool isVirtualDisabled() const { return impl->isVirtualDisabled(); } + void setVirtualDisabled(bool val) { impl->setVirtualDisabled(val); } + + + + SerT* operator->(){ return impl.get(); } + + template + operator SerializerRef() const { + return SerializerRef(impl); + } + + + //Big block of helpers for conveniently checking traits in different contexts. + template + using has_traits = typename TraitHolder::template has; + template + using has_any_traits = typename TraitHolder::template has_any; + + template + using has_not_traits = std::integral_constant::value)>; + template + using has_not_any_traits = std::integral_constant::value)>; + + template + static constexpr bool has_traits_v = has_traits::value; + template + static constexpr bool has_any_traits_v = has_any_traits::value; + template + static constexpr bool has_not_traits_v = has_not_traits::value; + template + static constexpr bool has_not_any_traits_v = has_not_any_traits::value; + + template + using has_traits_t = std::enable_if_t>; + template + using has_any_traits_t = std::enable_if_t>; + template + using has_not_traits_t = std::enable_if_t>; + template + using has_not_any_traits_t = std::enable_if_t>; + + + //Helpers for converting between traits + using TraitlessT = SerializerRef; + + //Returns a new reference with traits in addition to this reference's traits. + template + auto withTraits(UserTraitHolder = {}){ + using NewTraitHolder = typename TraitHolder::template with; + return setTraits(NewTraitHolder()); + } + + //Returns a new reference with traits removed (if present) from this reference's traits. + template + auto withoutTraits(UserTraitHolder = {}){ + using NewTraitHolder = typename TraitHolder::template without; + return setTraits(NewTraitHolder()); + } + + //Returns a new reference with traits set to the inputs, regardless of this reference's traits. + template + SerializerRef setTraits(UserTraitHolder = {}){ + return *this; + } + +private: + std::shared_ptr impl; +}; + +} +#endif /*INCLUDED_CHECKPOINT_SERIALIZERS_REFERENCE_H*/ diff --git a/src/checkpoint/serializers/serializers_headers.h b/src/checkpoint/serializers/serializers_headers.h index 395a063d..d7b5c44a 100644 --- a/src/checkpoint/serializers/serializers_headers.h +++ b/src/checkpoint/serializers/serializers_headers.h @@ -46,21 +46,22 @@ #include "checkpoint/common.h" #include "checkpoint/serializers/base_serializer.h" +#include "checkpoint/serializers/reference.h" #include "checkpoint/serializers/footprinter.h" #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, \ - checkpoint::Packer, \ - checkpoint::PackerUserBuf, \ - checkpoint::PackerIO, \ - checkpoint::Unpacker, \ - checkpoint::UnpackerIO, \ - checkpoint::Sizer, \ - checkpoint::StreamPacker<>, \ - checkpoint::StreamUnpacker<> \ +#define checkpoint_serializer_variadic_args() \ + checkpoint::SerializerRef, \ + checkpoint::SerializerRef, \ + checkpoint::SerializerRef, \ + checkpoint::SerializerRef, \ + checkpoint::SerializerRef, \ + checkpoint::SerializerRef, \ + checkpoint::SerializerRef, \ + checkpoint::SerializerRef>, \ + checkpoint::SerializerRef> \ #endif /*INCLUDED_SRC_CHECKPOINT_SERIALIZERS_SERIALIZERS_HEADERS_H*/ diff --git a/src/checkpoint/traits/serializable_traits.h b/src/checkpoint/traits/serializable_traits.h index 3dc8b0bb..fef2e7cb 100644 --- a/src/checkpoint/traits/serializable_traits.h +++ b/src/checkpoint/traits/serializable_traits.h @@ -86,7 +86,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/src/checkpoint/traits/user_traits.h b/src/checkpoint/traits/user_traits.h new file mode 100644 index 00000000..eb090df1 --- /dev/null +++ b/src/checkpoint/traits/user_traits.h @@ -0,0 +1,196 @@ +/* +//@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_CHECKPOINT_TRAITS_USER_TRAITS_H +#define INCLUDED_CHECKPOINT_TRAITS_USER_TRAITS_H + +namespace { + struct NoTrait; + + template + struct without_helper { + using type = typename without_helper, U...>::type; + }; + template + struct without_helper { + using type = typename Traits::template _without_trait; + }; +} + +namespace checkpoint { +namespace SerializerUserTraits { + + template + struct is_base_or_derived + : std::disjunction, std::is_base_of> {}; + + template + struct is_same_template + : std::false_type {}; + template