mirror of
https://fuchsia.googlesource.com/third_party/pigweed.googlesource.com/pigweed/pigweed
synced 2024-09-21 06:12:09 +00:00
05ca54ccbc
- Create pw_bytes/endian.h, which provides functions for converting integer byte order. - Update pw_bytes docs. Change-Id: Icacc91d8c5d4f185c562f3b20b7249572ad84f5d Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/17464 Commit-Queue: Wyatt Hepler <hepler@google.com> Reviewed-by: Keir Mierle <keir@google.com>
165 lines
7.3 KiB
C++
165 lines
7.3 KiB
C++
// 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
|