Skip to content

Commit

Permalink
[struct_pack] support int128 uint128 with gcc or clang (#342)
Browse files Browse the repository at this point in the history
* [struct_pack] support int128/uint128, add doc & test

---------

Co-authored-by: Zezheng.Li <[email protected]>
  • Loading branch information
982945902 and poor-circle authored Jul 6, 2023
1 parent 34d0865 commit 15ed609
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 17 deletions.
6 changes: 5 additions & 1 deletion include/ylt/struct_pack/reflection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,11 @@ namespace detail {
if constexpr (is_compatible_v<T> || trivial_view<T>) {
return ignore_compatible_field;
}
else if constexpr (std::is_enum_v<T> || std::is_fundamental_v<T>) {
else if constexpr (std::is_enum_v<T> || std::is_fundamental_v<T>
#if __GNUC__ || __clang__
|| std::is_same_v<__int128,T> || std::is_same_v<unsigned __int128,T>
#endif
) {
return true;
}
else if constexpr (array<T>) {
Expand Down
45 changes: 33 additions & 12 deletions include/ylt/struct_pack/struct_pack_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,14 @@ template <typename U>
constexpr auto get_types() {
using T = std::remove_cvref_t<U>;
if constexpr (std::is_fundamental_v<T> || std::is_enum_v<T> || varint_t<T> ||
std::is_same_v<std::string, T> || container<T> || optional<T> ||
unique_ptr<T> || variant<T> || expected<T> || array<T> ||
c_array<T> || std::is_same_v<std::monostate, T>) {
string<T> || container<T> || optional<T> || unique_ptr<T> ||
variant<T> || expected<T> || array<T> || c_array<T> ||
std::is_same_v<std::monostate, T>
#if __GNUC__ || __clang__
|| std::is_same_v<__int128, T> ||
std::is_same_v<unsigned __int128, T>
#endif
) {
return declval<std::tuple<T>>();
}
else if constexpr (tuple<T>) {
Expand Down Expand Up @@ -293,7 +298,6 @@ template <typename T>
concept struct_pack_buffer = trivially_copyable_container<T>
&& struct_pack_byte<typename T::value_type>;
// clang-format on

enum class type_id {
// compatible template type
compatible_t = 0,
Expand All @@ -306,7 +310,7 @@ enum class type_id {
uint8_t,
int16_t,
uint16_t,
int128_t, // TODO: support int128/uint128
int128_t, // Tips: We only support 128-bit integer on gcc clang
uint128_t,
bool_t,
char_8_t,
Expand Down Expand Up @@ -411,14 +415,23 @@ consteval type_id get_integral_type() {
// char32_t's size maybe bigger than 32bits, which is not supported.
else if constexpr (std::is_same_v<char32_t, T> && sizeof(char32_t) == 4) {
static_assert(sizeof(char32_t) == 4,
"sizeof(char16_t)!=4, which is not supported.");
"sizeof(char32_t)!=4, which is not supported.");
return type_id::char_32_t;
}
else if constexpr (std::is_same_v<bool, T> && sizeof(bool)) {
static_assert(sizeof(bool) == 1,
"sizeof(bool)!=1, which is not supported.");
return type_id::bool_t;
}
#if __GNUC__ || __clang__
//-std=gnu++20
else if constexpr (std::is_same_v<__int128, T>) {
return type_id::int128_t;
}
else if constexpr (std::is_same_v<unsigned __int128, T>) {
return type_id::uint128_t;
}
#endif
else {
/*
* Due to different data model,
Expand Down Expand Up @@ -505,7 +518,12 @@ consteval type_id get_type_id() {
else if constexpr (std::is_enum_v<T>) {
return get_integral_type<std::underlying_type_t<T>>();
}
else if constexpr (std::is_integral_v<T>) {
else if constexpr (std::is_integral_v<T>
#if __GNUC__ || __CLANG__
|| std::is_same_v<__int128, T> ||
std::is_same_v<unsigned __int128, T>
#endif
) {
return get_integral_type<T>();
}
else if constexpr (std::is_floating_point_v<T>) {
Expand Down Expand Up @@ -560,7 +578,7 @@ consteval type_id get_type_id() {
else {
static_assert(!sizeof(T), "not supported type");
}
}
} // namespace detail

template <size_t size>
consteval decltype(auto) get_size_literal() {
Expand Down Expand Up @@ -1146,7 +1164,8 @@ constexpr size_info inline calculate_one_size(const T &item) {
size_info ret{.total = 0, .size_cnt = 0, .max_size = 0};
if constexpr (id == type_id::monostate_t) {
}
else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type>) {
else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type> ||
id == type_id::int128_t || id == type_id::uint128_t) {
ret.total = sizeof(type);
}
else if constexpr (detail::varint_t<type>) {
Expand Down Expand Up @@ -1684,7 +1703,8 @@ class packer {
else if constexpr (std::is_same_v<type, std::monostate>) {
// do nothing
}
else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type>) {
else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type> ||
id == type_id::int128_t || id == type_id::uint128_t) {
writer_.write((char *)&item, sizeof(type));
}
else if constexpr (detail::varint_t<type>) {
Expand Down Expand Up @@ -1891,7 +1911,7 @@ class packer {
friend constexpr serialize_buffer_size get_needed_size(const T &t);
writer &writer_;
const serialize_buffer_size &info;
};
}; // namespace detail

template <serialize_config conf = serialize_config{},
struct_pack::writer_t Writer, typename... Args>
Expand Down Expand Up @@ -2422,7 +2442,8 @@ class unpacker {
else if constexpr (std::is_same_v<type, std::monostate>) {
// do nothing
}
else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type>) {
else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type> ||
id == type_id::int128_t || id == type_id::uint128_t) {
if constexpr (NotSkip) {
if (!reader_.read((char *)&item, sizeof(type))) [[unlikely]] {
return struct_pack::errc::no_buffer_space;
Expand Down
22 changes: 22 additions & 0 deletions src/struct_pack/tests/test_serialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,28 @@ TEST_CASE("compatible convert to optional") {
CHECK(b.value() == "hello world");
CHECK(a.value() == "hello world");
}
#if __GNUC__ || __clang__
struct test_int_128 {
__int128_t x;
__uint128_t y;
bool operator==(const test_int_128 &) const = default;
};

TEST_CASE("test 128-bit int") {
__int128_t i = INT64_MAX;
i *= INT64_MAX;
CHECK(i > INT64_MAX);
__uint128_t j = UINT64_MAX;
j *= UINT64_MAX;
CHECK(j > UINT64_MAX);
auto vec = std::vector<test_int_128>{{i, j}, {-1 * i, j + UINT64_MAX}};
auto buffer = struct_pack::serialize(vec);
auto result = struct_pack::deserialize<std::vector<test_int_128>>(buffer);
CHECK(result == vec);
CHECK(struct_pack::detail::is_trivial_serializable<test_int_128>::value);
}

#endif

#if __cpp_lib_span >= 202002L

Expand Down
10 changes: 6 additions & 4 deletions website/docs/en/struct_pack/struct_pack_type_system.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ supported by `struct_pack`.

| Type | Meaning | code |
| ------------------------- | ----------------------------------------- | ------------------------------------------ |
| int8_t | Signed fixed-length 8-bit integer | complementary code |
| int16_t | Signed fixed-length 16-bit integer | complementary cod |
| int32_t | Signed fixed-length 32-bit integer | complementary cod |
| int64_t | Signed fixed-length 64-bit integer | complementary cod |
| int8_t | Signed fixed-length 8-bit integer | complement code |
| int16_t | Signed fixed-length 16-bit integer | complement code |
| int32_t | Signed fixed-length 32-bit integer | complement code |
| int64_t | Signed fixed-length 64-bit integer | complement code |
| int128_t (GCC/Clang only) | Signed fixed-length 64-bit integer | complement code |
| uint8_t | Unsigned fixed-length 8-bit integer | Original Code |
| uint16_t | Unsigned fixed-length 16-bit integer | Original Code |
| uint32_t | Unsigned fixed-length 32-bit integer | Original Code |
| uint64_t | Unsigned fixed-length 64-bit integer | Original Code |
| uint128_t (GCC/Clang only)| Unsigned fixed-length 64-bit integer | Original Code |
| struct_pack::var_uint32_t | Unsigned variable-length 32-bit integer | `varint` variable length code |
| struct_pack::var_uint64_t | Unsigned variable-length 64-bit integer | `varint` variable length code |
| struct_pack::var_int32_t | Signed variable-length 32-bit integers | `varint`+`zigzag` variable length encoding |
Expand Down

0 comments on commit 15ed609

Please sign in to comment.