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 | |
16 | #ifndef ABSL_BASE_INTERNAL_ENDIAN_H_ |
17 | #define ABSL_BASE_INTERNAL_ENDIAN_H_ |
18 | |
19 | // The following guarantees declaration of the byte swap functions |
20 | #ifdef _MSC_VER |
21 | #include <stdlib.h> // NOLINT(build/include) |
22 | #elif defined(__APPLE__) |
23 | // Mac OS X / Darwin features |
24 | #include <libkern/OSByteOrder.h> |
25 | #elif defined(__FreeBSD__) |
26 | #include <sys/endian.h> |
27 | #elif defined(__GLIBC__) |
28 | #include <byteswap.h> // IWYU pragma: export |
29 | #endif |
30 | |
31 | #include <cstdint> |
32 | #include "absl/base/config.h" |
33 | #include "absl/base/internal/unaligned_access.h" |
34 | #include "absl/base/port.h" |
35 | |
36 | namespace absl { |
37 | |
38 | // Use compiler byte-swapping intrinsics if they are available. 32-bit |
39 | // and 64-bit versions are available in Clang and GCC as of GCC 4.3.0. |
40 | // The 16-bit version is available in Clang and GCC only as of GCC 4.8.0. |
41 | // For simplicity, we enable them all only for GCC 4.8.0 or later. |
42 | #if defined(__clang__) || \ |
43 | (defined(__GNUC__) && \ |
44 | ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5)) |
45 | inline uint64_t gbswap_64(uint64_t host_int) { |
46 | return __builtin_bswap64(host_int); |
47 | } |
48 | inline uint32_t gbswap_32(uint32_t host_int) { |
49 | return __builtin_bswap32(host_int); |
50 | } |
51 | inline uint16_t gbswap_16(uint16_t host_int) { |
52 | return __builtin_bswap16(host_int); |
53 | } |
54 | |
55 | #elif defined(_MSC_VER) |
56 | inline uint64_t gbswap_64(uint64_t host_int) { |
57 | return _byteswap_uint64(host_int); |
58 | } |
59 | inline uint32_t gbswap_32(uint32_t host_int) { |
60 | return _byteswap_ulong(host_int); |
61 | } |
62 | inline uint16_t gbswap_16(uint16_t host_int) { |
63 | return _byteswap_ushort(host_int); |
64 | } |
65 | |
66 | #elif defined(__APPLE__) |
67 | inline uint64_t gbswap_64(uint64_t host_int) { return OSSwapInt16(host_int); } |
68 | inline uint32_t gbswap_32(uint32_t host_int) { return OSSwapInt32(host_int); } |
69 | inline uint16_t gbswap_16(uint16_t host_int) { return OSSwapInt64(host_int); } |
70 | |
71 | #else |
72 | inline uint64_t gbswap_64(uint64_t host_int) { |
73 | #if defined(__GNUC__) && defined(__x86_64__) && !defined(__APPLE__) |
74 | // Adapted from /usr/include/byteswap.h. Not available on Mac. |
75 | if (__builtin_constant_p(host_int)) { |
76 | return __bswap_constant_64(host_int); |
77 | } else { |
78 | uint64_t result; |
79 | __asm__("bswap %0" : "=r" (result) : "0" (host_int)); |
80 | return result; |
81 | } |
82 | #elif defined(__GLIBC__) |
83 | return bswap_64(host_int); |
84 | #else |
85 | return (((host_int & uint64_t{0xFF}) << 56) | |
86 | ((host_int & uint64_t{0xFF00}) << 40) | |
87 | ((host_int & uint64_t{0xFF0000}) << 24) | |
88 | ((host_int & uint64_t{0xFF000000}) << 8) | |
89 | ((host_int & uint64_t{0xFF00000000}) >> 8) | |
90 | ((host_int & uint64_t{0xFF0000000000}) >> 24) | |
91 | ((host_int & uint64_t{0xFF000000000000}) >> 40) | |
92 | ((host_int & uint64_t{0xFF00000000000000}) >> 56)); |
93 | #endif // bswap_64 |
94 | } |
95 | |
96 | inline uint32_t gbswap_32(uint32_t host_int) { |
97 | #if defined(__GLIBC__) |
98 | return bswap_32(host_int); |
99 | #else |
100 | return (((host_int & uint32_t{0xFF}) << 24) | |
101 | ((host_int & uint32_t{0xFF00}) << 8) | |
102 | ((host_int & uint32_t{0xFF0000}) >> 8) | |
103 | ((host_int & uint32_t{0xFF000000}) >> 24)); |
104 | #endif |
105 | } |
106 | |
107 | inline uint16_t gbswap_16(uint16_t host_int) { |
108 | #if defined(__GLIBC__) |
109 | return bswap_16(host_int); |
110 | #else |
111 | return (((host_int & uint16_t{0xFF}) << 8) | |
112 | ((host_int & uint16_t{0xFF00}) >> 8)); |
113 | #endif |
114 | } |
115 | |
116 | #endif // intrinics available |
117 | |
118 | #ifdef ABSL_IS_LITTLE_ENDIAN |
119 | |
120 | // Definitions for ntohl etc. that don't require us to include |
121 | // netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather |
122 | // than just #defining them because in debug mode, gcc doesn't |
123 | // correctly handle the (rather involved) definitions of bswap_32. |
124 | // gcc guarantees that inline functions are as fast as macros, so |
125 | // this isn't a performance hit. |
126 | inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); } |
127 | inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); } |
128 | inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); } |
129 | |
130 | #elif defined ABSL_IS_BIG_ENDIAN |
131 | |
132 | // These definitions are simpler on big-endian machines |
133 | // These are functions instead of macros to avoid self-assignment warnings |
134 | // on calls such as "i = ghtnol(i);". This also provides type checking. |
135 | inline uint16_t ghtons(uint16_t x) { return x; } |
136 | inline uint32_t ghtonl(uint32_t x) { return x; } |
137 | inline uint64_t ghtonll(uint64_t x) { return x; } |
138 | |
139 | #else |
140 | #error \ |
141 | "Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \ |
142 | "ABSL_IS_LITTLE_ENDIAN must be defined" |
143 | #endif // byte order |
144 | |
145 | inline uint16_t gntohs(uint16_t x) { return ghtons(x); } |
146 | inline uint32_t gntohl(uint32_t x) { return ghtonl(x); } |
147 | inline uint64_t gntohll(uint64_t x) { return ghtonll(x); } |
148 | |
149 | // Utilities to convert numbers between the current hosts's native byte |
150 | // order and little-endian byte order |
151 | // |
152 | // Load/Store methods are alignment safe |
153 | namespace little_endian { |
154 | // Conversion functions. |
155 | #ifdef ABSL_IS_LITTLE_ENDIAN |
156 | |
157 | inline uint16_t FromHost16(uint16_t x) { return x; } |
158 | inline uint16_t ToHost16(uint16_t x) { return x; } |
159 | |
160 | inline uint32_t FromHost32(uint32_t x) { return x; } |
161 | inline uint32_t ToHost32(uint32_t x) { return x; } |
162 | |
163 | inline uint64_t FromHost64(uint64_t x) { return x; } |
164 | inline uint64_t ToHost64(uint64_t x) { return x; } |
165 | |
166 | inline constexpr bool IsLittleEndian() { return true; } |
167 | |
168 | #elif defined ABSL_IS_BIG_ENDIAN |
169 | |
170 | inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); } |
171 | inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); } |
172 | |
173 | inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); } |
174 | inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); } |
175 | |
176 | inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); } |
177 | inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); } |
178 | |
179 | inline constexpr bool IsLittleEndian() { return false; } |
180 | |
181 | #endif /* ENDIAN */ |
182 | |
183 | // Functions to do unaligned loads and stores in little-endian order. |
184 | inline uint16_t Load16(const void *p) { |
185 | return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); |
186 | } |
187 | |
188 | inline void Store16(void *p, uint16_t v) { |
189 | ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v)); |
190 | } |
191 | |
192 | inline uint32_t Load32(const void *p) { |
193 | return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p)); |
194 | } |
195 | |
196 | inline void Store32(void *p, uint32_t v) { |
197 | ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v)); |
198 | } |
199 | |
200 | inline uint64_t Load64(const void *p) { |
201 | return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p)); |
202 | } |
203 | |
204 | inline void Store64(void *p, uint64_t v) { |
205 | ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v)); |
206 | } |
207 | |
208 | } // namespace little_endian |
209 | |
210 | // Utilities to convert numbers between the current hosts's native byte |
211 | // order and big-endian byte order (same as network byte order) |
212 | // |
213 | // Load/Store methods are alignment safe |
214 | namespace big_endian { |
215 | #ifdef ABSL_IS_LITTLE_ENDIAN |
216 | |
217 | inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); } |
218 | inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); } |
219 | |
220 | inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); } |
221 | inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); } |
222 | |
223 | inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); } |
224 | inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); } |
225 | |
226 | inline constexpr bool IsLittleEndian() { return true; } |
227 | |
228 | #elif defined ABSL_IS_BIG_ENDIAN |
229 | |
230 | inline uint16_t FromHost16(uint16_t x) { return x; } |
231 | inline uint16_t ToHost16(uint16_t x) { return x; } |
232 | |
233 | inline uint32_t FromHost32(uint32_t x) { return x; } |
234 | inline uint32_t ToHost32(uint32_t x) { return x; } |
235 | |
236 | inline uint64_t FromHost64(uint64_t x) { return x; } |
237 | inline uint64_t ToHost64(uint64_t x) { return x; } |
238 | |
239 | inline constexpr bool IsLittleEndian() { return false; } |
240 | |
241 | #endif /* ENDIAN */ |
242 | |
243 | // Functions to do unaligned loads and stores in big-endian order. |
244 | inline uint16_t Load16(const void *p) { |
245 | return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); |
246 | } |
247 | |
248 | inline void Store16(void *p, uint16_t v) { |
249 | ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v)); |
250 | } |
251 | |
252 | inline uint32_t Load32(const void *p) { |
253 | return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p)); |
254 | } |
255 | |
256 | inline void Store32(void *p, uint32_t v) { |
257 | ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v)); |
258 | } |
259 | |
260 | inline uint64_t Load64(const void *p) { |
261 | return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p)); |
262 | } |
263 | |
264 | inline void Store64(void *p, uint64_t v) { |
265 | ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v)); |
266 | } |
267 | |
268 | } // namespace big_endian |
269 | |
270 | } // namespace absl |
271 | |
272 | #endif // ABSL_BASE_INTERNAL_ENDIAN_H_ |
273 | |