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