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