• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Pigweed Authors
2 //
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
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
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
13 // the License.
14 
15 #include "pw_bytes/endian.h"
16 
17 #include <array>
18 #include <cstddef>
19 
20 #include "gtest/gtest.h"
21 
22 namespace pw::bytes {
23 namespace {
24 
25 constexpr endian kNonNative =
26     (endian::native == endian::little) ? endian::big : endian::little;
27 
28 // ConvertOrderTo/From
29 //
30 // ConvertOrderTo and ConvertOrderFrom are implemented identically, but are
31 // provided as separate functions to improve readability where they are used.
32 //
33 // clang-format off
34 
35 // Native endianess conversions (should do nothing)
36 
37 // Convert unsigned to native endianness
38 static_assert(ConvertOrderTo(endian::native, uint8_t{0x12}) == uint8_t{0x12});
39 static_assert(ConvertOrderTo(endian::native, uint16_t{0x0011}) == uint16_t{0x0011});
40 static_assert(ConvertOrderTo(endian::native, uint32_t{0x33221100}) == uint32_t{0x33221100});
41 static_assert(ConvertOrderTo(endian::native, uint64_t{0x0011223344556677}) == uint64_t{0x0011223344556677});
42 
43 // Convert signed to native endianness
44 static_assert(ConvertOrderTo(endian::native, int8_t{0x12}) == int8_t{0x12});
45 static_assert(ConvertOrderTo(endian::native, int16_t{0x0011}) == int16_t{0x0011});
46 static_assert(ConvertOrderTo(endian::native, int32_t{0x33221100}) == int32_t{0x33221100});
47 static_assert(ConvertOrderTo(endian::native, int64_t{0x0011223344556677}) == int64_t{0x0011223344556677});
48 
49 // Convert unsigned from native endianness
50 static_assert(ConvertOrderFrom(endian::native, uint8_t{0x12}) == uint8_t{0x12});
51 static_assert(ConvertOrderFrom(endian::native, uint16_t{0x0011}) == uint16_t{0x0011});
52 static_assert(ConvertOrderFrom(endian::native, uint32_t{0x33221100}) == uint32_t{0x33221100});
53 static_assert(ConvertOrderFrom(endian::native, uint64_t{0x0011223344556677}) == uint64_t{0x0011223344556677});
54 
55 // Convert signed from native endianness
56 static_assert(ConvertOrderFrom(endian::native, int8_t{0x12}) == int8_t{0x12});
57 static_assert(ConvertOrderFrom(endian::native, int16_t{0x0011}) == int16_t{0x0011});
58 static_assert(ConvertOrderFrom(endian::native, int32_t{0x33221100}) == int32_t{0x33221100});
59 static_assert(ConvertOrderFrom(endian::native, int64_t{0x0011223344556677}) == int64_t{0x0011223344556677});
60 
61 // Non-native endianess conversions (should reverse byte order)
62 
63 // Convert unsigned to non-native endianness
64 static_assert(ConvertOrderTo(kNonNative, uint8_t{0x12}) == uint8_t{0x12});
65 static_assert(ConvertOrderTo(kNonNative, uint16_t{0x0011}) == uint16_t{0x1100});
66 static_assert(ConvertOrderTo(kNonNative, uint32_t{0x33221100}) == uint32_t{0x00112233});
67 static_assert(ConvertOrderTo(kNonNative, uint64_t{0x0011223344556677}) == uint64_t{0x7766554433221100});
68 
69 // Convert signed to non-native endianness
70 static_assert(ConvertOrderTo(kNonNative, int8_t{0x12}) == int8_t{0x12});
71 static_assert(ConvertOrderTo(kNonNative, int16_t{0x0011}) == int16_t{0x1100});
72 static_assert(ConvertOrderTo(kNonNative, int32_t{0x33221100}) == int32_t{0x00112233});
73 static_assert(ConvertOrderTo(kNonNative, int64_t{0x0011223344556677}) == int64_t{0x7766554433221100});
74 
75 // Convert unsigned from non-native endianness
76 static_assert(ConvertOrderFrom(kNonNative, uint8_t{0x12}) == uint8_t{0x12});
77 static_assert(ConvertOrderFrom(kNonNative, uint16_t{0x0011}) == uint16_t{0x1100});
78 static_assert(ConvertOrderFrom(kNonNative, uint32_t{0x33221100}) == uint32_t{0x00112233});
79 static_assert(ConvertOrderFrom(kNonNative, uint64_t{0x0011223344556677}) == uint64_t{0x7766554433221100});
80 
81 // Convert signed from non-native endianness
82 static_assert(ConvertOrderFrom(kNonNative, int8_t{0x12}) == int8_t{0x12});
83 static_assert(ConvertOrderFrom(kNonNative, int16_t{0x0011}) == int16_t{0x1100});
84 static_assert(ConvertOrderFrom(kNonNative, int32_t{0x33221100}) == int32_t{0x00112233});
85 static_assert(ConvertOrderFrom(kNonNative, int64_t{0x0011223344556677}) == int64_t{0x7766554433221100});
86 
87 // clang-format on
88 
89 template <typename T, typename U>
Equal(const T & lhs,const U & rhs)90 constexpr bool Equal(const T& lhs, const U& rhs) {
91   if (sizeof(lhs) != sizeof(rhs) || std::size(lhs) != std::size(rhs)) {
92     return false;
93   }
94 
95   for (size_t i = 0; i < std::size(lhs); ++i) {
96     if (lhs[i] != rhs[i]) {
97       return false;
98     }
99   }
100 
101   return true;
102 }
103 
104 // CopyInOrder copies a value to a std::array with the specified endianness.
105 //
106 // clang-format off
107 
108 // 8-bit little
109 static_assert(Equal(CopyInOrder(endian::little, '?'),
110                     Array<'?'>()));
111 static_assert(Equal(CopyInOrder(endian::little, uint8_t{0x10}),
112                     Array<0x10>()));
113 static_assert(Equal(CopyInOrder(endian::little, static_cast<int8_t>(0x10)),
114                     Array<0x10>()));
115 
116 // 8-bit big
117 static_assert(Equal(CopyInOrder(endian::big, '?'),
118                     Array<'?'>()));
119 static_assert(Equal(CopyInOrder(endian::big, static_cast<uint8_t>(0x10)),
120                     Array<0x10>()));
121 static_assert(Equal(CopyInOrder(endian::big, static_cast<int8_t>(0x10)),
122                     Array<0x10>()));
123 
124 // 16-bit little
125 static_assert(Equal(CopyInOrder(endian::little, uint16_t{0xAB12}),
126                     Array<0x12, 0xAB>()));
127 static_assert(Equal(CopyInOrder(endian::little, static_cast<int16_t>(0xAB12)),
128                     Array<0x12, 0xAB>()));
129 
130 // 16-bit big
131 static_assert(Equal(CopyInOrder(endian::big, uint16_t{0xAB12}),
132                     Array<0xAB, 0x12>()));
133 static_assert(Equal(CopyInOrder(endian::big, static_cast<int16_t>(0xAB12)),
134                     Array<0xAB, 0x12>()));
135 
136 // 32-bit little
137 static_assert(Equal(CopyInOrder(endian::little, uint32_t{0xAABBCCDD}),
138                     Array<0xDD, 0xCC, 0xBB, 0xAA>()));
139 static_assert(Equal(CopyInOrder(endian::little, static_cast<int32_t>(0xAABBCCDD)),
140                     Array<0xDD, 0xCC, 0xBB, 0xAA>()));
141 
142 // 32-bit big
143 static_assert(Equal(CopyInOrder(endian::big, uint32_t{0xAABBCCDD}),
144                     Array<0xAA, 0xBB, 0xCC, 0xDD>()));
145 static_assert(Equal(CopyInOrder(endian::big, static_cast<int32_t>(0xAABBCCDD)),
146                     Array<0xAA, 0xBB, 0xCC, 0xDD>()));
147 
148 // 64-bit little
149 static_assert(Equal(CopyInOrder(endian::little, uint64_t{0xAABBCCDD11223344}),
150                     Array<0x44, 0x33, 0x22, 0x11, 0xDD, 0xCC, 0xBB, 0xAA>()));
151 static_assert(Equal(CopyInOrder(endian::little, static_cast<int64_t>(0xAABBCCDD11223344ull)),
152                     Array<0x44, 0x33, 0x22, 0x11, 0xDD, 0xCC, 0xBB, 0xAA>()));
153 
154 // 64-bit big
155 static_assert(Equal(CopyInOrder(endian::big, uint64_t{0xAABBCCDD11223344}),
156                     Array<0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22, 0x33, 0x44>()));
157 static_assert(Equal(CopyInOrder(endian::big, static_cast<int64_t>(0xAABBCCDD11223344ull)),
158                     Array<0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22, 0x33, 0x44>()));
159 
160 // clang-format on
161 
162 constexpr const char* kNumber = "\x11\x22\x33\x44\xaa\xbb\xcc\xdd";
163 
164 TEST(ReadInOrder, 8Bit_Big) {
165   EXPECT_EQ(ReadInOrder<uint8_t>(endian::big, "\0"), 0u);
166   EXPECT_EQ(ReadInOrder<uint8_t>(endian::big, "\x80"), 0x80u);
167   EXPECT_EQ(ReadInOrder<uint8_t>(endian::big, kNumber), 0x11u);
168 
169   EXPECT_EQ(ReadInOrder<int8_t>(endian::big, "\0"), 0);
170   EXPECT_EQ(ReadInOrder<int8_t>(endian::big, "\x80"), -128);
171   EXPECT_EQ(ReadInOrder<int8_t>(endian::big, kNumber), 0x11);
172 }
173 
174 TEST(ReadInOrder, 8Bit_Little) {
175   EXPECT_EQ(ReadInOrder<uint8_t>(endian::little, "\0"), 0u);
176   EXPECT_EQ(ReadInOrder<uint8_t>(endian::little, "\x80"), 0x80u);
177   EXPECT_EQ(ReadInOrder<uint8_t>(endian::little, kNumber), 0x11u);
178 
179   EXPECT_EQ(ReadInOrder<int8_t>(endian::little, "\0"), 0);
180   EXPECT_EQ(ReadInOrder<int8_t>(endian::little, "\x80"), -128);
181   EXPECT_EQ(ReadInOrder<int8_t>(endian::little, kNumber), 0x11);
182 }
183 
184 TEST(ReadInOrder, 16Bit_Big) {
185   EXPECT_EQ(ReadInOrder<uint16_t>(endian::big, "\0\0"), 0u);
186   EXPECT_EQ(ReadInOrder<uint16_t>(endian::big, "\x80\0"), 0x8000u);
187   EXPECT_EQ(ReadInOrder<uint16_t>(endian::big, kNumber), 0x1122u);
188 
189   EXPECT_EQ(ReadInOrder<int16_t>(endian::big, "\0\0"), 0);
190   EXPECT_EQ(ReadInOrder<int16_t>(endian::big, "\x80\0"), -32768);
191   EXPECT_EQ(ReadInOrder<int16_t>(endian::big, kNumber), 0x1122);
192 }
193 
194 TEST(ReadInOrder, 16Bit_Little) {
195   EXPECT_EQ(ReadInOrder<uint16_t>(endian::little, "\0\0"), 0u);
196   EXPECT_EQ(ReadInOrder<uint16_t>(endian::little, "\x80\0"), 0x80u);
197   EXPECT_EQ(ReadInOrder<uint16_t>(endian::little, kNumber), 0x2211u);
198 
199   EXPECT_EQ(ReadInOrder<int16_t>(endian::little, "\0\0"), 0);
200   EXPECT_EQ(ReadInOrder<int16_t>(endian::little, "\x80\0"), 0x80);
201   EXPECT_EQ(ReadInOrder<int16_t>(endian::little, kNumber), 0x2211);
202 }
203 
204 TEST(ReadInOrder, 32Bit_Big) {
205   EXPECT_EQ(ReadInOrder<uint32_t>(endian::big, "\0\0\0\0"), 0u);
206   EXPECT_EQ(ReadInOrder<uint32_t>(endian::big, "\x80\0\0\0"), 0x80000000u);
207   EXPECT_EQ(ReadInOrder<uint32_t>(endian::big, kNumber), 0x11223344u);
208 
209   EXPECT_EQ(ReadInOrder<int32_t>(endian::big, "\0\0\0\0"), 0);
210   EXPECT_EQ(ReadInOrder<int32_t>(endian::big, "\x80\0\0\0"), -2147483648);
211   EXPECT_EQ(ReadInOrder<int32_t>(endian::big, kNumber), 0x11223344);
212 }
213 
214 TEST(ReadInOrder, 32Bit_Little) {
215   EXPECT_EQ(ReadInOrder<uint32_t>(endian::little, "\0\0\0\0"), 0u);
216   EXPECT_EQ(ReadInOrder<uint32_t>(endian::little, "\x80\0\0\0"), 0x80u);
217   EXPECT_EQ(ReadInOrder<uint32_t>(endian::little, kNumber), 0x44332211u);
218 
219   EXPECT_EQ(ReadInOrder<int32_t>(endian::little, "\0\0\0\0"), 0);
220   EXPECT_EQ(ReadInOrder<int32_t>(endian::little, "\x80\0\0\0"), 0x80);
221   EXPECT_EQ(ReadInOrder<int32_t>(endian::little, kNumber), 0x44332211);
222 }
223 
224 TEST(ReadInOrder, 64Bit_Big) {
225   EXPECT_EQ(ReadInOrder<uint64_t>(endian::big, "\0\0\0\0\0\0\0\0"), 0u);
226   EXPECT_EQ(ReadInOrder<uint64_t>(endian::big, "\x80\0\0\0\0\0\0\0"),
227             0x80000000'00000000llu);
228   EXPECT_EQ(ReadInOrder<uint64_t>(endian::big, kNumber), 0x11223344AABBCCDDu);
229 
230   EXPECT_EQ(ReadInOrder<int64_t>(endian::big, "\0\0\0\0\0\0\0\0"), 0);
231   EXPECT_EQ(ReadInOrder<int64_t>(endian::big, "\x80\0\0\0\0\0\0\0"),
232             static_cast<int64_t>(1llu << 63));
233   EXPECT_EQ(ReadInOrder<int64_t>(endian::big, kNumber), 0x11223344AABBCCDD);
234 }
235 
236 TEST(ReadInOrder, 64Bit_Little) {
237   EXPECT_EQ(ReadInOrder<uint64_t>(endian::little, "\0\0\0\0\0\0\0\0"), 0u);
238   EXPECT_EQ(ReadInOrder<uint64_t>(endian::little, "\x80\0\0\0\0\0\0\0"), 0x80u);
239   EXPECT_EQ(ReadInOrder<uint64_t>(endian::little, kNumber),
240             0xDDCCBBAA44332211u);
241 
242   EXPECT_EQ(ReadInOrder<int64_t>(endian::little, "\0\0\0\0\0\0\0\0"), 0);
243   EXPECT_EQ(ReadInOrder<int64_t>(endian::little, "\x80\0\0\0\0\0\0\0"), 0x80);
244   EXPECT_EQ(ReadInOrder<int64_t>(endian::little, kNumber),
245             static_cast<int64_t>(0xDDCCBBAA44332211));
246 }
247 
TEST(ReadInOrder,StdArray)248 TEST(ReadInOrder, StdArray) {
249   std::array<std::byte, 4> buffer = Array<1, 2, 3, 4>();
250   EXPECT_EQ(0x04030201, ReadInOrder<int32_t>(endian::little, buffer));
251   EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(endian::big, buffer));
252 }
253 
TEST(ReadInOrder,CArray)254 TEST(ReadInOrder, CArray) {
255   char buffer[5] = {1, 2, 3, 4, 99};
256   EXPECT_EQ(0x04030201, ReadInOrder<int32_t>(endian::little, buffer));
257   EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(endian::big, buffer));
258 }
259 
TEST(ReadInOrder,BoundsChecking_Ok)260 TEST(ReadInOrder, BoundsChecking_Ok) {
261   constexpr auto buffer = Array<1, 2, 3, 4>();
262   uint16_t value = 0;
263   EXPECT_TRUE(ReadInOrder(endian::little, buffer, value));
264   EXPECT_EQ(0x0201, value);
265 }
266 
TEST(ReadInOrder,BoundsChecking_TooSmall)267 TEST(ReadInOrder, BoundsChecking_TooSmall) {
268   constexpr auto buffer = Array<1, 2, 3>();
269   int32_t value = 0;
270   EXPECT_FALSE(ReadInOrder(endian::little, buffer, value));
271   EXPECT_EQ(0, value);
272 }
273 
TEST(ReadInOrder,PartialLittleEndian)274 TEST(ReadInOrder, PartialLittleEndian) {
275   constexpr auto buffer = Array<1, 2, 3, 4>();
276 
277   EXPECT_EQ(0x00000000, ReadInOrder<int32_t>(endian::little, buffer.data(), 0));
278   EXPECT_EQ(0x00000001, ReadInOrder<int32_t>(endian::little, buffer.data(), 1));
279   EXPECT_EQ(0x00000201, ReadInOrder<int32_t>(endian::little, buffer.data(), 2));
280   EXPECT_EQ(0x00030201, ReadInOrder<int32_t>(endian::little, buffer.data(), 3));
281   EXPECT_EQ(0x04030201, ReadInOrder<int32_t>(endian::little, buffer.data(), 4));
282   EXPECT_EQ(0x04030201, ReadInOrder<int32_t>(endian::little, buffer.data(), 5));
283   EXPECT_EQ(0x04030201,
284             ReadInOrder<int32_t>(endian::little, buffer.data(), 100));
285 }
286 
TEST(ReadInOrder,PartialBigEndian)287 TEST(ReadInOrder, PartialBigEndian) {
288   constexpr auto buffer = Array<1, 2, 3, 4>();
289 
290   EXPECT_EQ(0x00000000, ReadInOrder<int32_t>(endian::big, buffer.data(), 0));
291   EXPECT_EQ(0x01000000, ReadInOrder<int32_t>(endian::big, buffer.data(), 1));
292   EXPECT_EQ(0x01020000, ReadInOrder<int32_t>(endian::big, buffer.data(), 2));
293   EXPECT_EQ(0x01020300, ReadInOrder<int32_t>(endian::big, buffer.data(), 3));
294   EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(endian::big, buffer.data(), 4));
295   EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(endian::big, buffer.data(), 5));
296   EXPECT_EQ(0x01020304, ReadInOrder<int32_t>(endian::big, buffer.data(), 100));
297 }
298 
299 }  // namespace
300 }  // namespace pw::bytes
301