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