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 #include <cstdint>
20 #include <cstdlib>
21
22 #include "absl/base/casts.h"
23 #include "absl/base/config.h"
24 #include "absl/base/internal/unaligned_access.h"
25 #include "absl/base/port.h"
26
27 namespace absl {
28 ABSL_NAMESPACE_BEGIN
29
gbswap_64(uint64_t host_int)30 inline uint64_t gbswap_64(uint64_t host_int) {
31 #if ABSL_HAVE_BUILTIN(__builtin_bswap64) || defined(__GNUC__)
32 return __builtin_bswap64(host_int);
33 #elif defined(_MSC_VER)
34 return _byteswap_uint64(host_int);
35 #else
36 return (((host_int & uint64_t{0xFF}) << 56) |
37 ((host_int & uint64_t{0xFF00}) << 40) |
38 ((host_int & uint64_t{0xFF0000}) << 24) |
39 ((host_int & uint64_t{0xFF000000}) << 8) |
40 ((host_int & uint64_t{0xFF00000000}) >> 8) |
41 ((host_int & uint64_t{0xFF0000000000}) >> 24) |
42 ((host_int & uint64_t{0xFF000000000000}) >> 40) |
43 ((host_int & uint64_t{0xFF00000000000000}) >> 56));
44 #endif
45 }
46
gbswap_32(uint32_t host_int)47 inline uint32_t gbswap_32(uint32_t host_int) {
48 #if ABSL_HAVE_BUILTIN(__builtin_bswap32) || defined(__GNUC__)
49 return __builtin_bswap32(host_int);
50 #elif defined(_MSC_VER)
51 return _byteswap_ulong(host_int);
52 #else
53 return (((host_int & uint32_t{0xFF}) << 24) |
54 ((host_int & uint32_t{0xFF00}) << 8) |
55 ((host_int & uint32_t{0xFF0000}) >> 8) |
56 ((host_int & uint32_t{0xFF000000}) >> 24));
57 #endif
58 }
59
gbswap_16(uint16_t host_int)60 inline uint16_t gbswap_16(uint16_t host_int) {
61 #if ABSL_HAVE_BUILTIN(__builtin_bswap16) || defined(__GNUC__)
62 return __builtin_bswap16(host_int);
63 #elif defined(_MSC_VER)
64 return _byteswap_ushort(host_int);
65 #else
66 return (((host_int & uint16_t{0xFF}) << 8) |
67 ((host_int & uint16_t{0xFF00}) >> 8));
68 #endif
69 }
70
71 #ifdef ABSL_IS_LITTLE_ENDIAN
72
73 // Portable definitions for htonl (host-to-network) and friends on little-endian
74 // architectures.
ghtons(uint16_t x)75 inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
ghtonl(uint32_t x)76 inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
ghtonll(uint64_t x)77 inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
78
79 #elif defined ABSL_IS_BIG_ENDIAN
80
81 // Portable definitions for htonl (host-to-network) etc on big-endian
82 // architectures. These definitions are simpler since the host byte order is the
83 // same as network byte order.
ghtons(uint16_t x)84 inline uint16_t ghtons(uint16_t x) { return x; }
ghtonl(uint32_t x)85 inline uint32_t ghtonl(uint32_t x) { return x; }
ghtonll(uint64_t x)86 inline uint64_t ghtonll(uint64_t x) { return x; }
87
88 #else
89 #error \
90 "Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \
91 "ABSL_IS_LITTLE_ENDIAN must be defined"
92 #endif // byte order
93
gntohs(uint16_t x)94 inline uint16_t gntohs(uint16_t x) { return ghtons(x); }
gntohl(uint32_t x)95 inline uint32_t gntohl(uint32_t x) { return ghtonl(x); }
gntohll(uint64_t x)96 inline uint64_t gntohll(uint64_t x) { return ghtonll(x); }
97
98 // Utilities to convert numbers between the current hosts's native byte
99 // order and little-endian byte order
100 //
101 // Load/Store methods are alignment safe
102 namespace little_endian {
103 // Conversion functions.
104 #ifdef ABSL_IS_LITTLE_ENDIAN
105
FromHost16(uint16_t x)106 inline uint16_t FromHost16(uint16_t x) { return x; }
ToHost16(uint16_t x)107 inline uint16_t ToHost16(uint16_t x) { return x; }
108
FromHost32(uint32_t x)109 inline uint32_t FromHost32(uint32_t x) { return x; }
ToHost32(uint32_t x)110 inline uint32_t ToHost32(uint32_t x) { return x; }
111
FromHost64(uint64_t x)112 inline uint64_t FromHost64(uint64_t x) { return x; }
ToHost64(uint64_t x)113 inline uint64_t ToHost64(uint64_t x) { return x; }
114
IsLittleEndian()115 inline constexpr bool IsLittleEndian() { return true; }
116
117 #elif defined ABSL_IS_BIG_ENDIAN
118
119 inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
120 inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
121
122 inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
123 inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
124
125 inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
126 inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
127
128 inline constexpr bool IsLittleEndian() { return false; }
129
130 #endif /* ENDIAN */
131
FromHost(uint8_t x)132 inline uint8_t FromHost(uint8_t x) { return x; }
FromHost(uint16_t x)133 inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
FromHost(uint32_t x)134 inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
FromHost(uint64_t x)135 inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
ToHost(uint8_t x)136 inline uint8_t ToHost(uint8_t x) { return x; }
ToHost(uint16_t x)137 inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
ToHost(uint32_t x)138 inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
ToHost(uint64_t x)139 inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
140
FromHost(int8_t x)141 inline int8_t FromHost(int8_t x) { return x; }
FromHost(int16_t x)142 inline int16_t FromHost(int16_t x) {
143 return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
144 }
FromHost(int32_t x)145 inline int32_t FromHost(int32_t x) {
146 return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
147 }
FromHost(int64_t x)148 inline int64_t FromHost(int64_t x) {
149 return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
150 }
ToHost(int8_t x)151 inline int8_t ToHost(int8_t x) { return x; }
ToHost(int16_t x)152 inline int16_t ToHost(int16_t x) {
153 return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
154 }
ToHost(int32_t x)155 inline int32_t ToHost(int32_t x) {
156 return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
157 }
ToHost(int64_t x)158 inline int64_t ToHost(int64_t x) {
159 return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
160 }
161
162 // Functions to do unaligned loads and stores in little-endian order.
Load16(const void * p)163 inline uint16_t Load16(const void *p) {
164 return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
165 }
166
Store16(void * p,uint16_t v)167 inline void Store16(void *p, uint16_t v) {
168 ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
169 }
170
Load32(const void * p)171 inline uint32_t Load32(const void *p) {
172 return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
173 }
174
Store32(void * p,uint32_t v)175 inline void Store32(void *p, uint32_t v) {
176 ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
177 }
178
Load64(const void * p)179 inline uint64_t Load64(const void *p) {
180 return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
181 }
182
Store64(void * p,uint64_t v)183 inline void Store64(void *p, uint64_t v) {
184 ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
185 }
186
187 } // namespace little_endian
188
189 // Utilities to convert numbers between the current hosts's native byte
190 // order and big-endian byte order (same as network byte order)
191 //
192 // Load/Store methods are alignment safe
193 namespace big_endian {
194 #ifdef ABSL_IS_LITTLE_ENDIAN
195
FromHost16(uint16_t x)196 inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
ToHost16(uint16_t x)197 inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
198
FromHost32(uint32_t x)199 inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
ToHost32(uint32_t x)200 inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
201
FromHost64(uint64_t x)202 inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
ToHost64(uint64_t x)203 inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
204
IsLittleEndian()205 inline constexpr bool IsLittleEndian() { return true; }
206
207 #elif defined ABSL_IS_BIG_ENDIAN
208
209 inline uint16_t FromHost16(uint16_t x) { return x; }
210 inline uint16_t ToHost16(uint16_t x) { return x; }
211
212 inline uint32_t FromHost32(uint32_t x) { return x; }
213 inline uint32_t ToHost32(uint32_t x) { return x; }
214
215 inline uint64_t FromHost64(uint64_t x) { return x; }
216 inline uint64_t ToHost64(uint64_t x) { return x; }
217
218 inline constexpr bool IsLittleEndian() { return false; }
219
220 #endif /* ENDIAN */
221
FromHost(uint8_t x)222 inline uint8_t FromHost(uint8_t x) { return x; }
FromHost(uint16_t x)223 inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
FromHost(uint32_t x)224 inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
FromHost(uint64_t x)225 inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
ToHost(uint8_t x)226 inline uint8_t ToHost(uint8_t x) { return x; }
ToHost(uint16_t x)227 inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
ToHost(uint32_t x)228 inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
ToHost(uint64_t x)229 inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
230
FromHost(int8_t x)231 inline int8_t FromHost(int8_t x) { return x; }
FromHost(int16_t x)232 inline int16_t FromHost(int16_t x) {
233 return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
234 }
FromHost(int32_t x)235 inline int32_t FromHost(int32_t x) {
236 return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
237 }
FromHost(int64_t x)238 inline int64_t FromHost(int64_t x) {
239 return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
240 }
ToHost(int8_t x)241 inline int8_t ToHost(int8_t x) { return x; }
ToHost(int16_t x)242 inline int16_t ToHost(int16_t x) {
243 return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
244 }
ToHost(int32_t x)245 inline int32_t ToHost(int32_t x) {
246 return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
247 }
ToHost(int64_t x)248 inline int64_t ToHost(int64_t x) {
249 return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
250 }
251
252 // Functions to do unaligned loads and stores in big-endian order.
Load16(const void * p)253 inline uint16_t Load16(const void *p) {
254 return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
255 }
256
Store16(void * p,uint16_t v)257 inline void Store16(void *p, uint16_t v) {
258 ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
259 }
260
Load32(const void * p)261 inline uint32_t Load32(const void *p) {
262 return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
263 }
264
Store32(void * p,uint32_t v)265 inline void Store32(void *p, uint32_t v) {
266 ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
267 }
268
Load64(const void * p)269 inline uint64_t Load64(const void *p) {
270 return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
271 }
272
Store64(void * p,uint64_t v)273 inline void Store64(void *p, uint64_t v) {
274 ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
275 }
276
277 } // namespace big_endian
278
279 ABSL_NAMESPACE_END
280 } // namespace absl
281
282 #endif // ABSL_BASE_INTERNAL_ENDIAN_H_
283