1 // Copyright 2020 The Pigweed Authors
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
15 #include "pw_bytes/endian.h"
20 #include "gtest/gtest.h"
25 constexpr std::endian kNonNative = (std::endian::native == std::endian::little)
27 : std::endian::little;
29 // ConvertOrderTo/From
31 // ConvertOrderTo and ConvertOrderFrom are implemented identically, but are
32 // provided as separate functions to improve readability where they are used.
36 // Native endianess conversions (should do nothing)
38 // Convert unsigned to native endianness
39 static_assert(ConvertOrderTo(std::endian::native, uint8_t{0x12}) == uint8_t{0x12});
40 static_assert(ConvertOrderTo(std::endian::native, uint16_t{0x0011}) == uint16_t{0x0011});
41 static_assert(ConvertOrderTo(std::endian::native, uint32_t{0x33221100}) == uint32_t{0x33221100});
42 static_assert(ConvertOrderTo(std::endian::native, uint64_t{0x0011223344556677}) == uint64_t{0x0011223344556677});
44 // Convert signed to native endianness
45 static_assert(ConvertOrderTo(std::endian::native, int8_t{0x12}) == int8_t{0x12});
46 static_assert(ConvertOrderTo(std::endian::native, int16_t{0x0011}) == int16_t{0x0011});
47 static_assert(ConvertOrderTo(std::endian::native, int32_t{0x33221100}) == int32_t{0x33221100});
48 static_assert(ConvertOrderTo(std::endian::native, int64_t{0x0011223344556677}) == int64_t{0x0011223344556677});
50 // Convert unsigned from native endianness
51 static_assert(ConvertOrderFrom(std::endian::native, uint8_t{0x12}) == uint8_t{0x12});
52 static_assert(ConvertOrderFrom(std::endian::native, uint16_t{0x0011}) == uint16_t{0x0011});
53 static_assert(ConvertOrderFrom(std::endian::native, uint32_t{0x33221100}) == uint32_t{0x33221100});
54 static_assert(ConvertOrderFrom(std::endian::native, uint64_t{0x0011223344556677}) == uint64_t{0x0011223344556677});
56 // Convert signed from native endianness
57 static_assert(ConvertOrderFrom(std::endian::native, int8_t{0x12}) == int8_t{0x12});
58 static_assert(ConvertOrderFrom(std::endian::native, int16_t{0x0011}) == int16_t{0x0011});
59 static_assert(ConvertOrderFrom(std::endian::native, int32_t{0x33221100}) == int32_t{0x33221100});
60 static_assert(ConvertOrderFrom(std::endian::native, int64_t{0x0011223344556677}) == int64_t{0x0011223344556677});
62 // Non-native endianess conversions (should reverse byte order)
64 // Convert unsigned to non-native endianness
65 static_assert(ConvertOrderTo(kNonNative, uint8_t{0x12}) == uint8_t{0x12});
66 static_assert(ConvertOrderTo(kNonNative, uint16_t{0x0011}) == uint16_t{0x1100});
67 static_assert(ConvertOrderTo(kNonNative, uint32_t{0x33221100}) == uint32_t{0x00112233});
68 static_assert(ConvertOrderTo(kNonNative, uint64_t{0x0011223344556677}) == uint64_t{0x7766554433221100});
70 // Convert signed to non-native endianness
71 static_assert(ConvertOrderTo(kNonNative, int8_t{0x12}) == int8_t{0x12});
72 static_assert(ConvertOrderTo(kNonNative, int16_t{0x0011}) == int16_t{0x1100});
73 static_assert(ConvertOrderTo(kNonNative, int32_t{0x33221100}) == int32_t{0x00112233});
74 static_assert(ConvertOrderTo(kNonNative, int64_t{0x0011223344556677}) == int64_t{0x7766554433221100});
76 // Convert unsigned from non-native endianness
77 static_assert(ConvertOrderFrom(kNonNative, uint8_t{0x12}) == uint8_t{0x12});
78 static_assert(ConvertOrderFrom(kNonNative, uint16_t{0x0011}) == uint16_t{0x1100});
79 static_assert(ConvertOrderFrom(kNonNative, uint32_t{0x33221100}) == uint32_t{0x00112233});
80 static_assert(ConvertOrderFrom(kNonNative, uint64_t{0x0011223344556677}) == uint64_t{0x7766554433221100});
82 // Convert signed from non-native endianness
83 static_assert(ConvertOrderFrom(kNonNative, int8_t{0x12}) == int8_t{0x12});
84 static_assert(ConvertOrderFrom(kNonNative, int16_t{0x0011}) == int16_t{0x1100});
85 static_assert(ConvertOrderFrom(kNonNative, int32_t{0x33221100}) == int32_t{0x00112233});
86 static_assert(ConvertOrderFrom(kNonNative, int64_t{0x0011223344556677}) == int64_t{0x7766554433221100});
90 template <typename T, typename U>
91 constexpr bool Equal(const T& lhs, const U& rhs) {
92 if (sizeof(lhs) != sizeof(rhs) || std::size(lhs) != std::size(rhs)) {
96 for (size_t i = 0; i < std::size(lhs); ++i) {
97 if (lhs[i] != rhs[i]) {
105 // CopyInOrder copies a value to a std::array with the specified endianness.
110 static_assert(Equal(CopyInOrder(std::endian::little, '?'),
112 static_assert(Equal(CopyInOrder(std::endian::little, uint8_t{0x10}),
114 static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int8_t>(0x10)),
118 static_assert(Equal(CopyInOrder(std::endian::big, '?'),
120 static_assert(Equal(CopyInOrder(std::endian::big, static_cast<uint8_t>(0x10)),
122 static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int8_t>(0x10)),
126 static_assert(Equal(CopyInOrder(std::endian::little, uint16_t{0xAB12}),
127 Array<0x12, 0xAB>()));
128 static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int16_t>(0xAB12)),
129 Array<0x12, 0xAB>()));
132 static_assert(Equal(CopyInOrder(std::endian::big, uint16_t{0xAB12}),
133 Array<0xAB, 0x12>()));
134 static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int16_t>(0xAB12)),
135 Array<0xAB, 0x12>()));
138 static_assert(Equal(CopyInOrder(std::endian::little, uint32_t{0xAABBCCDD}),
139 Array<0xDD, 0xCC, 0xBB, 0xAA>()));
140 static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int32_t>(0xAABBCCDD)),
141 Array<0xDD, 0xCC, 0xBB, 0xAA>()));
144 static_assert(Equal(CopyInOrder(std::endian::big, uint32_t{0xAABBCCDD}),
145 Array<0xAA, 0xBB, 0xCC, 0xDD>()));
146 static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int32_t>(0xAABBCCDD)),
147 Array<0xAA, 0xBB, 0xCC, 0xDD>()));
150 static_assert(Equal(CopyInOrder(std::endian::little, uint64_t{0xAABBCCDD11223344}),
151 Array<0x44, 0x33, 0x22, 0x11, 0xDD, 0xCC, 0xBB, 0xAA>()));
152 static_assert(Equal(CopyInOrder(std::endian::little, static_cast<int64_t>(0xAABBCCDD11223344ull)),
153 Array<0x44, 0x33, 0x22, 0x11, 0xDD, 0xCC, 0xBB, 0xAA>()));
156 static_assert(Equal(CopyInOrder(std::endian::big, uint64_t{0xAABBCCDD11223344}),
157 Array<0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22, 0x33, 0x44>()));
158 static_assert(Equal(CopyInOrder(std::endian::big, static_cast<int64_t>(0xAABBCCDD11223344ull)),
159 Array<0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22, 0x33, 0x44>()));
163 constexpr const char* kNumber = "\x11\x22\x33\x44\xaa\xbb\xcc\xdd";
165 TEST(ReadInOrder, 8Bit_Big) {
166 EXPECT_EQ(ReadInOrder<uint8_t>(std::endian::big, "\0"), 0u);
167 EXPECT_EQ(ReadInOrder<uint8_t>(std::endian::big, "\x80"), 0x80u);
168 EXPECT_EQ(ReadInOrder<uint8_t>(std::endian::big, kNumber), 0x11u);
170 EXPECT_EQ(ReadInOrder<int8_t>(std::endian::big, "\0"), 0);
171 EXPECT_EQ(ReadInOrder<int8_t>(std::endian::big, "\x80"), -128);
172 EXPECT_EQ(ReadInOrder<int8_t>(std::endian::big, kNumber), 0x11);
175 TEST(ReadInOrder, 8Bit_Little) {
176 EXPECT_EQ(ReadInOrder<uint8_t>(std::endian::little, "\0"), 0u);
177 EXPECT_EQ(ReadInOrder<uint8_t>(std::endian::little, "\x80"), 0x80u);
178 EXPECT_EQ(ReadInOrder<uint8_t>(std::endian::little, kNumber), 0x11u);
180 EXPECT_EQ(ReadInOrder<int8_t>(std::endian::little, "\0"), 0);
181 EXPECT_EQ(ReadInOrder<int8_t>(std::endian::little, "\x80"), -128);
182 EXPECT_EQ(ReadInOrder<int8_t>(std::endian::little, kNumber), 0x11);
185 TEST(ReadInOrder, 16Bit_Big) {
186 EXPECT_EQ(ReadInOrder<uint16_t>(std::endian::big, "\0\0"), 0u);
187 EXPECT_EQ(ReadInOrder<uint16_t>(std::endian::big, "\x80\0"), 0x8000u);
188 EXPECT_EQ(ReadInOrder<uint16_t>(std::endian::big, kNumber), 0x1122u);
190 EXPECT_EQ(ReadInOrder<int16_t>(std::endian::big, "\0\0"), 0);
191 EXPECT_EQ(ReadInOrder<int16_t>(std::endian::big, "\x80\0"), -32768);
192 EXPECT_EQ(ReadInOrder<int16_t>(std::endian::big, kNumber), 0x1122);
195 TEST(ReadInOrder, 16Bit_Little) {
196 EXPECT_EQ(ReadInOrder<uint16_t>(std::endian::little, "\0\0"), 0u);
197 EXPECT_EQ(ReadInOrder<uint16_t>(std::endian::little, "\x80\0"), 0x80u);
198 EXPECT_EQ(ReadInOrder<uint16_t>(std::endian::little, kNumber), 0x2211u);
200 EXPECT_EQ(ReadInOrder<int16_t>(std::endian::little, "\0\0"), 0);
201 EXPECT_EQ(ReadInOrder<int16_t>(std::endian::little, "\x80\0"), 0x80);
202 EXPECT_EQ(ReadInOrder<int16_t>(std::endian::little, kNumber), 0x2211);
205 TEST(ReadInOrder, 32Bit_Big) {
206 EXPECT_EQ(ReadInOrder<uint32_t>(std::endian::big, "\0\0\0\0"), 0u);
207 EXPECT_EQ(ReadInOrder<uint32_t>(std::endian::big, "\x80\0\0\0"), 0x80000000u);
208 EXPECT_EQ(ReadInOrder<uint32_t>(std::endian::big, kNumber), 0x11223344u);
210 EXPECT_EQ(ReadInOrder<int32_t>(std::endian::big, "\0\0\0\0"), 0);
211 EXPECT_EQ(ReadInOrder<int32_t>(std::endian::big, "\x80\0\0\0"), -2147483648);
212 EXPECT_EQ(ReadInOrder<int32_t>(std::endian::big, kNumber), 0x11223344);
215 TEST(ReadInOrder, 32Bit_Little) {
216 EXPECT_EQ(ReadInOrder<uint32_t>(std::endian::little, "\0\0\0\0"), 0u);
217 EXPECT_EQ(ReadInOrder<uint32_t>(std::endian::little, "\x80\0\0\0"), 0x80u);
218 EXPECT_EQ(ReadInOrder<uint32_t>(std::endian::little, kNumber), 0x44332211u);
220 EXPECT_EQ(ReadInOrder<int32_t>(std::endian::little, "\0\0\0\0"), 0);
221 EXPECT_EQ(ReadInOrder<int32_t>(std::endian::little, "\x80\0\0\0"), 0x80);
222 EXPECT_EQ(ReadInOrder<int32_t>(std::endian::little, kNumber), 0x44332211);
225 TEST(ReadInOrder, 64Bit_Big) {
226 EXPECT_EQ(ReadInOrder<uint64_t>(std::endian::big, "\0\0\0\0\0\0\0\0"), 0u);
227 EXPECT_EQ(ReadInOrder<uint64_t>(std::endian::big, "\x80\0\0\0\0\0\0\0"),
228 0x80000000'00000000llu);
229 EXPECT_EQ(ReadInOrder<uint64_t>(std::endian::big, kNumber),
230 0x11223344AABBCCDDu);
232 EXPECT_EQ(ReadInOrder<int64_t>(std::endian::big, "\0\0\0\0\0\0\0\0"), 0);
233 EXPECT_EQ(ReadInOrder<int64_t>(std::endian::big, "\x80\0\0\0\0\0\0\0"),
234 static_cast<int64_t>(1llu << 63));
235 EXPECT_EQ(ReadInOrder<int64_t>(std::endian::big, kNumber),
239 TEST(ReadInOrder, 64Bit_Little) {
240 EXPECT_EQ(ReadInOrder<uint64_t>(std::endian::little, "\0\0\0\0\0\0\0\0"), 0u);
241 EXPECT_EQ(ReadInOrder<uint64_t>(std::endian::little, "\x80\0\0\0\0\0\0\0"),
243 EXPECT_EQ(ReadInOrder<uint64_t>(std::endian::little, kNumber),
244 0xDDCCBBAA44332211u);
246 EXPECT_EQ(ReadInOrder<int64_t>(std::endian::little, "\0\0\0\0\0\0\0\0"), 0);
247 EXPECT_EQ(ReadInOrder<int64_t>(std::endian::little, "\x80\0\0\0\0\0\0\0"),
249 EXPECT_EQ(ReadInOrder<int64_t>(std::endian::little, kNumber),
250 static_cast<int64_t>(0xDDCCBBAA44332211));
253 TEST(ReadInOrder, StdArray) {
254 std::array<std::byte, 4> buffer = Array<1, 2, 3, 4>();
255 EXPECT_EQ(0x04030201, ReadInOrder<int32_t>(std::endian::little, buffer));
256 EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(std::endian::big, buffer));
259 TEST(ReadInOrder, CArray) {
260 char buffer[5] = {1, 2, 3, 4, 99};
261 EXPECT_EQ(0x04030201, ReadInOrder<int32_t>(std::endian::little, buffer));
262 EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(std::endian::big, buffer));
265 TEST(ReadInOrder, BoundsChecking_Ok) {
266 constexpr auto buffer = Array<1, 2, 3, 4>();
268 EXPECT_TRUE(ReadInOrder(std::endian::little, buffer, value));
269 EXPECT_EQ(0x0201, value);
272 TEST(ReadInOrder, BoundsChecking_TooSmall) {
273 constexpr auto buffer = Array<1, 2, 3>();
275 EXPECT_FALSE(ReadInOrder(std::endian::little, buffer, value));
280 } // namespace pw::bytes