From 3307ffa1310464a2d9c2b2172789fb76f64e618d Mon Sep 17 00:00:00 2001 From: Li Feiyang Date: Wed, 27 Aug 2025 10:53:00 +0800 Subject: [PATCH 1/4] feat: implement endian conversion utilities --- src/iceberg/util/endian.h | 124 ++++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 3 +- test/endian_test.cc | 121 +++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 src/iceberg/util/endian.h create mode 100644 test/endian_test.cc diff --git a/src/iceberg/util/endian.h b/src/iceberg/util/endian.h new file mode 100644 index 000000000..509da9eed --- /dev/null +++ b/src/iceberg/util/endian.h @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#pragma once + +#include +#include + +/// \file iceberg/util/endian.h +/// \brief Endianness conversion utilities + +namespace iceberg { + +/// \brief Concept for values that can be written in little-endian format. +template +concept EndianConvertible = std::is_arithmetic_v && !std::same_as; + +/// \brief Convert a value to little-endian format. +template +constexpr T ToLittleEndian(T value) { + if constexpr (std::endian::native == std::endian::little || sizeof(T) <= 1) { + return value; + } else { + if constexpr (std::is_integral_v) { + return std::byteswap(value); + } else if constexpr (std::is_floating_point_v) { + // For floats, use the bit_cast -> byteswap -> bit_cast pattern. + if constexpr (sizeof(T) == sizeof(uint32_t)) { + uint32_t int_representation = std::bit_cast(value); + int_representation = std::byteswap(int_representation); + return std::bit_cast(int_representation); + } else if constexpr (sizeof(T) == sizeof(uint64_t)) { + uint64_t int_representation = std::bit_cast(value); + int_representation = std::byteswap(int_representation); + return std::bit_cast(int_representation); + } + } + } +} + +/// \brief Convert a value from little-endian format. +template +constexpr T FromLittleEndian(T value) { + if constexpr (std::endian::native == std::endian::little || sizeof(T) <= 1) { + return value; + } else { + if constexpr (std::is_integral_v) { + return std::byteswap(value); + } else if constexpr (std::is_floating_point_v) { + // For floats, use the bit_cast -> byteswap -> bit_cast pattern. + if constexpr (sizeof(T) == sizeof(uint32_t)) { + uint32_t int_representation = std::bit_cast(value); + int_representation = std::byteswap(int_representation); + return std::bit_cast(int_representation); + } else if constexpr (sizeof(T) == sizeof(uint64_t)) { + uint64_t int_representation = std::bit_cast(value); + int_representation = std::byteswap(int_representation); + return std::bit_cast(int_representation); + } + } + } +} + +/// \brief Convert a value to big-endian format. +template +constexpr T ToBigEndian(T value) { + if constexpr (std::endian::native == std::endian::big || sizeof(T) <= 1) { + return value; + } else { + if constexpr (std::is_integral_v) { + return std::byteswap(value); + } else if constexpr (std::is_floating_point_v) { + if constexpr (sizeof(T) == sizeof(uint32_t)) { + uint32_t int_representation = std::bit_cast(value); + int_representation = std::byteswap(int_representation); + return std::bit_cast(int_representation); + } else if constexpr (sizeof(T) == sizeof(uint64_t)) { + uint64_t int_representation = std::bit_cast(value); + int_representation = std::byteswap(int_representation); + return std::bit_cast(int_representation); + } + } + } +} + +/// \brief Convert a value from big-endian format. +template +constexpr T FromBigEndian(T value) { + if constexpr (std::endian::native == std::endian::big || sizeof(T) <= 1) { + return value; + } else { + if constexpr (std::is_integral_v) { + return std::byteswap(value); + } else if constexpr (std::is_floating_point_v) { + if constexpr (sizeof(T) == sizeof(uint32_t)) { + uint32_t int_representation = std::bit_cast(value); + int_representation = std::byteswap(int_representation); + return std::bit_cast(int_representation); + } else if constexpr (sizeof(T) == sizeof(uint64_t)) { + uint64_t int_representation = std::bit_cast(value); + int_representation = std::byteswap(int_representation); + return std::bit_cast(int_representation); + } + } + } +} + +} // namespace iceberg diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8dbb3df86..6ee5cd901 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -89,7 +89,8 @@ add_iceberg_test(util_test formatter_test.cc config_test.cc visit_type_test.cc - string_util_test.cc) + string_util_test.cc + endian_test.cc) if(ICEBERG_BUILD_BUNDLE) add_iceberg_test(avro_test diff --git a/test/endian_test.cc b/test/endian_test.cc new file mode 100644 index 000000000..716f38c14 --- /dev/null +++ b/test/endian_test.cc @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "iceberg/util/endian.h" + +#include +#include +#include + +#include + +namespace iceberg { + +// test round trip preserves value +TEST(EndianTest, RoundTripPreservesValue) { + EXPECT_EQ(FromLittleEndian(ToLittleEndian(0x1234)), 0x1234); + EXPECT_EQ(FromBigEndian(ToBigEndian(0xDEADBEEF)), 0xDEADBEEF); + EXPECT_EQ(FromLittleEndian(ToLittleEndian(std::numeric_limits::max())), + std::numeric_limits::max()); + EXPECT_EQ(FromBigEndian(ToBigEndian(0)), 0); + + EXPECT_EQ(FromBigEndian(ToBigEndian(-1)), -1); + EXPECT_EQ(FromLittleEndian(ToLittleEndian(-0x12345678)), -0x12345678); + EXPECT_EQ(FromBigEndian(ToBigEndian(std::numeric_limits::min())), + std::numeric_limits::min()); + EXPECT_EQ(FromLittleEndian(ToLittleEndian(std::numeric_limits::max())), + std::numeric_limits::max()); + + EXPECT_EQ(FromLittleEndian(ToLittleEndian(3.14f)), 3.14f); + EXPECT_EQ(FromBigEndian(ToBigEndian(2.718281828459045)), 2.718281828459045); + + EXPECT_EQ(FromLittleEndian(ToLittleEndian(std::numeric_limits::infinity())), + std::numeric_limits::infinity()); + EXPECT_EQ(FromBigEndian(ToBigEndian(-std::numeric_limits::infinity())), + -std::numeric_limits::infinity()); + EXPECT_TRUE(std::isnan( + FromLittleEndian(ToLittleEndian(std::numeric_limits::quiet_NaN())))); + EXPECT_EQ(FromBigEndian(ToBigEndian(0.0f)), 0.0f); + EXPECT_EQ(FromLittleEndian(ToLittleEndian(-0.0f)), -0.0f); + + EXPECT_EQ(FromBigEndian(ToBigEndian(std::numeric_limits::infinity())), + std::numeric_limits::infinity()); + EXPECT_EQ(FromLittleEndian(ToLittleEndian(-std::numeric_limits::infinity())), + -std::numeric_limits::infinity()); + EXPECT_TRUE( + std::isnan(FromBigEndian(ToBigEndian(std::numeric_limits::quiet_NaN())))); + EXPECT_EQ(FromLittleEndian(ToLittleEndian(0.0)), 0.0); + EXPECT_EQ(FromBigEndian(ToBigEndian(-0.0)), -0.0); +} + +// test constexpr evaluation +TEST(EndianTest, ConstexprEvaluation) { + static_assert(FromBigEndian(ToBigEndian(0x1234)) == 0x1234); + static_assert(FromLittleEndian(ToLittleEndian(0x12345678)) == 0x12345678); + static_assert(FromBigEndian(ToBigEndian(-1)) == -1); + + static_assert(ToBigEndian(0xFF) == 0xFF); + static_assert(FromLittleEndian(-1) == -1); + + static_assert(FromLittleEndian(ToLittleEndian(3.14f)) == 3.14f); + static_assert(FromBigEndian(ToBigEndian(2.718)) == 2.718); +} + +// test platform dependent behavior +TEST(EndianTest, PlatformDependentBehavior) { + uint32_t test_value = 0x12345678; + + if constexpr (std::endian::native == std::endian::little) { + EXPECT_EQ(ToLittleEndian(test_value), test_value); + EXPECT_EQ(FromLittleEndian(test_value), test_value); + EXPECT_NE(ToBigEndian(test_value), test_value); + } else if constexpr (std::endian::native == std::endian::big) { + EXPECT_EQ(ToBigEndian(test_value), test_value); + EXPECT_EQ(FromBigEndian(test_value), test_value); + EXPECT_NE(ToLittleEndian(test_value), test_value); + } + + EXPECT_EQ(ToLittleEndian(0xAB), 0xAB); + EXPECT_EQ(ToBigEndian(0xAB), 0xAB); +} + +// test specific byte pattern validation +TEST(EndianTest, SpecificBytePatternValidation) { + uint32_t original_int = 0x12345678; + uint32_t little_endian_int = ToLittleEndian(original_int); + uint32_t big_endian_int = ToBigEndian(original_int); + + auto little_int_bytes = std::bit_cast>(little_endian_int); + auto big_int_bytes = std::bit_cast>(big_endian_int); + + EXPECT_EQ(little_int_bytes, (std::array{0x78, 0x56, 0x34, 0x12})); + EXPECT_EQ(big_int_bytes, (std::array{0x12, 0x34, 0x56, 0x78})); + + float original_float = 3.14f; + float little_endian_float = ToLittleEndian(original_float); + float big_endian_float = ToBigEndian(original_float); + + auto little_float_bytes = std::bit_cast>(little_endian_float); + auto big_float_bytes = std::bit_cast>(big_endian_float); + + EXPECT_EQ(little_float_bytes, (std::array{0xC3, 0xF5, 0x48, 0x40})); + EXPECT_EQ(big_float_bytes, (std::array{0x40, 0x48, 0xF5, 0xC3})); +} + +} // namespace iceberg From 8a121e1882068e28b266ca695d130ac6eda9e0cf Mon Sep 17 00:00:00 2001 From: Li Feiyang Date: Wed, 27 Aug 2025 18:15:48 +0800 Subject: [PATCH 2/4] feat: implement endian conversion utilities --- src/iceberg/util/endian.h | 80 ++++++++++++--------------------------- test/CMakeLists.txt | 6 +-- 2 files changed, 28 insertions(+), 58 deletions(-) diff --git a/src/iceberg/util/endian.h b/src/iceberg/util/endian.h index 509da9eed..96bb643db 100644 --- a/src/iceberg/util/endian.h +++ b/src/iceberg/util/endian.h @@ -21,36 +21,43 @@ #include #include +#include /// \file iceberg/util/endian.h /// \brief Endianness conversion utilities namespace iceberg { -/// \brief Concept for values that can be written in little-endian format. +/// \brief Concept for values that can be converted to/from another endian format. template concept EndianConvertible = std::is_arithmetic_v && !std::same_as; +/// \brief Byte-swap a value. For floating-point types, only support 32-bit and 64-bit +/// floats. +template +constexpr T ByteSwap(T value) { + if constexpr (sizeof(T) <= 1) { + return value; + } else if constexpr (std::is_integral_v) { + return std::byteswap(value); + } else if constexpr (std::is_floating_point_v) { + if constexpr (sizeof(T) == sizeof(uint32_t)) { + return std::bit_cast(std::byteswap(std::bit_cast(value))); + } else if constexpr (sizeof(T) == sizeof(uint64_t)) { + return std::bit_cast(std::byteswap(std::bit_cast(value))); + } else { + static_assert(false, "Unsupported floating-point size for endian conversion."); + } + } +} + /// \brief Convert a value to little-endian format. template constexpr T ToLittleEndian(T value) { if constexpr (std::endian::native == std::endian::little || sizeof(T) <= 1) { return value; } else { - if constexpr (std::is_integral_v) { - return std::byteswap(value); - } else if constexpr (std::is_floating_point_v) { - // For floats, use the bit_cast -> byteswap -> bit_cast pattern. - if constexpr (sizeof(T) == sizeof(uint32_t)) { - uint32_t int_representation = std::bit_cast(value); - int_representation = std::byteswap(int_representation); - return std::bit_cast(int_representation); - } else if constexpr (sizeof(T) == sizeof(uint64_t)) { - uint64_t int_representation = std::bit_cast(value); - int_representation = std::byteswap(int_representation); - return std::bit_cast(int_representation); - } - } + return ByteSwap(value); } } @@ -60,20 +67,7 @@ constexpr T FromLittleEndian(T value) { if constexpr (std::endian::native == std::endian::little || sizeof(T) <= 1) { return value; } else { - if constexpr (std::is_integral_v) { - return std::byteswap(value); - } else if constexpr (std::is_floating_point_v) { - // For floats, use the bit_cast -> byteswap -> bit_cast pattern. - if constexpr (sizeof(T) == sizeof(uint32_t)) { - uint32_t int_representation = std::bit_cast(value); - int_representation = std::byteswap(int_representation); - return std::bit_cast(int_representation); - } else if constexpr (sizeof(T) == sizeof(uint64_t)) { - uint64_t int_representation = std::bit_cast(value); - int_representation = std::byteswap(int_representation); - return std::bit_cast(int_representation); - } - } + return ByteSwap(value); } } @@ -83,19 +77,7 @@ constexpr T ToBigEndian(T value) { if constexpr (std::endian::native == std::endian::big || sizeof(T) <= 1) { return value; } else { - if constexpr (std::is_integral_v) { - return std::byteswap(value); - } else if constexpr (std::is_floating_point_v) { - if constexpr (sizeof(T) == sizeof(uint32_t)) { - uint32_t int_representation = std::bit_cast(value); - int_representation = std::byteswap(int_representation); - return std::bit_cast(int_representation); - } else if constexpr (sizeof(T) == sizeof(uint64_t)) { - uint64_t int_representation = std::bit_cast(value); - int_representation = std::byteswap(int_representation); - return std::bit_cast(int_representation); - } - } + return ByteSwap(value); } } @@ -105,19 +87,7 @@ constexpr T FromBigEndian(T value) { if constexpr (std::endian::native == std::endian::big || sizeof(T) <= 1) { return value; } else { - if constexpr (std::is_integral_v) { - return std::byteswap(value); - } else if constexpr (std::is_floating_point_v) { - if constexpr (sizeof(T) == sizeof(uint32_t)) { - uint32_t int_representation = std::bit_cast(value); - int_representation = std::byteswap(int_representation); - return std::bit_cast(int_representation); - } else if constexpr (sizeof(T) == sizeof(uint64_t)) { - uint64_t int_representation = std::bit_cast(value); - int_representation = std::byteswap(int_representation); - return std::bit_cast(int_representation); - } - } + return ByteSwap(value); } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6ee5cd901..42ad13209 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -86,11 +86,11 @@ add_iceberg_test(json_serde_test add_iceberg_test(util_test SOURCES - formatter_test.cc config_test.cc - visit_type_test.cc + endian_test.cc + formatter_test.cc string_util_test.cc - endian_test.cc) + visit_type_test.cc) if(ICEBERG_BUILD_BUNDLE) add_iceberg_test(avro_test From b2ed0c336f2a98c23375c6e17a808be370ff267d Mon Sep 17 00:00:00 2001 From: Li Feiyang Date: Thu, 28 Aug 2025 00:50:10 +0800 Subject: [PATCH 3/4] fix ci --- test/endian_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/endian_test.cc b/test/endian_test.cc index 716f38c14..33197b78c 100644 --- a/test/endian_test.cc +++ b/test/endian_test.cc @@ -74,7 +74,7 @@ TEST(EndianTest, ConstexprEvaluation) { static_assert(FromLittleEndian(-1) == -1); static_assert(FromLittleEndian(ToLittleEndian(3.14f)) == 3.14f); - static_assert(FromBigEndian(ToBigEndian(2.718)) == 2.718); + static_assert(FromBigEndian(ToBigEndian(2.71)) == 2.71); } // test platform dependent behavior From 8fc6c85f6e478e844c35a270c2b355c3cae8454a Mon Sep 17 00:00:00 2001 From: Li Feiyang Date: Mon, 1 Sep 2025 16:20:54 +0800 Subject: [PATCH 4/4] fix review --- src/iceberg/util/endian.h | 14 +++--- test/endian_test.cc | 92 ++++++++++++--------------------------- 2 files changed, 37 insertions(+), 69 deletions(-) diff --git a/src/iceberg/util/endian.h b/src/iceberg/util/endian.h index 96bb643db..30c38baee 100644 --- a/src/iceberg/util/endian.h +++ b/src/iceberg/util/endian.h @@ -30,7 +30,7 @@ namespace iceberg { /// \brief Concept for values that can be converted to/from another endian format. template -concept EndianConvertible = std::is_arithmetic_v && !std::same_as; +concept EndianConvertible = std::is_arithmetic_v; /// \brief Byte-swap a value. For floating-point types, only support 32-bit and 64-bit /// floats. @@ -41,7 +41,9 @@ constexpr T ByteSwap(T value) { } else if constexpr (std::is_integral_v) { return std::byteswap(value); } else if constexpr (std::is_floating_point_v) { - if constexpr (sizeof(T) == sizeof(uint32_t)) { + if constexpr (sizeof(T) == sizeof(uint16_t)) { + return std::bit_cast(std::byteswap(std::bit_cast(value))); + } else if constexpr (sizeof(T) == sizeof(uint32_t)) { return std::bit_cast(std::byteswap(std::bit_cast(value))); } else if constexpr (sizeof(T) == sizeof(uint64_t)) { return std::bit_cast(std::byteswap(std::bit_cast(value))); @@ -54,7 +56,7 @@ constexpr T ByteSwap(T value) { /// \brief Convert a value to little-endian format. template constexpr T ToLittleEndian(T value) { - if constexpr (std::endian::native == std::endian::little || sizeof(T) <= 1) { + if constexpr (std::endian::native == std::endian::little) { return value; } else { return ByteSwap(value); @@ -64,7 +66,7 @@ constexpr T ToLittleEndian(T value) { /// \brief Convert a value from little-endian format. template constexpr T FromLittleEndian(T value) { - if constexpr (std::endian::native == std::endian::little || sizeof(T) <= 1) { + if constexpr (std::endian::native == std::endian::little) { return value; } else { return ByteSwap(value); @@ -74,7 +76,7 @@ constexpr T FromLittleEndian(T value) { /// \brief Convert a value to big-endian format. template constexpr T ToBigEndian(T value) { - if constexpr (std::endian::native == std::endian::big || sizeof(T) <= 1) { + if constexpr (std::endian::native == std::endian::big) { return value; } else { return ByteSwap(value); @@ -84,7 +86,7 @@ constexpr T ToBigEndian(T value) { /// \brief Convert a value from big-endian format. template constexpr T FromBigEndian(T value) { - if constexpr (std::endian::native == std::endian::big || sizeof(T) <= 1) { + if constexpr (std::endian::native == std::endian::big) { return value; } else { return ByteSwap(value); diff --git a/test/endian_test.cc b/test/endian_test.cc index 33197b78c..b62644cf4 100644 --- a/test/endian_test.cc +++ b/test/endian_test.cc @@ -27,76 +27,42 @@ namespace iceberg { -// test round trip preserves value +#define EXPECT_ROUNDTRIP(value) \ + do { \ + EXPECT_EQ(FromLittleEndian(ToLittleEndian(value)), value); \ + EXPECT_EQ(FromBigEndian(ToBigEndian(value)), value); \ + } while (false) + TEST(EndianTest, RoundTripPreservesValue) { - EXPECT_EQ(FromLittleEndian(ToLittleEndian(0x1234)), 0x1234); - EXPECT_EQ(FromBigEndian(ToBigEndian(0xDEADBEEF)), 0xDEADBEEF); - EXPECT_EQ(FromLittleEndian(ToLittleEndian(std::numeric_limits::max())), - std::numeric_limits::max()); - EXPECT_EQ(FromBigEndian(ToBigEndian(0)), 0); - - EXPECT_EQ(FromBigEndian(ToBigEndian(-1)), -1); - EXPECT_EQ(FromLittleEndian(ToLittleEndian(-0x12345678)), -0x12345678); - EXPECT_EQ(FromBigEndian(ToBigEndian(std::numeric_limits::min())), - std::numeric_limits::min()); - EXPECT_EQ(FromLittleEndian(ToLittleEndian(std::numeric_limits::max())), - std::numeric_limits::max()); - - EXPECT_EQ(FromLittleEndian(ToLittleEndian(3.14f)), 3.14f); - EXPECT_EQ(FromBigEndian(ToBigEndian(2.718281828459045)), 2.718281828459045); - - EXPECT_EQ(FromLittleEndian(ToLittleEndian(std::numeric_limits::infinity())), - std::numeric_limits::infinity()); - EXPECT_EQ(FromBigEndian(ToBigEndian(-std::numeric_limits::infinity())), - -std::numeric_limits::infinity()); + EXPECT_ROUNDTRIP(static_cast(0x1234)); + EXPECT_ROUNDTRIP(static_cast(0xDEADBEEF)); + EXPECT_ROUNDTRIP(std::numeric_limits::max()); + EXPECT_ROUNDTRIP(static_cast(0)); + + EXPECT_ROUNDTRIP(static_cast(-1)); + EXPECT_ROUNDTRIP(static_cast(-0x12345678)); + EXPECT_ROUNDTRIP(std::numeric_limits::min()); + EXPECT_ROUNDTRIP(std::numeric_limits::max()); + + EXPECT_ROUNDTRIP(3.14f); + EXPECT_ROUNDTRIP(2.718281828459045); + EXPECT_ROUNDTRIP(0.0f); + EXPECT_ROUNDTRIP(-0.0f); + EXPECT_ROUNDTRIP(0.0); + EXPECT_ROUNDTRIP(-0.0); + + EXPECT_ROUNDTRIP(std::numeric_limits::infinity()); + EXPECT_ROUNDTRIP(-std::numeric_limits::infinity()); + EXPECT_ROUNDTRIP(std::numeric_limits::infinity()); + EXPECT_ROUNDTRIP(-std::numeric_limits::infinity()); + EXPECT_TRUE(std::isnan( FromLittleEndian(ToLittleEndian(std::numeric_limits::quiet_NaN())))); - EXPECT_EQ(FromBigEndian(ToBigEndian(0.0f)), 0.0f); - EXPECT_EQ(FromLittleEndian(ToLittleEndian(-0.0f)), -0.0f); - - EXPECT_EQ(FromBigEndian(ToBigEndian(std::numeric_limits::infinity())), - std::numeric_limits::infinity()); - EXPECT_EQ(FromLittleEndian(ToLittleEndian(-std::numeric_limits::infinity())), - -std::numeric_limits::infinity()); EXPECT_TRUE( std::isnan(FromBigEndian(ToBigEndian(std::numeric_limits::quiet_NaN())))); - EXPECT_EQ(FromLittleEndian(ToLittleEndian(0.0)), 0.0); - EXPECT_EQ(FromBigEndian(ToBigEndian(-0.0)), -0.0); -} - -// test constexpr evaluation -TEST(EndianTest, ConstexprEvaluation) { - static_assert(FromBigEndian(ToBigEndian(0x1234)) == 0x1234); - static_assert(FromLittleEndian(ToLittleEndian(0x12345678)) == 0x12345678); - static_assert(FromBigEndian(ToBigEndian(-1)) == -1); - - static_assert(ToBigEndian(0xFF) == 0xFF); - static_assert(FromLittleEndian(-1) == -1); - - static_assert(FromLittleEndian(ToLittleEndian(3.14f)) == 3.14f); - static_assert(FromBigEndian(ToBigEndian(2.71)) == 2.71); -} - -// test platform dependent behavior -TEST(EndianTest, PlatformDependentBehavior) { - uint32_t test_value = 0x12345678; - - if constexpr (std::endian::native == std::endian::little) { - EXPECT_EQ(ToLittleEndian(test_value), test_value); - EXPECT_EQ(FromLittleEndian(test_value), test_value); - EXPECT_NE(ToBigEndian(test_value), test_value); - } else if constexpr (std::endian::native == std::endian::big) { - EXPECT_EQ(ToBigEndian(test_value), test_value); - EXPECT_EQ(FromBigEndian(test_value), test_value); - EXPECT_NE(ToLittleEndian(test_value), test_value); - } - - EXPECT_EQ(ToLittleEndian(0xAB), 0xAB); - EXPECT_EQ(ToBigEndian(0xAB), 0xAB); } -// test specific byte pattern validation -TEST(EndianTest, SpecificBytePatternValidation) { +TEST(EndianTest, ByteWiseValidation) { uint32_t original_int = 0x12345678; uint32_t little_endian_int = ToLittleEndian(original_int); uint32_t big_endian_int = ToBigEndian(original_int);