Skip to content

Commit

Permalink
#161 use reconstruction logic for std::vector
Browse files Browse the repository at this point in the history
  • Loading branch information
Jakub Strzebonski committed Jun 17, 2021
1 parent b0c332e commit fdd3a55
Show file tree
Hide file tree
Showing 2 changed files with 209 additions and 9 deletions.
96 changes: 87 additions & 9 deletions src/checkpoint/container/vector_serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#define INCLUDED_CHECKPOINT_CONTAINER_VECTOR_SERIALIZE_H

#include "checkpoint/common.h"
#include "checkpoint/dispatch/reconstructor.h"
#include "checkpoint/serializers/serializers_headers.h"

#include <vector>
Expand All @@ -54,29 +55,105 @@ namespace checkpoint {

template <typename SerializerT, typename T, typename VectorAllocator>
typename std::enable_if_t<
not std::is_same<SerializerT, checkpoint::Footprinter>::value,
void
> serializeVectorMeta(SerializerT& s, std::vector<T, VectorAllocator>& vec) {
not std::is_same<SerializerT, checkpoint::Footprinter>::value, SerialSizeType
>
serializeVectorMeta(SerializerT& s, std::vector<T, VectorAllocator>& vec) {
SerialSizeType vec_capacity = vec.capacity();
s | vec_capacity;
vec.reserve(vec_capacity);

SerialSizeType vec_size = vec.size();
s | vec_size;
vec.resize(vec_size);
return vec_size;
}

template <typename SerializerT, typename T, typename VectorAllocator>
typename std::enable_if_t<
std::is_same<SerializerT, checkpoint::Footprinter>::value,
void
> serializeVectorMeta(SerializerT& s, std::vector<T, VectorAllocator>& vec) {
std::is_same<SerializerT, checkpoint::Footprinter>::value, SerialSizeType
>
serializeVectorMeta(SerializerT& s, std::vector<T, VectorAllocator>& vec) {
s.countBytes(vec);
return 0;
}

template <typename T, typename VectorAllocator>
void constructVectorDataWithResize(
SerialSizeType const vec_size, std::vector<T, VectorAllocator>& vec,
typename dispatch::Reconstructor<T>::template isDefaultConsType<T>* = nullptr
) {
vec.resize(vec_size);
}

template <typename T, typename VectorAllocator>
void constructVectorDataWithResize(
SerialSizeType const, std::vector<T, VectorAllocator>& vec,
typename dispatch::Reconstructor<T>::template isNotDefaultConsType<T>* = nullptr
) {
static_assert(
SerializableTraits<T, void>::is_tagged_constructible or
SerializableTraits<T, void>::is_reconstructible or
std::is_default_constructible<T>::value,
"Either a default constructor, reconstruct() function, or tagged "
"constructor are required for std::vector de-serialization"
);
}

template <typename T, typename VectorAllocator>
void constructVectorDataReconstruct(
SerialSizeType const vec_size, std::vector<T, VectorAllocator>& vec,
typename dispatch::Reconstructor<T>::template isReconstructibleType<T>* = nullptr
) {
auto buf = dispatch::Standard::template allocate<T>();
for (SerialSizeType i = 0; i < vec_size; ++i) {
auto& t = T::reconstruct(buf);
vec.emplace_back(std::move(t));
}
}

template <typename T, typename VectorAllocator>
void constructVectorDataReconstruct(
SerialSizeType const vec_size, std::vector<T, VectorAllocator>& vec,
typename dispatch::Reconstructor<T>::template isNonIntReconstructibleType<T>* = nullptr
) {
auto buf = dispatch::Standard::allocate<T>();
for (SerialSizeType i = 0; i < vec_size; ++i) {
T* t = nullptr;
reconstruct(t, buf);
vec.emplace_back(std::move(*t));
}
}

template <typename T, typename VectorAllocator>
void constructVectorDataReconstruct(
SerialSizeType const vec_size, std::vector<T, VectorAllocator>& vec,
typename dispatch::Reconstructor<T>::template isNotReconstructibleType<T>* = nullptr
) {
constructVectorDataWithResize(vec_size, vec);
}

template <typename T, typename VectorAllocator>
void constructVectorData(
SerialSizeType const vec_size, std::vector<T, VectorAllocator>& vec,
typename dispatch::Reconstructor<T>::template isTaggedConstructibleType<T>* = nullptr
) {
for (SerialSizeType i = 0; i < vec_size; ++i) {
vec.emplace_back(SERIALIZE_CONSTRUCT_TAG{});
}
}

template <typename T, typename VectorAllocator>
void constructVectorData(
SerialSizeType const vec_size, std::vector<T, VectorAllocator>& vec,
typename dispatch::Reconstructor<T>::template isNotTaggedConstructibleType<T>* = nullptr
) {
constructVectorDataReconstruct(vec_size, vec);
}

template <typename Serializer, typename T, typename VectorAllocator>
void serialize(Serializer& s, std::vector<T, VectorAllocator>& vec) {
serializeVectorMeta(s, vec);
auto const vec_size = serializeVectorMeta(s, vec);

constructVectorData(vec_size, vec);
dispatch::serializeArray(s, vec.data(), vec.size());

// make sure to account for reserved space when footprinting
Expand All @@ -90,7 +167,8 @@ void serialize(Serializer& s, std::vector<bool, VectorAllocator>& vec) {
return;
}

serializeVectorMeta(s, vec);
auto const vec_size = serializeVectorMeta(s, vec);
constructVectorData(vec_size, vec);

if (!s.isUnpacking()) {
for (bool elt : vec) {
Expand Down
122 changes: 122 additions & 0 deletions tests/unit/test_serialization_error_checking.cc
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,125 @@ TEST_F(TestObject, test_serialization_error_checking_memory_usage) {
}

}}} // end namespace checkpoint::tests::unit

template <typename T>
struct MyAllocator : public std::allocator<T> {
using size_type = size_t;
using pointer = T*;
using const_pointer = const T*;

template <typename U>
struct rebind {
typedef MyAllocator<U> other;
};

pointer allocate(size_type n, const void* hint = 0) {
fprintf(stderr, "Alloc %ld bytes.\n", n * sizeof(T));
return std::allocator<T>::allocate(n, hint);
}

void deallocate(pointer p, size_type n) {
fprintf(
stderr, "Dealloc %ld bytes (%p).\n", n * sizeof(T),
reinterpret_cast<void*>(p)
);
return std::allocator<T>::deallocate(p, n);
}

MyAllocator() throw() : std::allocator<T>() {
fprintf(stderr, "Hello allocator!\n");
}

MyAllocator(const MyAllocator& a) throw() : std::allocator<T>(a) { }

template <class U>
MyAllocator(const MyAllocator<U>& a) throw() : std::allocator<T>(a) { }

~MyAllocator() throw() { }
};

template <typename T>
struct std::allocator_traits<MyAllocator<T>> {
using allocator_type = MyAllocator<T>;
using value_type = typename allocator_type::value_type;
using pointer = value_type*;
using const_pointer = const pointer;
using const_void_pointer = const void*;
using size_type = typename allocator_type::size_type;
using difference_type = typename allocator_type::difference_type;

static pointer allocate(allocator_type& a, size_type n) {
return a.allocate(n);
}

static pointer
allocate(allocator_type& a, size_type n, const_void_pointer hint) {
return a.allocate(n, hint);
}

static void deallocate(allocator_type& a, pointer p, size_type n) {
a.deallocate(p, n);
}

template <typename U, typename... Args>
static void construct(allocator_type& a, U* p, Args&&... args) {
// do nothing during construction
}

template <typename U>
static void destroy(allocator_type& a, U* p) {
a.destroy(p);
}

static size_type max_size(const allocator_type& a) noexcept {
return a.max_size();
}

template <typename U>
using rebind_alloc = typename allocator_type::template rebind<U>::other;
};

namespace checkpoint { namespace tests { namespace unit {

struct AAA {
int a;
AAA() { std::cout << "default ctor called\n"; }

template <typename Serializer>
void serialize(Serializer& s) {
s | a;
}
};

TEST_F(TestObject, test_test_test) {
using VecT = std::vector<AAA, MyAllocator<AAA>>;
VecT vec{};
vec.resize(5);

std::array<AAA, 5> array;
auto i = 0;
for (auto& a : array) {
a.a = i++;
}

std::memcpy(
reinterpret_cast<void*>(vec.data()), reinterpret_cast<void*>(&array),
array.size() * sizeof(decltype(array)::value_type)
);

std::vector<AAA> vec2{
std::make_move_iterator(vec.begin()), std::make_move_iterator(vec.end())
};

auto ret = serialize<VecT>(vec);
EXPECT_NO_THROW(deserialize<VecT>(ret->getBuffer()));
}

// TEST_F(TestObject, test_test) {
// using vecT = std::vector<std::vector<int>>;
// vecT vec{{1, 2}, {3, 4}};
// auto ret = checkpoint::serialize<vecT>(vec);
// checkpoint::deserialize<vecT>(ret->getBuffer());
// }

}}} // namespace checkpoint::tests::unit

0 comments on commit fdd3a55

Please sign in to comment.