2121
2222#include < bit>
2323#include < concepts>
24+ #include < cstdint>
2425
2526// / \file iceberg/util/endian.h
2627// / \brief Endianness conversion utilities
2728
2829namespace iceberg {
2930
30- // / \brief Concept for values that can be written in little- endian format.
31+ // / \brief Concept for values that can be converted to/from another endian format.
3132template <typename T>
3233concept EndianConvertible = std::is_arithmetic_v<T> && !std::same_as<T, bool >;
3334
35+ // / \brief Byte-swap a value. For floating-point types, only support 32-bit and 64-bit
36+ // / floats.
37+ template <EndianConvertible T>
38+ constexpr T ByteSwap (T value) {
39+ if constexpr (sizeof (T) <= 1 ) {
40+ return value;
41+ } else if constexpr (std::is_integral_v<T>) {
42+ return std::byteswap (value);
43+ } else if constexpr (std::is_floating_point_v<T>) {
44+ if constexpr (sizeof (T) == sizeof (uint32_t )) {
45+ return std::bit_cast<T>(std::byteswap (std::bit_cast<uint32_t >(value)));
46+ } else if constexpr (sizeof (T) == sizeof (uint64_t )) {
47+ return std::bit_cast<T>(std::byteswap (std::bit_cast<uint64_t >(value)));
48+ } else {
49+ static_assert (false , " Unsupported floating-point size for endian conversion." );
50+ }
51+ }
52+ }
53+
3454// / \brief Convert a value to little-endian format.
3555template <EndianConvertible T>
3656constexpr T ToLittleEndian (T value) {
3757 if constexpr (std::endian::native == std::endian::little || sizeof (T) <= 1 ) {
3858 return value;
3959 } else {
40- if constexpr (std::is_integral_v<T>) {
41- return std::byteswap (value);
42- } else if constexpr (std::is_floating_point_v<T>) {
43- // For floats, use the bit_cast -> byteswap -> bit_cast pattern.
44- if constexpr (sizeof (T) == sizeof (uint32_t )) {
45- uint32_t int_representation = std::bit_cast<uint32_t >(value);
46- int_representation = std::byteswap (int_representation);
47- return std::bit_cast<T>(int_representation);
48- } else if constexpr (sizeof (T) == sizeof (uint64_t )) {
49- uint64_t int_representation = std::bit_cast<uint64_t >(value);
50- int_representation = std::byteswap (int_representation);
51- return std::bit_cast<T>(int_representation);
52- }
53- }
60+ return ByteSwap (value);
5461 }
5562}
5663
@@ -60,20 +67,7 @@ constexpr T FromLittleEndian(T value) {
6067 if constexpr (std::endian::native == std::endian::little || sizeof (T) <= 1 ) {
6168 return value;
6269 } else {
63- if constexpr (std::is_integral_v<T>) {
64- return std::byteswap (value);
65- } else if constexpr (std::is_floating_point_v<T>) {
66- // For floats, use the bit_cast -> byteswap -> bit_cast pattern.
67- if constexpr (sizeof (T) == sizeof (uint32_t )) {
68- uint32_t int_representation = std::bit_cast<uint32_t >(value);
69- int_representation = std::byteswap (int_representation);
70- return std::bit_cast<T>(int_representation);
71- } else if constexpr (sizeof (T) == sizeof (uint64_t )) {
72- uint64_t int_representation = std::bit_cast<uint64_t >(value);
73- int_representation = std::byteswap (int_representation);
74- return std::bit_cast<T>(int_representation);
75- }
76- }
70+ return ByteSwap (value);
7771 }
7872}
7973
@@ -83,19 +77,7 @@ constexpr T ToBigEndian(T value) {
8377 if constexpr (std::endian::native == std::endian::big || sizeof (T) <= 1 ) {
8478 return value;
8579 } else {
86- if constexpr (std::is_integral_v<T>) {
87- return std::byteswap (value);
88- } else if constexpr (std::is_floating_point_v<T>) {
89- if constexpr (sizeof (T) == sizeof (uint32_t )) {
90- uint32_t int_representation = std::bit_cast<uint32_t >(value);
91- int_representation = std::byteswap (int_representation);
92- return std::bit_cast<T>(int_representation);
93- } else if constexpr (sizeof (T) == sizeof (uint64_t )) {
94- uint64_t int_representation = std::bit_cast<uint64_t >(value);
95- int_representation = std::byteswap (int_representation);
96- return std::bit_cast<T>(int_representation);
97- }
98- }
80+ return ByteSwap (value);
9981 }
10082}
10183
@@ -105,19 +87,7 @@ constexpr T FromBigEndian(T value) {
10587 if constexpr (std::endian::native == std::endian::big || sizeof (T) <= 1 ) {
10688 return value;
10789 } else {
108- if constexpr (std::is_integral_v<T>) {
109- return std::byteswap (value);
110- } else if constexpr (std::is_floating_point_v<T>) {
111- if constexpr (sizeof (T) == sizeof (uint32_t )) {
112- uint32_t int_representation = std::bit_cast<uint32_t >(value);
113- int_representation = std::byteswap (int_representation);
114- return std::bit_cast<T>(int_representation);
115- } else if constexpr (sizeof (T) == sizeof (uint64_t )) {
116- uint64_t int_representation = std::bit_cast<uint64_t >(value);
117- int_representation = std::byteswap (int_representation);
118- return std::bit_cast<T>(int_representation);
119- }
120- }
90+ return ByteSwap (value);
12191 }
12292}
12393
0 commit comments