1*9356374aSAndroid Build Coastguard Worker // Copyright 2017 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker
15*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/endian.h"
16*9356374aSAndroid Build Coastguard Worker
17*9356374aSAndroid Build Coastguard Worker #include <algorithm>
18*9356374aSAndroid Build Coastguard Worker #include <cstdint>
19*9356374aSAndroid Build Coastguard Worker #include <limits>
20*9356374aSAndroid Build Coastguard Worker #include <random>
21*9356374aSAndroid Build Coastguard Worker #include <vector>
22*9356374aSAndroid Build Coastguard Worker
23*9356374aSAndroid Build Coastguard Worker #include "gtest/gtest.h"
24*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h"
25*9356374aSAndroid Build Coastguard Worker
26*9356374aSAndroid Build Coastguard Worker namespace absl {
27*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
28*9356374aSAndroid Build Coastguard Worker namespace {
29*9356374aSAndroid Build Coastguard Worker
30*9356374aSAndroid Build Coastguard Worker const uint64_t kInitialNumber{0x0123456789abcdef};
31*9356374aSAndroid Build Coastguard Worker const uint64_t k64Value{kInitialNumber};
32*9356374aSAndroid Build Coastguard Worker const uint32_t k32Value{0x01234567};
33*9356374aSAndroid Build Coastguard Worker const uint16_t k16Value{0x0123};
34*9356374aSAndroid Build Coastguard Worker const int kNumValuesToTest = 1000000;
35*9356374aSAndroid Build Coastguard Worker const int kRandomSeed = 12345;
36*9356374aSAndroid Build Coastguard Worker
37*9356374aSAndroid Build Coastguard Worker #if defined(ABSL_IS_BIG_ENDIAN)
38*9356374aSAndroid Build Coastguard Worker const uint64_t kInitialInNetworkOrder{kInitialNumber};
39*9356374aSAndroid Build Coastguard Worker const uint64_t k64ValueLE{0xefcdab8967452301};
40*9356374aSAndroid Build Coastguard Worker const uint32_t k32ValueLE{0x67452301};
41*9356374aSAndroid Build Coastguard Worker const uint16_t k16ValueLE{0x2301};
42*9356374aSAndroid Build Coastguard Worker
43*9356374aSAndroid Build Coastguard Worker const uint64_t k64ValueBE{kInitialNumber};
44*9356374aSAndroid Build Coastguard Worker const uint32_t k32ValueBE{k32Value};
45*9356374aSAndroid Build Coastguard Worker const uint16_t k16ValueBE{k16Value};
46*9356374aSAndroid Build Coastguard Worker #elif defined(ABSL_IS_LITTLE_ENDIAN)
47*9356374aSAndroid Build Coastguard Worker const uint64_t kInitialInNetworkOrder{0xefcdab8967452301};
48*9356374aSAndroid Build Coastguard Worker const uint64_t k64ValueLE{kInitialNumber};
49*9356374aSAndroid Build Coastguard Worker const uint32_t k32ValueLE{k32Value};
50*9356374aSAndroid Build Coastguard Worker const uint16_t k16ValueLE{k16Value};
51*9356374aSAndroid Build Coastguard Worker
52*9356374aSAndroid Build Coastguard Worker const uint64_t k64ValueBE{0xefcdab8967452301};
53*9356374aSAndroid Build Coastguard Worker const uint32_t k32ValueBE{0x67452301};
54*9356374aSAndroid Build Coastguard Worker const uint16_t k16ValueBE{0x2301};
55*9356374aSAndroid Build Coastguard Worker #endif
56*9356374aSAndroid Build Coastguard Worker
GenerateAllUint16Values()57*9356374aSAndroid Build Coastguard Worker std::vector<uint16_t> GenerateAllUint16Values() {
58*9356374aSAndroid Build Coastguard Worker std::vector<uint16_t> result;
59*9356374aSAndroid Build Coastguard Worker result.reserve(size_t{1} << (sizeof(uint16_t) * 8));
60*9356374aSAndroid Build Coastguard Worker for (uint32_t i = std::numeric_limits<uint16_t>::min();
61*9356374aSAndroid Build Coastguard Worker i <= std::numeric_limits<uint16_t>::max(); ++i) {
62*9356374aSAndroid Build Coastguard Worker result.push_back(static_cast<uint16_t>(i));
63*9356374aSAndroid Build Coastguard Worker }
64*9356374aSAndroid Build Coastguard Worker return result;
65*9356374aSAndroid Build Coastguard Worker }
66*9356374aSAndroid Build Coastguard Worker
67*9356374aSAndroid Build Coastguard Worker template<typename T>
GenerateRandomIntegers(size_t num_values_to_test)68*9356374aSAndroid Build Coastguard Worker std::vector<T> GenerateRandomIntegers(size_t num_values_to_test) {
69*9356374aSAndroid Build Coastguard Worker std::vector<T> result;
70*9356374aSAndroid Build Coastguard Worker result.reserve(num_values_to_test);
71*9356374aSAndroid Build Coastguard Worker std::mt19937_64 rng(kRandomSeed);
72*9356374aSAndroid Build Coastguard Worker for (size_t i = 0; i < num_values_to_test; ++i) {
73*9356374aSAndroid Build Coastguard Worker result.push_back(rng());
74*9356374aSAndroid Build Coastguard Worker }
75*9356374aSAndroid Build Coastguard Worker return result;
76*9356374aSAndroid Build Coastguard Worker }
77*9356374aSAndroid Build Coastguard Worker
ManualByteSwap(char * bytes,int length)78*9356374aSAndroid Build Coastguard Worker void ManualByteSwap(char* bytes, int length) {
79*9356374aSAndroid Build Coastguard Worker if (length == 1)
80*9356374aSAndroid Build Coastguard Worker return;
81*9356374aSAndroid Build Coastguard Worker
82*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(0, length % 2);
83*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < length / 2; ++i) {
84*9356374aSAndroid Build Coastguard Worker int j = (length - 1) - i;
85*9356374aSAndroid Build Coastguard Worker using std::swap;
86*9356374aSAndroid Build Coastguard Worker swap(bytes[i], bytes[j]);
87*9356374aSAndroid Build Coastguard Worker }
88*9356374aSAndroid Build Coastguard Worker }
89*9356374aSAndroid Build Coastguard Worker
90*9356374aSAndroid Build Coastguard Worker template<typename T>
UnalignedLoad(const char * p)91*9356374aSAndroid Build Coastguard Worker inline T UnalignedLoad(const char* p) {
92*9356374aSAndroid Build Coastguard Worker static_assert(
93*9356374aSAndroid Build Coastguard Worker sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
94*9356374aSAndroid Build Coastguard Worker "Unexpected type size");
95*9356374aSAndroid Build Coastguard Worker
96*9356374aSAndroid Build Coastguard Worker switch (sizeof(T)) {
97*9356374aSAndroid Build Coastguard Worker case 1: return *reinterpret_cast<const T*>(p);
98*9356374aSAndroid Build Coastguard Worker case 2:
99*9356374aSAndroid Build Coastguard Worker return ABSL_INTERNAL_UNALIGNED_LOAD16(p);
100*9356374aSAndroid Build Coastguard Worker case 4:
101*9356374aSAndroid Build Coastguard Worker return ABSL_INTERNAL_UNALIGNED_LOAD32(p);
102*9356374aSAndroid Build Coastguard Worker case 8:
103*9356374aSAndroid Build Coastguard Worker return ABSL_INTERNAL_UNALIGNED_LOAD64(p);
104*9356374aSAndroid Build Coastguard Worker default:
105*9356374aSAndroid Build Coastguard Worker // Suppresses invalid "not all control paths return a value" on MSVC
106*9356374aSAndroid Build Coastguard Worker return {};
107*9356374aSAndroid Build Coastguard Worker }
108*9356374aSAndroid Build Coastguard Worker }
109*9356374aSAndroid Build Coastguard Worker
110*9356374aSAndroid Build Coastguard Worker template <typename T, typename ByteSwapper>
GBSwapHelper(const std::vector<T> & host_values_to_test,const ByteSwapper & byte_swapper)111*9356374aSAndroid Build Coastguard Worker static void GBSwapHelper(const std::vector<T>& host_values_to_test,
112*9356374aSAndroid Build Coastguard Worker const ByteSwapper& byte_swapper) {
113*9356374aSAndroid Build Coastguard Worker // Test byte_swapper against a manual byte swap.
114*9356374aSAndroid Build Coastguard Worker for (typename std::vector<T>::const_iterator it = host_values_to_test.begin();
115*9356374aSAndroid Build Coastguard Worker it != host_values_to_test.end(); ++it) {
116*9356374aSAndroid Build Coastguard Worker T host_value = *it;
117*9356374aSAndroid Build Coastguard Worker
118*9356374aSAndroid Build Coastguard Worker char actual_value[sizeof(host_value)];
119*9356374aSAndroid Build Coastguard Worker memcpy(actual_value, &host_value, sizeof(host_value));
120*9356374aSAndroid Build Coastguard Worker byte_swapper(actual_value);
121*9356374aSAndroid Build Coastguard Worker
122*9356374aSAndroid Build Coastguard Worker char expected_value[sizeof(host_value)];
123*9356374aSAndroid Build Coastguard Worker memcpy(expected_value, &host_value, sizeof(host_value));
124*9356374aSAndroid Build Coastguard Worker ManualByteSwap(expected_value, sizeof(host_value));
125*9356374aSAndroid Build Coastguard Worker
126*9356374aSAndroid Build Coastguard Worker ASSERT_EQ(0, memcmp(actual_value, expected_value, sizeof(host_value)))
127*9356374aSAndroid Build Coastguard Worker << "Swap output for 0x" << std::hex << host_value << " does not match. "
128*9356374aSAndroid Build Coastguard Worker << "Expected: 0x" << UnalignedLoad<T>(expected_value) << "; "
129*9356374aSAndroid Build Coastguard Worker << "actual: 0x" << UnalignedLoad<T>(actual_value);
130*9356374aSAndroid Build Coastguard Worker }
131*9356374aSAndroid Build Coastguard Worker }
132*9356374aSAndroid Build Coastguard Worker
Swap16(char * bytes)133*9356374aSAndroid Build Coastguard Worker void Swap16(char* bytes) {
134*9356374aSAndroid Build Coastguard Worker ABSL_INTERNAL_UNALIGNED_STORE16(
135*9356374aSAndroid Build Coastguard Worker bytes, gbswap_16(ABSL_INTERNAL_UNALIGNED_LOAD16(bytes)));
136*9356374aSAndroid Build Coastguard Worker }
137*9356374aSAndroid Build Coastguard Worker
Swap32(char * bytes)138*9356374aSAndroid Build Coastguard Worker void Swap32(char* bytes) {
139*9356374aSAndroid Build Coastguard Worker ABSL_INTERNAL_UNALIGNED_STORE32(
140*9356374aSAndroid Build Coastguard Worker bytes, gbswap_32(ABSL_INTERNAL_UNALIGNED_LOAD32(bytes)));
141*9356374aSAndroid Build Coastguard Worker }
142*9356374aSAndroid Build Coastguard Worker
Swap64(char * bytes)143*9356374aSAndroid Build Coastguard Worker void Swap64(char* bytes) {
144*9356374aSAndroid Build Coastguard Worker ABSL_INTERNAL_UNALIGNED_STORE64(
145*9356374aSAndroid Build Coastguard Worker bytes, gbswap_64(ABSL_INTERNAL_UNALIGNED_LOAD64(bytes)));
146*9356374aSAndroid Build Coastguard Worker }
147*9356374aSAndroid Build Coastguard Worker
TEST(EndianessTest,Uint16)148*9356374aSAndroid Build Coastguard Worker TEST(EndianessTest, Uint16) {
149*9356374aSAndroid Build Coastguard Worker GBSwapHelper(GenerateAllUint16Values(), &Swap16);
150*9356374aSAndroid Build Coastguard Worker }
151*9356374aSAndroid Build Coastguard Worker
TEST(EndianessTest,Uint32)152*9356374aSAndroid Build Coastguard Worker TEST(EndianessTest, Uint32) {
153*9356374aSAndroid Build Coastguard Worker GBSwapHelper(GenerateRandomIntegers<uint32_t>(kNumValuesToTest), &Swap32);
154*9356374aSAndroid Build Coastguard Worker }
155*9356374aSAndroid Build Coastguard Worker
TEST(EndianessTest,Uint64)156*9356374aSAndroid Build Coastguard Worker TEST(EndianessTest, Uint64) {
157*9356374aSAndroid Build Coastguard Worker GBSwapHelper(GenerateRandomIntegers<uint64_t>(kNumValuesToTest), &Swap64);
158*9356374aSAndroid Build Coastguard Worker }
159*9356374aSAndroid Build Coastguard Worker
TEST(EndianessTest,ghtonll_gntohll)160*9356374aSAndroid Build Coastguard Worker TEST(EndianessTest, ghtonll_gntohll) {
161*9356374aSAndroid Build Coastguard Worker // Test that absl::ghtonl compiles correctly
162*9356374aSAndroid Build Coastguard Worker uint32_t test = 0x01234567;
163*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(absl::gntohl(absl::ghtonl(test)), test);
164*9356374aSAndroid Build Coastguard Worker
165*9356374aSAndroid Build Coastguard Worker uint64_t comp = absl::ghtonll(kInitialNumber);
166*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, kInitialInNetworkOrder);
167*9356374aSAndroid Build Coastguard Worker comp = absl::gntohll(kInitialInNetworkOrder);
168*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, kInitialNumber);
169*9356374aSAndroid Build Coastguard Worker
170*9356374aSAndroid Build Coastguard Worker // Test that htonll and ntohll are each others' inverse functions on a
171*9356374aSAndroid Build Coastguard Worker // somewhat assorted batch of numbers. 37 is chosen to not be anything
172*9356374aSAndroid Build Coastguard Worker // particularly nice base 2.
173*9356374aSAndroid Build Coastguard Worker uint64_t value = 1;
174*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < 100; ++i) {
175*9356374aSAndroid Build Coastguard Worker comp = absl::ghtonll(absl::gntohll(value));
176*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(value, comp);
177*9356374aSAndroid Build Coastguard Worker comp = absl::gntohll(absl::ghtonll(value));
178*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(value, comp);
179*9356374aSAndroid Build Coastguard Worker value *= 37;
180*9356374aSAndroid Build Coastguard Worker }
181*9356374aSAndroid Build Coastguard Worker }
182*9356374aSAndroid Build Coastguard Worker
TEST(EndianessTest,little_endian)183*9356374aSAndroid Build Coastguard Worker TEST(EndianessTest, little_endian) {
184*9356374aSAndroid Build Coastguard Worker // Check little_endian uint16_t.
185*9356374aSAndroid Build Coastguard Worker uint64_t comp = little_endian::FromHost16(k16Value);
186*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k16ValueLE);
187*9356374aSAndroid Build Coastguard Worker comp = little_endian::ToHost16(k16ValueLE);
188*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k16Value);
189*9356374aSAndroid Build Coastguard Worker
190*9356374aSAndroid Build Coastguard Worker // Check little_endian uint32_t.
191*9356374aSAndroid Build Coastguard Worker comp = little_endian::FromHost32(k32Value);
192*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k32ValueLE);
193*9356374aSAndroid Build Coastguard Worker comp = little_endian::ToHost32(k32ValueLE);
194*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k32Value);
195*9356374aSAndroid Build Coastguard Worker
196*9356374aSAndroid Build Coastguard Worker // Check little_endian uint64_t.
197*9356374aSAndroid Build Coastguard Worker comp = little_endian::FromHost64(k64Value);
198*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k64ValueLE);
199*9356374aSAndroid Build Coastguard Worker comp = little_endian::ToHost64(k64ValueLE);
200*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k64Value);
201*9356374aSAndroid Build Coastguard Worker
202*9356374aSAndroid Build Coastguard Worker // Check little-endian Load and store functions.
203*9356374aSAndroid Build Coastguard Worker uint16_t u16Buf;
204*9356374aSAndroid Build Coastguard Worker uint32_t u32Buf;
205*9356374aSAndroid Build Coastguard Worker uint64_t u64Buf;
206*9356374aSAndroid Build Coastguard Worker
207*9356374aSAndroid Build Coastguard Worker little_endian::Store16(&u16Buf, k16Value);
208*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(u16Buf, k16ValueLE);
209*9356374aSAndroid Build Coastguard Worker comp = little_endian::Load16(&u16Buf);
210*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k16Value);
211*9356374aSAndroid Build Coastguard Worker
212*9356374aSAndroid Build Coastguard Worker little_endian::Store32(&u32Buf, k32Value);
213*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(u32Buf, k32ValueLE);
214*9356374aSAndroid Build Coastguard Worker comp = little_endian::Load32(&u32Buf);
215*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k32Value);
216*9356374aSAndroid Build Coastguard Worker
217*9356374aSAndroid Build Coastguard Worker little_endian::Store64(&u64Buf, k64Value);
218*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(u64Buf, k64ValueLE);
219*9356374aSAndroid Build Coastguard Worker comp = little_endian::Load64(&u64Buf);
220*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k64Value);
221*9356374aSAndroid Build Coastguard Worker }
222*9356374aSAndroid Build Coastguard Worker
TEST(EndianessTest,big_endian)223*9356374aSAndroid Build Coastguard Worker TEST(EndianessTest, big_endian) {
224*9356374aSAndroid Build Coastguard Worker // Check big-endian Load and store functions.
225*9356374aSAndroid Build Coastguard Worker uint16_t u16Buf;
226*9356374aSAndroid Build Coastguard Worker uint32_t u32Buf;
227*9356374aSAndroid Build Coastguard Worker uint64_t u64Buf;
228*9356374aSAndroid Build Coastguard Worker
229*9356374aSAndroid Build Coastguard Worker unsigned char buffer[10];
230*9356374aSAndroid Build Coastguard Worker big_endian::Store16(&u16Buf, k16Value);
231*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(u16Buf, k16ValueBE);
232*9356374aSAndroid Build Coastguard Worker uint64_t comp = big_endian::Load16(&u16Buf);
233*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k16Value);
234*9356374aSAndroid Build Coastguard Worker
235*9356374aSAndroid Build Coastguard Worker big_endian::Store32(&u32Buf, k32Value);
236*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(u32Buf, k32ValueBE);
237*9356374aSAndroid Build Coastguard Worker comp = big_endian::Load32(&u32Buf);
238*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k32Value);
239*9356374aSAndroid Build Coastguard Worker
240*9356374aSAndroid Build Coastguard Worker big_endian::Store64(&u64Buf, k64Value);
241*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(u64Buf, k64ValueBE);
242*9356374aSAndroid Build Coastguard Worker comp = big_endian::Load64(&u64Buf);
243*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k64Value);
244*9356374aSAndroid Build Coastguard Worker
245*9356374aSAndroid Build Coastguard Worker big_endian::Store16(buffer + 1, k16Value);
246*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(u16Buf, k16ValueBE);
247*9356374aSAndroid Build Coastguard Worker comp = big_endian::Load16(buffer + 1);
248*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k16Value);
249*9356374aSAndroid Build Coastguard Worker
250*9356374aSAndroid Build Coastguard Worker big_endian::Store32(buffer + 1, k32Value);
251*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(u32Buf, k32ValueBE);
252*9356374aSAndroid Build Coastguard Worker comp = big_endian::Load32(buffer + 1);
253*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k32Value);
254*9356374aSAndroid Build Coastguard Worker
255*9356374aSAndroid Build Coastguard Worker big_endian::Store64(buffer + 1, k64Value);
256*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(u64Buf, k64ValueBE);
257*9356374aSAndroid Build Coastguard Worker comp = big_endian::Load64(buffer + 1);
258*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(comp, k64Value);
259*9356374aSAndroid Build Coastguard Worker }
260*9356374aSAndroid Build Coastguard Worker
261*9356374aSAndroid Build Coastguard Worker } // namespace
262*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
263*9356374aSAndroid Build Coastguard Worker } // namespace absl
264