byte_order.h (7548B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #ifndef LIB_JXL_BASE_BYTE_ORDER_H_ 7 #define LIB_JXL_BASE_BYTE_ORDER_H_ 8 9 #include <jxl/types.h> 10 #include <stdint.h> 11 #include <string.h> // memcpy 12 13 #include "lib/jxl/base/compiler_specific.h" 14 15 #if JXL_COMPILER_MSVC 16 #include <intrin.h> // _byteswap_* 17 #endif 18 19 #if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) 20 #define JXL_BYTE_ORDER_LITTLE 1 21 #else 22 // This means that we don't know that the byte order is little endian, in 23 // this case we use endian-neutral code that works for both little- and 24 // big-endian. 25 #define JXL_BYTE_ORDER_LITTLE 0 26 #endif 27 28 // Returns whether the system is little-endian (least-significant byte first). 29 #if JXL_BYTE_ORDER_LITTLE 30 static constexpr bool IsLittleEndian() { return true; } 31 #else 32 static inline bool IsLittleEndian() { 33 const uint32_t multibyte = 1; 34 uint8_t byte; 35 memcpy(&byte, &multibyte, 1); 36 return byte == 1; 37 } 38 #endif 39 40 static inline bool SwapEndianness(JxlEndianness endianness) { 41 return ((endianness == JXL_BIG_ENDIAN && IsLittleEndian()) || 42 (endianness == JXL_LITTLE_ENDIAN && !IsLittleEndian())); 43 } 44 45 #if JXL_COMPILER_MSVC 46 #define JXL_BSWAP16(x) _byteswap_ushort(x) 47 #define JXL_BSWAP32(x) _byteswap_ulong(x) 48 #define JXL_BSWAP64(x) _byteswap_uint64(x) 49 #else 50 #define JXL_BSWAP16(x) __builtin_bswap16(x) 51 #define JXL_BSWAP32(x) __builtin_bswap32(x) 52 #define JXL_BSWAP64(x) __builtin_bswap64(x) 53 #endif 54 55 static JXL_INLINE uint32_t LoadBE16(const uint8_t* p) { 56 const uint32_t byte1 = p[0]; 57 const uint32_t byte0 = p[1]; 58 return (byte1 << 8) | byte0; 59 } 60 61 static JXL_INLINE uint32_t LoadLE16(const uint8_t* p) { 62 const uint32_t byte0 = p[0]; 63 const uint32_t byte1 = p[1]; 64 return (byte1 << 8) | byte0; 65 } 66 67 static JXL_INLINE uint32_t LoadBE32(const uint8_t* p) { 68 #if JXL_BYTE_ORDER_LITTLE 69 uint32_t big; 70 memcpy(&big, p, 4); 71 return JXL_BSWAP32(big); 72 #else 73 // Byte-order-independent - can't assume this machine is big endian. 74 const uint32_t byte3 = p[0]; 75 const uint32_t byte2 = p[1]; 76 const uint32_t byte1 = p[2]; 77 const uint32_t byte0 = p[3]; 78 return (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0; 79 #endif 80 } 81 82 static JXL_INLINE uint64_t LoadBE64(const uint8_t* p) { 83 #if JXL_BYTE_ORDER_LITTLE 84 uint64_t big; 85 memcpy(&big, p, 8); 86 return JXL_BSWAP64(big); 87 #else 88 // Byte-order-independent - can't assume this machine is big endian. 89 const uint64_t byte7 = p[0]; 90 const uint64_t byte6 = p[1]; 91 const uint64_t byte5 = p[2]; 92 const uint64_t byte4 = p[3]; 93 const uint64_t byte3 = p[4]; 94 const uint64_t byte2 = p[5]; 95 const uint64_t byte1 = p[6]; 96 const uint64_t byte0 = p[7]; 97 return (byte7 << 56ull) | (byte6 << 48ull) | (byte5 << 40ull) | 98 (byte4 << 32ull) | (byte3 << 24ull) | (byte2 << 16ull) | 99 (byte1 << 8ull) | byte0; 100 #endif 101 } 102 103 static JXL_INLINE uint32_t LoadLE32(const uint8_t* p) { 104 #if JXL_BYTE_ORDER_LITTLE 105 uint32_t little; 106 memcpy(&little, p, 4); 107 return little; 108 #else 109 // Byte-order-independent - can't assume this machine is big endian. 110 const uint32_t byte0 = p[0]; 111 const uint32_t byte1 = p[1]; 112 const uint32_t byte2 = p[2]; 113 const uint32_t byte3 = p[3]; 114 return (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0; 115 #endif 116 } 117 118 static JXL_INLINE uint64_t LoadLE64(const uint8_t* p) { 119 #if JXL_BYTE_ORDER_LITTLE 120 uint64_t little; 121 memcpy(&little, p, 8); 122 return little; 123 #else 124 // Byte-order-independent - can't assume this machine is big endian. 125 const uint64_t byte0 = p[0]; 126 const uint64_t byte1 = p[1]; 127 const uint64_t byte2 = p[2]; 128 const uint64_t byte3 = p[3]; 129 const uint64_t byte4 = p[4]; 130 const uint64_t byte5 = p[5]; 131 const uint64_t byte6 = p[6]; 132 const uint64_t byte7 = p[7]; 133 return (byte7 << 56) | (byte6 << 48) | (byte5 << 40) | (byte4 << 32) | 134 (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0; 135 #endif 136 } 137 138 // Loads a Big-Endian float 139 static JXL_INLINE float LoadBEFloat(const uint8_t* p) { 140 uint32_t u = LoadBE32(p); 141 float result; 142 memcpy(&result, &u, 4); 143 return result; 144 } 145 146 // Loads a Little-Endian float 147 static JXL_INLINE float LoadLEFloat(const uint8_t* p) { 148 uint32_t u = LoadLE32(p); 149 float result; 150 memcpy(&result, &u, 4); 151 return result; 152 } 153 154 static JXL_INLINE void StoreBE16(const uint32_t native, uint8_t* p) { 155 p[0] = (native >> 8) & 0xFF; 156 p[1] = native & 0xFF; 157 } 158 159 static JXL_INLINE void StoreLE16(const uint32_t native, uint8_t* p) { 160 p[1] = (native >> 8) & 0xFF; 161 p[0] = native & 0xFF; 162 } 163 164 static JXL_INLINE void StoreBE32(const uint32_t native, uint8_t* p) { 165 #if JXL_BYTE_ORDER_LITTLE 166 const uint32_t big = JXL_BSWAP32(native); 167 memcpy(p, &big, 4); 168 #else 169 // Byte-order-independent - can't assume this machine is big endian. 170 p[0] = native >> 24; 171 p[1] = (native >> 16) & 0xFF; 172 p[2] = (native >> 8) & 0xFF; 173 p[3] = native & 0xFF; 174 #endif 175 } 176 177 static JXL_INLINE void StoreBE64(const uint64_t native, uint8_t* p) { 178 #if JXL_BYTE_ORDER_LITTLE 179 const uint64_t big = JXL_BSWAP64(native); 180 memcpy(p, &big, 8); 181 #else 182 // Byte-order-independent - can't assume this machine is big endian. 183 p[0] = native >> 56ull; 184 p[1] = (native >> 48ull) & 0xFF; 185 p[2] = (native >> 40ull) & 0xFF; 186 p[3] = (native >> 32ull) & 0xFF; 187 p[4] = (native >> 24ull) & 0xFF; 188 p[5] = (native >> 16ull) & 0xFF; 189 p[6] = (native >> 8ull) & 0xFF; 190 p[7] = native & 0xFF; 191 #endif 192 } 193 194 static JXL_INLINE void StoreLE32(const uint32_t native, uint8_t* p) { 195 #if JXL_BYTE_ORDER_LITTLE 196 const uint32_t little = native; 197 memcpy(p, &little, 4); 198 #else 199 // Byte-order-independent - can't assume this machine is big endian. 200 p[3] = native >> 24; 201 p[2] = (native >> 16) & 0xFF; 202 p[1] = (native >> 8) & 0xFF; 203 p[0] = native & 0xFF; 204 #endif 205 } 206 207 static JXL_INLINE void StoreLE64(const uint64_t native, uint8_t* p) { 208 #if JXL_BYTE_ORDER_LITTLE 209 const uint64_t little = native; 210 memcpy(p, &little, 8); 211 #else 212 // Byte-order-independent - can't assume this machine is big endian. 213 p[7] = native >> 56; 214 p[6] = (native >> 48) & 0xFF; 215 p[5] = (native >> 40) & 0xFF; 216 p[4] = (native >> 32) & 0xFF; 217 p[3] = (native >> 24) & 0xFF; 218 p[2] = (native >> 16) & 0xFF; 219 p[1] = (native >> 8) & 0xFF; 220 p[0] = native & 0xFF; 221 #endif 222 } 223 224 static JXL_INLINE float BSwapFloat(float x) { 225 uint32_t u; 226 memcpy(&u, &x, 4); 227 uint32_t uswap = JXL_BSWAP32(u); 228 float xswap; 229 memcpy(&xswap, &uswap, 4); 230 return xswap; 231 } 232 233 // Big/Little Endian order. 234 struct OrderBE {}; 235 struct OrderLE {}; 236 237 // Wrappers for calling from generic code. 238 static JXL_INLINE void Store16(OrderBE /*tag*/, const uint32_t native, 239 uint8_t* p) { 240 StoreBE16(native, p); 241 } 242 243 static JXL_INLINE void Store16(OrderLE /*tag*/, const uint32_t native, 244 uint8_t* p) { 245 StoreLE16(native, p); 246 } 247 248 static JXL_INLINE void Store32(OrderBE /*tag*/, const uint32_t native, 249 uint8_t* p) { 250 StoreBE32(native, p); 251 } 252 253 static JXL_INLINE void Store32(OrderLE /*tag*/, const uint32_t native, 254 uint8_t* p) { 255 StoreLE32(native, p); 256 } 257 258 static JXL_INLINE uint32_t Load16(OrderBE /*tag*/, const uint8_t* p) { 259 return LoadBE16(p); 260 } 261 262 static JXL_INLINE uint32_t Load16(OrderLE /*tag*/, const uint8_t* p) { 263 return LoadLE16(p); 264 } 265 266 static JXL_INLINE uint32_t Load32(OrderBE /*tag*/, const uint8_t* p) { 267 return LoadBE32(p); 268 } 269 270 static JXL_INLINE uint32_t Load32(OrderLE /*tag*/, const uint8_t* p) { 271 return LoadLE32(p); 272 } 273 274 #endif // LIB_JXL_BASE_BYTE_ORDER_H_