Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable optional user traits on serializers #282

Closed
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions examples/checkpoint_example_traversal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -125,11 +125,11 @@ struct CustomDispatch<SerializerT, std::vector<U>> {
};

/// Custom traverser for printing typed ranges
struct TypedTraverse : checkpoint::Serializer {
struct TypedTraverse : checkpoint::Serializer<> {
template <typename U, typename V>
using DispatcherType = CustomDispatch<U, V>;

TypedTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { }
TypedTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { }

template <typename SerializerT, typename T>
void contiguousTyped(SerializerT&, T*, std::size_t num_elms) {
Expand Down
10 changes: 5 additions & 5 deletions examples/checkpoint_example_traversal_nonintrusive.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -136,12 +136,12 @@ struct CustomDispatch<SerializerT, std::vector<U>> {
}
};

/// Custom traverser for printing typed ranges
struct TypedTraverse : checkpoint::Serializer {
/// Custom traverser for printing typed range<>s
struct TypedTraverse : checkpoint::Serializer<> {
template <typename U, typename V>
using DispatcherType = CustomDispatch<U, V>;

TypedTraverse() : checkpoint::Serializer(checkpoint::eSerializationMode::None) { }
TypedTraverse() : checkpoint::Serializer<>(checkpoint::eSerializationMode::None) { }

template <typename SerializerT, typename T>
void contiguousTyped(SerializerT&, T*, std::size_t num_elms) {
Expand Down
15 changes: 15 additions & 0 deletions examples/checkpoint_example_user_traits.cc
Original file line number Diff line number Diff line change
@@ -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<test::TestObj, CheckpointingTrait>(obj);
s_info = checkpoint::serialize<test::TestObj, CheckpointingTrait, CheckpointingTrait>(obj);
s_info = checkpoint::serialize<test::TestObj, RandomTrait, CheckpointingTrait>(obj);
s_info = checkpoint::serialize<test::TestObj, CheckpointingTrait, RandomTrait>(obj);
s_info = checkpoint::serialize<test::TestObj, RandomTrait, RandomTrait>(obj);
s_info = checkpoint::serialize<test::TestObj, ShallowTrait>(obj);
}
44 changes: 44 additions & 0 deletions examples/checkpoint_example_user_traits.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include "checkpoint/checkpoint.h"

struct CheckpointingTrait {};
struct RandomTrait {};

struct ShallowTrait {};

namespace test {
struct TestObj {
int a = 1;

TestObj() {}

template<typename SerializerT>
void serialize(SerializerT& s){
if constexpr (checkpoint::hasTrait<CheckpointingTrait, SerializerT>::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<ShallowTrait, SerializerT>::value, "ShallowTrait should have been removed!\n");
}
};
}


namespace test {
template<typename SerializerT, std::enable_if_t< checkpoint::hasTrait<RandomTrait, SerializerT>::value >* = nullptr>
void serialize(SerializerT& s, TestObj& myObj){
if(s.isSizing()) printf("Inserting random extra object serialization step! ");
myObj.serialize(s);
}

template<typename SerializerT, std::enable_if_t< checkpoint::hasTrait<ShallowTrait, SerializerT>::value >* = nullptr>
void serialize(SerializerT& s, TestObj& myObj){
if(s.isSizing()) printf("Removing shallow trait before passing along!\n");

auto& newS = checkpoint::withoutTrait<ShallowTrait>(s);

myObj.serialize(newS);
}
}
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
113 changes: 103 additions & 10 deletions src/checkpoint/checkpoint_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ using SerializedReturnType = std::unique_ptr<SerializedInfo>;
* \return a \c std::unique_ptr to a \c SerializedInfo containing the buffer
* with serialized data and the size of the buffer
*/
template <typename T>
template <typename T, typename... UserTraits>
SerializedReturnType serialize(T& target, BufferCallbackType fn = nullptr);

/**
Expand All @@ -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 <typename T>
template <typename T, typename... UserTraits>
T* deserialize(char* buf, char* object_buf);

/**
Expand All @@ -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 <typename T>
template <typename T, typename... UserTraits>
std::unique_ptr<T> deserialize(char* buf);

/**
Expand All @@ -132,7 +132,7 @@ std::unique_ptr<T> deserialize(char* buf);
* \param[in] t a valid pointer to a \c T that has been user-allocated and
* constructed
*/
template <typename T>
template <typename T, typename... UserTraits>
void deserializeInPlace(char* buf, T* t);

/**
Expand All @@ -143,7 +143,7 @@ void deserializeInPlace(char* buf, T* t);
*
* \return a unique pointer to \c T that must be deallocated
*/
template <typename T>
template <typename T, typename... UserTraits>
std::unique_ptr<T> deserialize(SerializedReturnType&& in);

/**
Expand All @@ -153,7 +153,7 @@ std::unique_ptr<T> deserialize(SerializedReturnType&& in);
*
* \return number of bytes for the \c target
*/
template <typename T>
template <typename T, typename... UserTraits>
std::size_t getSize(T& target);

/**
Expand All @@ -170,7 +170,7 @@ std::size_t getSize(T& target);
*
* \return memory footprint of the \c target
*/
template <typename T>
template <typename T, typename... UserTraits>
std::size_t getMemoryFootprint(T& target, std::size_t size_offset = 0);

/**
Expand All @@ -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 <typename T>
template <typename T, typename... UserTraits>
void serializeToFile(T& target, std::string const& file);

/**
Expand All @@ -200,7 +200,7 @@ void serializeToFile(T& target, std::string const& file);
*
* \return unique pointer to the new object \c T
*/
template <typename T>
template <typename T, typename... UserTraits>
std::unique_ptr<T> deserializeFromFile(std::string const& file);

/**
Expand All @@ -214,9 +214,102 @@ std::unique_ptr<T> 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 <typename T>
template <typename T, typename... UserTraits>
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 <typename T, typename StreamT, typename... UserTraits>
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 <typename T, typename StreamT, typename... UserTraits>
std::unique_ptr<T> 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 <typename T, typename StreamT, typename... UserTraits>
void deserializeInPlaceFromStream(StreamT& stream, T* buf);

/**
* \brief Checks for \c Trait in the template parameters of \c SerializerT.
*
* Assumes \c SerializerT<typename... UserTraits> 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<Trait, SerializerT>::value.
*
* \return extends std::true_type if \c Trait is within \c UserTraits..., else std::false_type.
*/
template <typename Trait, typename SerializerT>
struct hasTrait : std::false_type {};

/**
* \brief Returns a \c SerializerT with no instances of \c Trait in its
* template parameters.
*
* Assumes \c SerializerT<typename... UserTraits> 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<UserTraits...>.
*
* \return Serializer of type \c SerializerT<UserTraits...>, where \c UserTraits...
* does not contain \c Trait
*/
template <typename Trait, typename SerializerT>
auto& withoutTrait(SerializerT& s);

/**
* \brief Returns a \c SerializerT with \c Trait added to its list of
* \c UserTraits...
*
* Assumes SerializerT<typename... UserTraits> is a valid template and
* uses std::reinterpret_cast to create a new reference to
* \c SerializerT<UserTraits..., Trait>.
*
* \param[in] Serializer of type \c SerializerT<UserTraits...>
*
* \return Serializer of type \c SerializerT<UserTraits..., Trait>
*/
template <typename Trait, typename SerializerT>
auto& withTrait(SerializerT& s);

} /* end namespace checkpoint */

#endif /*INCLUDED_CHECKPOINT_CHECKPOINT_API_H*/
Loading