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

support int128 uint128 with gcc or clang #342

Merged
merged 7 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
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