| // Copyright 2020 The Pigweed Authors |
| // |
| // Licensed 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 |
| // |
| // https://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 "pw_bytes/endian.h" |
| |
| #include <array> |
| #include <cstddef> |
| |
| #include "gtest/gtest.h" |
| |
| namespace pw::bytes { |
| namespace { |
| |
| constexpr std::endian kNonNative = (std::endian::native == std::endian::little) |
| ? std::endian::big |
| : std::endian::little; |
| |
| // ConvertOrderTo/From |
| // |
| // ConvertOrderTo and ConvertOrderFrom are implemented identically, but are |
| // provided as separate functions to improve readability where they are used. |
| // |
| // clang-format off |
| |
| // Native endianess conversions (should do nothing) |
| |
| // Convert unsigned to native endianness |
| static_assert(ConvertOrderTo(std::endian::native, uint8_t{0x12}) == uint8_t{0x12}); |
| static_assert(ConvertOrderTo(std::endian::native, uint16_t{0x0011}) == uint16_t{0x0011}); |
| static_assert(ConvertOrderTo(std::endian::native, uint32_t{0x33221100}) == uint32_t{0x33221100}); |
| static_assert(ConvertOrderTo(std::endian::native, uint64_t{0x0011223344556677}) == uint64_t{0x0011223344556677}); |
| |
| // Convert signed to native endianness |
| static_assert(ConvertOrderTo(std::endian::native, int8_t{0x12}) == int8_t{0x12}); |
| static_assert(ConvertOrderTo(std::endian::native, int16_t{0x0011}) == int16_t{0x0011}); |
| static_assert(ConvertOrderTo(std::endian::native, int32_t{0x33221100}) == int32_t{0x33221100}); |
| static_assert(ConvertOrderTo(std::endian::native, int64_t{0x0011223344556677}) == int64_t{0x0011223344556677}); |
| |
| // Convert unsigned from native endianness |
| static_assert(ConvertOrderFrom(std::endian::native, uint8_t{0x12}) == uint8_t{0x12}); |
| static_assert(ConvertOrderFrom(std::endian::native, uint16_t{0x0011}) == uint16_t{0x0011}); |
| static_assert(ConvertOrderFrom(std::endian::native, uint32_t{0x33221100}) == uint32_t{0x33221100}); |
| static_assert(ConvertOrderFrom(std::endian::native, uint64_t{0x0011223344556677}) == uint64_t{0x0011223344556677}); |
| |
| // Convert signed from native endianness |
| static_assert(ConvertOrderFrom(std::endian::native, int8_t{0x12}) == int8_t{0x12}); |
| static_assert(ConvertOrderFrom(std::endian::native, int16_t{0x0011}) == int16_t{0x0011}); |
| static_assert(ConvertOrderFrom(std::endian::native, int32_t{0x33221100}) == int32_t{0x33221100}); |
| static_assert(ConvertOrderFrom(std::endian::native, int64_t{0x0011223344556677}) == int64_t{0x0011223344556677}); |
| |
| // Non-native endianess conversions (should reverse byte order) |
| |
| // Convert unsigned to non-native endianness |
| static_assert(ConvertOrderTo(kNonNative, uint8_t{0x12}) == uint8_t{0x12}); |
| static_assert(ConvertOrderTo(kNonNative, uint16_t{0x0011}) == uint16_t{0x1100}); |
| static_assert(ConvertOrderTo(kNonNative, uint32_t{0x33221100}) == uint32_t{0x00112233}); |
| static_assert(ConvertOrderTo(kNonNative, uint64_t{0x0011223344556677}) == uint64_t{0x7766554433221100}); |
| |
| // Convert signed to non-native endianness |
| static_assert(ConvertOrderTo(kNonNative, int8_t{0x12}) == int8_t{0x12}); |
| static_assert(ConvertOrderTo(kNonNative, int16_t{0x0011}) == int16_t{0x1100}); |
| static_assert(ConvertOrderTo(kNonNative, int32_t{0x33221100}) == int32_t{0x00112233}); |
| static_assert(ConvertOrderTo(kNonNative, int64_t{0x0011223344556677}) == int64_t{0x7766554433221100}); |
| |
| // Convert unsigned from non-native endianness |
| static_assert(ConvertOrderFrom(kNonNative, uint8_t{0x12}) == uint8_t{0x12}); |
| static_assert(ConvertOrderFrom(kNonNative, uint16_t{0x0011}) == uint16_t{0x1100}); |
| static_assert(ConvertOrderFrom(kNonNative, uint32_t{0x33221100}) == uint32_t{0x00112233}); |
| static_assert(ConvertOrderFrom(kNonNative, uint64_t{0x0011223344556677}) == uint64_t{0x7766554433221100}); |
| |
| // Convert signed from non-native endianness |
| static_assert(ConvertOrderFrom(kNonNative, int8_t{0x12}) == int8_t{0x12}); |
| static_assert(ConvertOrderFrom(kNonNative, int16_t{0x0011}) == int16_t{0x1100}); |
| static_assert(ConvertOrderFrom(kNonNative, int32_t{0x33221100}) == int32_t{0x00112233}); |
| static_assert(ConvertOrderFrom(kNonNative, int64_t{0x0011223344556677}) == int64_t{0x7766554433221100}); |
| |
| // clang-format on |
| |
| template <typename T, typename U> |
| constexpr bool Equal(const T& lhs, const U& rhs) { |
| if (sizeof(lhs) != sizeof(rhs) || std::size(lhs) != std::size(rhs)) { |
| return false; |
| } |
| |
| for (size_t i = 0; i < std::size(lhs); ++i) { |
| if (lhs[i] != rhs[i]) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| // CopyInOrder copies a value to a std::array with the specified endianness. |
| // |
| // clang-format off |
| |
| // 8-bit little |
| static_assert(Equal(CopyInOrder(std::endian::little, '?'), |
| Array<'?'>())); |
| static_assert(Equal(CopyInOrder(std::endian::little, uint8_t{0x10}), |
| Array<0x10>())); |
| static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int8_t>(0x10)), |
| Array<0x10>())); |
| |
| // 8-bit big |
| static_assert(Equal(CopyInOrder(std::endian::big, '?'), |
| Array<'?'>())); |
| static_assert(Equal(CopyInOrder(std::endian::big, static_cast<uint8_t>(0x10)), |
| Array<0x10>())); |
| static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int8_t>(0x10)), |
| Array<0x10>())); |
| |
| // 16-bit little |
| static_assert(Equal(CopyInOrder(std::endian::little, uint16_t{0xAB12}), |
| Array<0x12, 0xAB>())); |
| static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int16_t>(0xAB12)), |
| Array<0x12, 0xAB>())); |
| |
| // 16-bit big |
| static_assert(Equal(CopyInOrder(std::endian::big, uint16_t{0xAB12}), |
| Array<0xAB, 0x12>())); |
| static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int16_t>(0xAB12)), |
| Array<0xAB, 0x12>())); |
| |
| // 32-bit little |
| static_assert(Equal(CopyInOrder(std::endian::little, uint32_t{0xAABBCCDD}), |
| Array<0xDD, 0xCC, 0xBB, 0xAA>())); |
| static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int32_t>(0xAABBCCDD)), |
| Array<0xDD, 0xCC, 0xBB, 0xAA>())); |
| |
| // 32-bit big |
| static_assert(Equal(CopyInOrder(std::endian::big, uint32_t{0xAABBCCDD}), |
| Array<0xAA, 0xBB, 0xCC, 0xDD>())); |
| static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int32_t>(0xAABBCCDD)), |
| Array<0xAA, 0xBB, 0xCC, 0xDD>())); |
| |
| // 64-bit little |
| static_assert(Equal(CopyInOrder(std::endian::little, uint64_t{0xAABBCCDD11223344}), |
| Array<0x44, 0x33, 0x22, 0x11, 0xDD, 0xCC, 0xBB, 0xAA>())); |
| static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int64_t>(0xAABBCCDD11223344ull)), |
| Array<0x44, 0x33, 0x22, 0x11, 0xDD, 0xCC, 0xBB, 0xAA>())); |
| |
| // 64-bit big |
| static_assert(Equal(CopyInOrder(std::endian::big, uint64_t{0xAABBCCDD11223344}), |
| Array<0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22, 0x33, 0x44>())); |
| static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int64_t>(0xAABBCCDD11223344ull)), |
| Array<0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22, 0x33, 0x44>())); |
| |
| // clang-format on |
| |
| } // namespace |
| } // namespace pw::bytes |