Skip to content

Commit

Permalink
fix compile error in big endian
Browse files Browse the repository at this point in the history
  • Loading branch information
poor-circle committed Oct 12, 2023
1 parent 3c87843 commit 504e551
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 114 deletions.
10 changes: 9 additions & 1 deletion cmake/build.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
message(STATUS "-------------COMPILE Setting-------------")
message(STATUS "-------------COMPILE SETTING-------------")

# CPP Standard
foreach(i ${CMAKE_CXX_COMPILE_FEATURES})
Expand Down Expand Up @@ -31,6 +31,14 @@ if(BUILD_WITH_LIBCXX AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
else()
endif()

include (TestBigEndian)
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
if(IS_BIG_ENDIAN)
message(STATUS "ENDIAN: BIG")
else()
message(STATUS "ENDIAN: LITTLE")
endif()

# force use lld if your compiler is clang

# When using coro_rpc_client to send request, only remote function declarations are required.
Expand Down
34 changes: 16 additions & 18 deletions include/ylt/struct_pack/endian_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ constexpr inline bool is_system_little_endian =
(BYTEORDER_ENDIAN == BYTEORDER_LITTLE_ENDIAN);
#endif

template <std::size_t block_size>
constexpr inline bool is_little_endian_copyable =
is_system_little_endian || block_size == 1;

template <std::size_t block_size, typename writer_t>
void write_wrapper(writer_t& writer, const char* data) {
if constexpr (is_system_little_endian || block_size == 1) {
Expand All @@ -93,7 +97,7 @@ void write_wrapper(writer_t& writer, const char* data) {
writer.write(&tmp, block_size);
#elif defined(__clang__) || defined(__GNUC__)
auto tmp = __builtin_bswap16(*data);
writer.write(&tmp, block_size);
writer.write((char*)&tmp, block_size);
#else
writer.write(data + 1, 1);
writer.write(data, 1);
Expand All @@ -105,7 +109,7 @@ void write_wrapper(writer_t& writer, const char* data) {
writer.write(&tmp, block_size);
#elif defined(__clang__) || defined(__GNUC__)
auto tmp = __builtin_bswap32(*data);
writer.write(&tmp, block_size);
writer.write((char*)&tmp, block_size);
#else
writer.write(data + 3, 1);
writer.write(data + 2, 1);
Expand All @@ -119,7 +123,7 @@ void write_wrapper(writer_t& writer, const char* data) {
writer.write(&tmp, block_size);
#elif defined(__clang__) || defined(__GNUC__)
auto tmp = __builtin_bswap64(*data);
writer.write(&tmp, block_size);
writer.write((char*)&tmp, block_size);
#else
writer.write(data + 7, 1);
writer.write(data + 6, 1);
Expand All @@ -138,8 +142,8 @@ void write_wrapper(writer_t& writer, const char* data) {
writer.write(&tmp1, block_size);
#elif defined(__clang__) || defined(__GNUC__)
auto tmp1 = __builtin_bswap64(*data), tmp2 = __builtin_bswap64(*data + 8);
writer.write(&tmp2, block_size);
writer.write(&tmp1, block_size);
writer.write((char*)&tmp2, block_size);
writer.write((char*)&tmp1, block_size);
#else
writer.write(data + 15, 1);
writer.write(data + 14, 1);
Expand All @@ -160,7 +164,7 @@ void write_wrapper(writer_t& writer, const char* data) {
#endif
}
else {
static_assert(sizeof(writer), "illegal block size(should be 1,2,4,8,16)");
static_assert(!sizeof(writer), "illegal block size(should be 1,2,4,8,16)");
}
}
template <std::size_t block_size, typename writer_t>
Expand All @@ -174,10 +178,7 @@ void write_wrapper(writer_t& writer, const char* data,
writer.write(data, total_sz);
}
else {
for (std::size_t i = 0; i < block_count; ++i) {
write_wrapper<block_size>(writer, data);
data += block_size;
}
static_assert(!sizeof(writer_t), "illegal use");
}
}
template <std::size_t block_size, typename reader_t>
Expand All @@ -187,7 +188,7 @@ bool read_wrapper(reader_t& reader, char* SP_RESTRICT data) {
}
else {
std::array<char, block_size> tmp;
bool res = static_cast<bool>(reader.read(&tmp, block_size));
bool res = static_cast<bool>(reader.read((char*)&tmp, block_size));
if SP_UNLIKELY (res) {
return res;
}
Expand Down Expand Up @@ -256,8 +257,10 @@ bool read_wrapper(reader_t& reader, char* SP_RESTRICT data) {
#endif
}
else {
static_assert(sizeof(reader), "illegal block size(should be 1,2,4,8,16)");
static_assert(!sizeof(reader),
"illegal block size(should be 1,2,4,8,16)");
}
return true;
}
}
template <std::size_t block_size, typename reader_t>
Expand All @@ -271,12 +274,7 @@ bool read_wrapper(reader_t& reader, char* SP_RESTRICT data,
return static_cast<bool>(reader.read(data, total_sz));
}
else {
for (std::size_t i = 0; i < block_count; ++i) {
if SP_UNLIKELY (!read_wrapper<block_size>(reader, data)) {
return false;
}
data += block_size;
}
static_assert(!sizeof(reader_t), "illegal use");
}
}
}; // namespace struct_pack::detail
21 changes: 13 additions & 8 deletions include/ylt/struct_pack/packer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "calculate_size.hpp"
#include "endian_wrapper.hpp"
#include "reflection.hpp"
#include "ylt/struct_pack/type_id.hpp"
#include "ylt/struct_pack/util.h"
namespace struct_pack::detail {
template <
Expand Down Expand Up @@ -158,10 +159,12 @@ class packer {
// do nothing
}
else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type> ||
id == type_id::int128_t || id == type_id::uint128_t ||
id == type_id::bitset_t) {
id == type_id::int128_t || id == type_id::uint128_t) {
write_wrapper<sizeof(item)>(writer_, (char *)&item);
}
else if constexpr (id == type_id::bitset_t) {
write_wrapper<sizeof(char)>(writer_, (char *)&item, sizeof(item));
}
else if constexpr (unique_ptr<type>) {
bool has_value = (item != nullptr);
write_wrapper<sizeof(char)>(writer_, (char *)&has_value);
Expand All @@ -188,9 +191,10 @@ class packer {
detail::serialize_varint(writer_, item);
}
else if constexpr (id == type_id::array_t) {
if constexpr (is_trivial_serializable<type>::value) {
write_wrapper<sizeof(decltype(item[0]))>(
writer_, (char *)&item, sizeof(type) / sizeof(decltype(item[0])));
if constexpr (is_trivial_serializable<type>::value &&
is_little_endian_copyable<sizeof(item[0])>) {
write_wrapper<sizeof(item[0])>(writer_, (char *)&item,
sizeof(type) / sizeof(item[0]));
}
else {
for (const auto &i : item) {
Expand Down Expand Up @@ -242,7 +246,8 @@ class packer {
}
}
#endif
if constexpr (trivially_copyable_container<type>) {
if constexpr (trivially_copyable_container<type> &&
is_little_endian_copyable<sizeof(typename type::value_type)>) {
using value_type = typename type::value_type;
write_wrapper<sizeof(value_type)>(writer_, (char *)item.data(),
item.size());
Expand Down Expand Up @@ -303,11 +308,11 @@ class packer {
"struct_pack only support aggregated type, or you should "
"add macro STRUCT_PACK_REFL(Type,field1,field2...)");
if constexpr (is_trivial_serializable<type>::value &&
is_system_little_endian) {
is_little_endian_copyable<sizeof(type)>) {
write_wrapper<sizeof(type)>(writer_, (char *)&item);
}
else if constexpr ((is_trivial_serializable<type>::value &&
!is_system_little_endian) ||
!is_little_endian_copyable<sizeof(type)>) ||
is_trivial_serializable<type, true>::value) {
visit_members(item, [&](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
int i = 1;
Expand Down
43 changes: 32 additions & 11 deletions include/ylt/struct_pack/unpacker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,8 +581,9 @@ class unpacker {
"The Reader isn't a view_reader, can't deserialize "
"a trivial_view<T>");
static_assert(
is_system_little_endian || sizeof(typename type::value_type) == 1,
"get a trivial view in big-endian system is limited.");
is_little_endian_copyable<sizeof(typename type::value_type)>,
"get a trivial view with byte width > 1 in big-endian system is "
"not allowed.");
const char *view = reader_.read_view(sizeof(typename T::value_type));
if SP_LIKELY (view != nullptr) {
item = *reinterpret_cast<const typename T::value_type *>(view);
Expand All @@ -600,8 +601,7 @@ class unpacker {
// do nothing
}
else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type> ||
id == type_id::int128_t || id == type_id::uint128_t ||
id == type_id::bitset_t) {
id == type_id::int128_t || id == type_id::uint128_t) {
if constexpr (NotSkip) {
if SP_UNLIKELY (!read_wrapper<sizeof(type)>(reader_, (char *)&item)) {
return struct_pack::errc::no_buffer_space;
Expand All @@ -611,6 +611,17 @@ class unpacker {
return reader_.ignore(sizeof(type)) ? errc{} : errc::no_buffer_space;
}
}
else if constexpr (id == type_id::bitset_t) {
if constexpr (NotSkip) {
if SP_UNLIKELY (!read_wrapper<sizeof(char)>(reader_, (char *)&item,
sizeof(type))) {
return struct_pack::errc::no_buffer_space;
}
}
else {
return reader_.ignore(sizeof(type)) ? errc{} : errc::no_buffer_space;
}
}
else if constexpr (unique_ptr<type>) {
bool has_value{};
if SP_UNLIKELY (!read_wrapper<sizeof(bool)>(reader_,
Expand Down Expand Up @@ -646,7 +657,8 @@ class unpacker {
code = detail::deserialize_varint<NotSkip>(reader_, item);
}
else if constexpr (id == type_id::array_t) {
if constexpr (is_trivial_serializable<type>::value) {
if constexpr (is_trivial_serializable<type>::value &&
is_little_endian_copyable<sizeof(item[0])>) {
if constexpr (NotSkip) {
if SP_UNLIKELY (!read_wrapper<sizeof(item[0])>(
reader_, (char *)&item,
Expand Down Expand Up @@ -782,16 +794,16 @@ class unpacker {
view_reader_t<Reader>,
"The Reader isn't a view_reader, can't deserialize "
"a string_view/span");
static_assert(
sizeof(value_type) == 1 || is_system_little_endian,
"zero-copy in big endian is limit.");
static_assert(is_little_endian_copyable<sizeof(value_type)>,
"zero-copy in big endian is limit.");
const char *view = reader_.read_view(mem_sz);
if SP_UNLIKELY (view == nullptr) {
return struct_pack::errc::no_buffer_space;
}
item = {(value_type *)(view), (std::size_t)size64};
}
else {
else if constexpr (is_little_endian_copyable<sizeof(
value_type)>) {
if SP_UNLIKELY (mem_sz >= PTRDIFF_MAX)
unreachable();
else {
Expand All @@ -802,6 +814,15 @@ class unpacker {
}
}
}
else {
item.resize(size64);
for (auto &i : item) {
code = deserialize_one<size_type, version, NotSkip>(i);
if SP_UNLIKELY (code != struct_pack::errc{}) {
return code;
}
}
}
}
else {
return reader_.ignore(mem_sz) ? errc{} : errc::no_buffer_space;
Expand Down Expand Up @@ -897,7 +918,7 @@ class unpacker {
"struct_pack only support aggregated type, or you should "
"add macro STRUCT_PACK_REFL(Type,field1,field2...)");
if constexpr (is_trivial_serializable<type>::value &&
is_system_little_endian) {
is_little_endian_copyable<sizeof(type)>) {
if constexpr (NotSkip) {
if SP_UNLIKELY (!read_wrapper<sizeof(type)>(reader_,
(char *)&item)) {
Expand All @@ -910,7 +931,7 @@ class unpacker {
}
}
else if constexpr ((is_trivial_serializable<type>::value &&
!is_system_little_endian) ||
!is_little_endian_copyable<sizeof(type)>) ||
is_trivial_serializable<type, true>::value) {
visit_members(item, [&](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
int i = 1;
Expand Down
6 changes: 6 additions & 0 deletions src/struct_pack/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ add_executable(struct_pack_test
main.cpp
)
add_test(NAME struct_pack_test COMMAND struct_pack_test)
include (TestBigEndian)
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
if(NOT IS_BIG_ENDIAN)
target_compile_definitions(struct_pack_test PRIVATE STRUCT_PACK_ENABLE_UNPORTABLE_TYPE TEST_IN_LITTLE_ENDIAN)
else()
target_compile_definitions(struct_pack_test PRIVATE STRUCT_PACK_ENABLE_UNPORTABLE_TYPE)
endif()
add_custom_command(
TARGET struct_pack_test PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
Expand Down
Loading

0 comments on commit 504e551

Please sign in to comment.