• 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 
GenerateAllUint16Values()57 std::vector<uint16_t> GenerateAllUint16Values() {
58   std::vector<uint16_t> result;
59   result.reserve(size_t{1} << (sizeof(uint16_t) * 8));
60   for (uint32_t i = std::numeric_limits<uint16_t>::min();
61        i <= std::numeric_limits<uint16_t>::max(); ++i) {
62     result.push_back(static_cast<uint16_t>(i));
63   }
64   return result;
65 }
66 
67 template<typename T>
GenerateRandomIntegers(size_t num_values_to_test)68 std::vector<T> GenerateRandomIntegers(size_t num_values_to_test) {
69   std::vector<T> result;
70   result.reserve(num_values_to_test);
71   std::mt19937_64 rng(kRandomSeed);
72   for (size_t i = 0; i < num_values_to_test; ++i) {
73     result.push_back(rng());
74   }
75   return result;
76 }
77 
ManualByteSwap(char * bytes,int length)78 void ManualByteSwap(char* bytes, int length) {
79   if (length == 1)
80     return;
81 
82   EXPECT_EQ(0, length % 2);
83   for (int i = 0; i < length / 2; ++i) {
84     int j = (length - 1) - i;
85     using std::swap;
86     swap(bytes[i], bytes[j]);
87   }
88 }
89 
90 template<typename T>
UnalignedLoad(const char * p)91 inline T UnalignedLoad(const char* p) {
92   static_assert(
93       sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
94       "Unexpected type size");
95 
96   switch (sizeof(T)) {
97     case 1: return *reinterpret_cast<const T*>(p);
98     case 2:
99       return ABSL_INTERNAL_UNALIGNED_LOAD16(p);
100     case 4:
101       return ABSL_INTERNAL_UNALIGNED_LOAD32(p);
102     case 8:
103       return ABSL_INTERNAL_UNALIGNED_LOAD64(p);
104     default:
105       // Suppresses invalid "not all control paths return a value" on MSVC
106       return {};
107   }
108 }
109 
110 template <typename T, typename ByteSwapper>
GBSwapHelper(const std::vector<T> & host_values_to_test,const ByteSwapper & byte_swapper)111 static void GBSwapHelper(const std::vector<T>& host_values_to_test,
112                          const ByteSwapper& byte_swapper) {
113   // Test byte_swapper against a manual byte swap.
114   for (typename std::vector<T>::const_iterator it = host_values_to_test.begin();
115        it != host_values_to_test.end(); ++it) {
116     T host_value = *it;
117 
118     char actual_value[sizeof(host_value)];
119     memcpy(actual_value, &host_value, sizeof(host_value));
120     byte_swapper(actual_value);
121 
122     char expected_value[sizeof(host_value)];
123     memcpy(expected_value, &host_value, sizeof(host_value));
124     ManualByteSwap(expected_value, sizeof(host_value));
125 
126     ASSERT_EQ(0, memcmp(actual_value, expected_value, sizeof(host_value)))
127         << "Swap output for 0x" << std::hex << host_value << " does not match. "
128         << "Expected: 0x" << UnalignedLoad<T>(expected_value) << "; "
129         << "actual: 0x" <<  UnalignedLoad<T>(actual_value);
130   }
131 }
132 
Swap16(char * bytes)133 void Swap16(char* bytes) {
134   ABSL_INTERNAL_UNALIGNED_STORE16(
135       bytes, gbswap_16(ABSL_INTERNAL_UNALIGNED_LOAD16(bytes)));
136 }
137 
Swap32(char * bytes)138 void Swap32(char* bytes) {
139   ABSL_INTERNAL_UNALIGNED_STORE32(
140       bytes, gbswap_32(ABSL_INTERNAL_UNALIGNED_LOAD32(bytes)));
141 }
142 
Swap64(char * bytes)143 void Swap64(char* bytes) {
144   ABSL_INTERNAL_UNALIGNED_STORE64(
145       bytes, gbswap_64(ABSL_INTERNAL_UNALIGNED_LOAD64(bytes)));
146 }
147 
TEST(EndianessTest,Uint16)148 TEST(EndianessTest, Uint16) {
149   GBSwapHelper(GenerateAllUint16Values(), &Swap16);
150 }
151 
TEST(EndianessTest,Uint32)152 TEST(EndianessTest, Uint32) {
153   GBSwapHelper(GenerateRandomIntegers<uint32_t>(kNumValuesToTest), &Swap32);
154 }
155 
TEST(EndianessTest,Uint64)156 TEST(EndianessTest, Uint64) {
157   GBSwapHelper(GenerateRandomIntegers<uint64_t>(kNumValuesToTest), &Swap64);
158 }
159 
TEST(EndianessTest,ghtonll_gntohll)160 TEST(EndianessTest, ghtonll_gntohll) {
161   // Test that absl::ghtonl compiles correctly
162   uint32_t test = 0x01234567;
163   EXPECT_EQ(absl::gntohl(absl::ghtonl(test)), test);
164 
165   uint64_t comp = absl::ghtonll(kInitialNumber);
166   EXPECT_EQ(comp, kInitialInNetworkOrder);
167   comp = absl::gntohll(kInitialInNetworkOrder);
168   EXPECT_EQ(comp, kInitialNumber);
169 
170   // Test that htonll and ntohll are each others' inverse functions on a
171   // somewhat assorted batch of numbers. 37 is chosen to not be anything
172   // particularly nice base 2.
173   uint64_t value = 1;
174   for (int i = 0; i < 100; ++i) {
175     comp = absl::ghtonll(absl::gntohll(value));
176     EXPECT_EQ(value, comp);
177     comp = absl::gntohll(absl::ghtonll(value));
178     EXPECT_EQ(value, comp);
179     value *= 37;
180   }
181 }
182 
TEST(EndianessTest,little_endian)183 TEST(EndianessTest, little_endian) {
184   // Check little_endian uint16_t.
185   uint64_t comp = little_endian::FromHost16(k16Value);
186   EXPECT_EQ(comp, k16ValueLE);
187   comp = little_endian::ToHost16(k16ValueLE);
188   EXPECT_EQ(comp, k16Value);
189 
190   // Check little_endian uint32_t.
191   comp = little_endian::FromHost32(k32Value);
192   EXPECT_EQ(comp, k32ValueLE);
193   comp = little_endian::ToHost32(k32ValueLE);
194   EXPECT_EQ(comp, k32Value);
195 
196   // Check little_endian uint64_t.
197   comp = little_endian::FromHost64(k64Value);
198   EXPECT_EQ(comp, k64ValueLE);
199   comp = little_endian::ToHost64(k64ValueLE);
200   EXPECT_EQ(comp, k64Value);
201 
202   // Check little-endian Load and store functions.
203   uint16_t u16Buf;
204   uint32_t u32Buf;
205   uint64_t u64Buf;
206 
207   little_endian::Store16(&u16Buf, k16Value);
208   EXPECT_EQ(u16Buf, k16ValueLE);
209   comp = little_endian::Load16(&u16Buf);
210   EXPECT_EQ(comp, k16Value);
211 
212   little_endian::Store32(&u32Buf, k32Value);
213   EXPECT_EQ(u32Buf, k32ValueLE);
214   comp = little_endian::Load32(&u32Buf);
215   EXPECT_EQ(comp, k32Value);
216 
217   little_endian::Store64(&u64Buf, k64Value);
218   EXPECT_EQ(u64Buf, k64ValueLE);
219   comp = little_endian::Load64(&u64Buf);
220   EXPECT_EQ(comp, k64Value);
221 }
222 
TEST(EndianessTest,big_endian)223 TEST(EndianessTest, big_endian) {
224   // Check big-endian Load and store functions.
225   uint16_t u16Buf;
226   uint32_t u32Buf;
227   uint64_t u64Buf;
228 
229   unsigned char buffer[10];
230   big_endian::Store16(&u16Buf, k16Value);
231   EXPECT_EQ(u16Buf, k16ValueBE);
232   uint64_t comp = big_endian::Load16(&u16Buf);
233   EXPECT_EQ(comp, k16Value);
234 
235   big_endian::Store32(&u32Buf, k32Value);
236   EXPECT_EQ(u32Buf, k32ValueBE);
237   comp = big_endian::Load32(&u32Buf);
238   EXPECT_EQ(comp, k32Value);
239 
240   big_endian::Store64(&u64Buf, k64Value);
241   EXPECT_EQ(u64Buf, k64ValueBE);
242   comp = big_endian::Load64(&u64Buf);
243   EXPECT_EQ(comp, k64Value);
244 
245   big_endian::Store16(buffer + 1, k16Value);
246   EXPECT_EQ(u16Buf, k16ValueBE);
247   comp = big_endian::Load16(buffer + 1);
248   EXPECT_EQ(comp, k16Value);
249 
250   big_endian::Store32(buffer + 1, k32Value);
251   EXPECT_EQ(u32Buf, k32ValueBE);
252   comp = big_endian::Load32(buffer + 1);
253   EXPECT_EQ(comp, k32Value);
254 
255   big_endian::Store64(buffer + 1, k64Value);
256   EXPECT_EQ(u64Buf, k64ValueBE);
257   comp = big_endian::Load64(buffer + 1);
258   EXPECT_EQ(comp, k64Value);
259 }
260 
261 }  // namespace
262 ABSL_NAMESPACE_END
263 }  // namespace absl
264