Integral and enum serialization
This commit is contained in:
parent
55505b6288
commit
b629833958
@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace metadump {
|
||||
|
||||
}
|
||||
3
include/metadump/metadump.hpp
Normal file
3
include/metadump/metadump.hpp
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
#include <metadump/mono.hpp>
|
||||
#include <metadump/multi.hpp>
|
||||
131
include/metadump/mono.hpp
Normal file
131
include/metadump/mono.hpp
Normal file
@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <concepts>
|
||||
#include <bit>
|
||||
#include <cstring>
|
||||
|
||||
namespace metadump {
|
||||
|
||||
constexpr std::size_t SIZE_DYNAMIC = 0;
|
||||
|
||||
template<std::size_t SIZE = SIZE_DYNAMIC>
|
||||
struct serializable {
|
||||
constexpr std::size_t serial_size() const { return SIZE; };
|
||||
virtual bool serial_dump(uint8_t* data) const = 0;
|
||||
virtual bool serial_load(const uint8_t* data) = 0;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct serializable<SIZE_DYNAMIC> {
|
||||
virtual std::size_t serial_size() const = 0;
|
||||
virtual bool serial_dump(uint8_t* data, std::size_t n) const = 0;
|
||||
virtual bool serial_load(const uint8_t* data, std::size_t n) = 0;
|
||||
};
|
||||
|
||||
namespace mono {
|
||||
|
||||
// Concepts to determine serialization method
|
||||
|
||||
namespace typeswitch {
|
||||
|
||||
template<typename T>
|
||||
concept integral = std::is_integral_v<T>;
|
||||
|
||||
template<typename T>
|
||||
concept enumeration = std::is_enum_v<T>;
|
||||
|
||||
/*
|
||||
template<typename I, template<typename...> typename T>
|
||||
struct is_specialization : std::false_type{};
|
||||
|
||||
template<template<typename...> typename T, typename... IArgs>
|
||||
struct is_specialization<T<IArgs...>, T> : std::true_type{};
|
||||
|
||||
template<typename T>
|
||||
concept is_serializable = std::is_base_of_v<Serializable, T>;
|
||||
|
||||
is_(dynamic/fixed)_serializable
|
||||
|
||||
template<typename T>
|
||||
concept is_container = is_specialization<T, std::vector>::value; // list, ...
|
||||
|
||||
is_(dynamic/fixed)_container
|
||||
|
||||
template<typename T>
|
||||
concept is_forced_default = is_specialization<T, SerialForcedDefault>::value;
|
||||
|
||||
template<typename T>
|
||||
concept is_default = (!serial_integral<T> && !serial_enum<T> && !serial_serializable<T> &&
|
||||
!serial_container<T> && !serial_forced_default<T>);
|
||||
|
||||
default -> reflection to serialize all public members
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct serializer;
|
||||
|
||||
// Integral values -> convert to LITTLE endian
|
||||
template<typeswitch::integral T>
|
||||
struct serializer<T> {
|
||||
static constexpr bool SERIAL_SIZE_DYNAMIC = false;
|
||||
|
||||
static constexpr std::size_t serial_size() {
|
||||
return sizeof(T);
|
||||
}
|
||||
|
||||
static bool dump(uint8_t* data, const T& v) {
|
||||
T tmp; // Little endian
|
||||
if constexpr (std::endian::native == std::endian::little)
|
||||
tmp = v;
|
||||
else if constexpr (std::endian::native == std::endian::big)
|
||||
tmp = std::byteswap<T>(v);
|
||||
else
|
||||
return false;
|
||||
|
||||
std::memcpy(data, &tmp, sizeof(T));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool load(const uint8_t* data, T& v) {
|
||||
T tmp; // Little endian
|
||||
std::memcpy(&tmp, data, sizeof(T));
|
||||
|
||||
if constexpr (std::endian::native == std::endian::little)
|
||||
v = tmp;
|
||||
else if constexpr (std::endian::native == std::endian::big)
|
||||
v = std::byteswap<T>(tmp);
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Enum serialization -> LITTLE endian integer
|
||||
template<typeswitch::enumeration T>
|
||||
struct serializer<T> {
|
||||
static constexpr bool SERIAL_SIZE_DYNAMIC = false;
|
||||
using INTEGRAL_TYPE = std::underlying_type_t<T>;
|
||||
|
||||
static constexpr std::size_t serial_size() {
|
||||
return serializer<INTEGRAL_TYPE>::serial_size();
|
||||
}
|
||||
|
||||
static bool dump(uint8_t* data, const T& v) {
|
||||
const INTEGRAL_TYPE& i = reinterpret_cast<const INTEGRAL_TYPE&>(v);
|
||||
return serializer<INTEGRAL_TYPE>::dump(data, i);
|
||||
}
|
||||
|
||||
static bool load(const uint8_t* data, T& v) {
|
||||
INTEGRAL_TYPE& i = reinterpret_cast<INTEGRAL_TYPE&>(v);
|
||||
return serializer<INTEGRAL_TYPE>::load(data, i);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
10
include/metadump/multi.hpp
Normal file
10
include/metadump/multi.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace metadump {
|
||||
|
||||
template<typename... Ts>
|
||||
class buffer {
|
||||
// iovec array and per-component buffers
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,2 +1,2 @@
|
||||
add_executable(metadump_test_simple simple.cpp)
|
||||
target_link_libraries(metadump_test_simple PRIVATE metadump GTest::GTest)
|
||||
add_executable(metadump_mono mono.cpp)
|
||||
target_link_libraries(metadump_mono PRIVATE metadump GTest::GTest)
|
||||
|
||||
68
test/mono.cpp
Normal file
68
test/mono.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <metadump/metadump.hpp>
|
||||
|
||||
template<typename T>
|
||||
using serializer = metadump::mono::serializer<T>;
|
||||
|
||||
TEST(MONO, INTEGRAL) {
|
||||
uint8_t buf[8];
|
||||
|
||||
// Serialization of uint8_t
|
||||
|
||||
static_assert(!serializer<uint8_t>::SERIAL_SIZE_DYNAMIC, "Integral serialization size should be fixed (uint8_t)!");
|
||||
static_assert(serializer<uint8_t>::serial_size() == sizeof(uint8_t), "Integral serialization size is incorrect (uint8_t)!");
|
||||
uint8_t a8 = 0x01, b8 = 0;
|
||||
|
||||
ASSERT_TRUE(serializer<uint8_t>::dump(buf, a8)) << "Failed to dump uint8_t!";
|
||||
ASSERT_TRUE(serializer<uint8_t>::load(buf, b8)) << "Failed to load uint8_t!";
|
||||
ASSERT_EQ(a8, b8) << "Deserialized uint8_t does not match serialization input!";
|
||||
|
||||
// Serialization of uint16_t
|
||||
|
||||
static_assert(!serializer<uint16_t>::SERIAL_SIZE_DYNAMIC, "Integral serialization size should be fixed (uint16_t)!");
|
||||
static_assert(serializer<uint16_t>::serial_size() == sizeof(uint16_t), "Integral serialization size is incorrect (uint16_t)!");
|
||||
uint16_t a16 = 0x0102, b16 = 0;
|
||||
|
||||
ASSERT_TRUE(serializer<uint16_t>::dump(buf, a16)) << "Failed to dump uint16_t!";
|
||||
ASSERT_TRUE(serializer<uint16_t>::load(buf, b16)) << "Failed to load uint16_t!";
|
||||
ASSERT_EQ(a16, b16) << "Deserialized uint16_t does not match serialization input!";
|
||||
|
||||
// Serialization of uint32_t
|
||||
|
||||
static_assert(!serializer<uint32_t>::SERIAL_SIZE_DYNAMIC, "Integral serialization size should be fixed (uint32_t)!");
|
||||
static_assert(serializer<uint32_t>::serial_size() == sizeof(uint32_t), "Integral serialization size is incorrect (uint32_t)!");
|
||||
uint32_t a32 = 0x01020304, b32 = 0;
|
||||
|
||||
ASSERT_TRUE(serializer<uint32_t>::dump(buf, a32)) << "Failed to dump uint32_t!";
|
||||
ASSERT_TRUE(serializer<uint32_t>::load(buf, b32)) << "Failed to load uint32_t!";
|
||||
ASSERT_EQ(a32, b32) << "Deserialized uint32_t does not match serialization input!";
|
||||
|
||||
// Serialization of uint64_t
|
||||
|
||||
static_assert(!serializer<uint64_t>::SERIAL_SIZE_DYNAMIC, "Integral serialization size should be fixed (uint64_t)!");
|
||||
static_assert(serializer<uint64_t>::serial_size() == sizeof(uint64_t), "Integral serialization size is incorrect (uint64_t)!");
|
||||
uint64_t a64 = 0x0102030405060708ull, b64 = 0;
|
||||
|
||||
ASSERT_TRUE(serializer<uint64_t>::dump(buf, a64)) << "Failed to dump uint64_t!";
|
||||
ASSERT_TRUE(serializer<uint64_t>::load(buf, b64)) << "Failed to load uint64_t!";
|
||||
ASSERT_EQ(a64, b64) << "Deserialized uint64_t does not match serialization input!";
|
||||
}
|
||||
|
||||
TEST(MONO, ENUM) {
|
||||
uint8_t buf[4];
|
||||
enum class ENUM : uint32_t { A, B, C, D, E };
|
||||
|
||||
static_assert(!serializer<ENUM>::SERIAL_SIZE_DYNAMIC, "Enum serialization size should be fixed!");
|
||||
static_assert(serializer<ENUM>::serial_size() == sizeof(uint32_t), "Enum serialization size does not match internal type!");
|
||||
|
||||
ENUM a = ENUM::D, b = ENUM::A;
|
||||
|
||||
ASSERT_TRUE(serializer<ENUM>::dump(buf, a)) << "Failed to dump enum!";
|
||||
ASSERT_TRUE(serializer<ENUM>::load(buf, b)) << "Failed to load enum!";
|
||||
ASSERT_EQ(a, b) << "Deserialized enum does not match serialization input!";
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "metadump.hpp"
|
||||
|
||||
TEST(METADUMP_SIMPLE, EMPTY) {
|
||||
ASSERT_TRUE(false) << "Tests not implemented!";
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user