SDL 3.0
SDL_endian.h
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22/**
23 * # CategoryEndian
24 *
25 * Functions for reading and writing endian-specific values.
26 */
27
28#ifndef SDL_endian_h_
29#define SDL_endian_h_
30
31#include <SDL3/SDL_stdinc.h>
32
33#if defined(_MSC_VER) && (_MSC_VER >= 1400)
34/* As of Clang 11, '_m_prefetchw' is conflicting with the winnt.h's version,
35 so we define the needed '_m_prefetch' here as a pseudo-header, until the issue is fixed. */
36#ifdef __clang__
37#ifndef __PRFCHWINTRIN_H
38#define __PRFCHWINTRIN_H
39static __inline__ void __attribute__((__always_inline__, __nodebug__))
40_m_prefetch(void *__P)
41{
42 __builtin_prefetch(__P, 0, 3 /* _MM_HINT_T0 */);
43}
44#endif /* __PRFCHWINTRIN_H */
45#endif /* __clang__ */
46
47#include <intrin.h>
48#endif
49
50/**
51 * \name The two types of endianness
52 */
53/* @{ */
54#define SDL_LIL_ENDIAN 1234
55#define SDL_BIG_ENDIAN 4321
56/* @} */
57
58#ifndef SDL_BYTEORDER
59#ifdef SDL_PLATFORM_LINUX
60#include <endian.h>
61#define SDL_BYTEORDER __BYTE_ORDER
62#elif defined(SDL_PLATFORM_SOLARIS)
63#include <sys/byteorder.h>
64#if defined(_LITTLE_ENDIAN)
65#define SDL_BYTEORDER SDL_LIL_ENDIAN
66#elif defined(_BIG_ENDIAN)
67#define SDL_BYTEORDER SDL_BIG_ENDIAN
68#else
69#error Unsupported endianness
70#endif
71#elif defined(SDL_PLATFORM_OPENBSD) || defined(__DragonFly__)
72#include <endian.h>
73#define SDL_BYTEORDER BYTE_ORDER
74#elif defined(SDL_PLATFORM_FREEBSD) || defined(SDL_PLATFORM_NETBSD)
75#include <sys/endian.h>
76#define SDL_BYTEORDER BYTE_ORDER
77/* predefs from newer gcc and clang versions: */
78#elif defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__BYTE_ORDER__)
79#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
80#define SDL_BYTEORDER SDL_LIL_ENDIAN
81#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
82#define SDL_BYTEORDER SDL_BIG_ENDIAN
83#else
84#error Unsupported endianness
85#endif /**/
86#else
87#if defined(__hppa__) || \
88 defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
89 (defined(__MIPS__) && defined(__MIPSEB__)) || \
90 defined(__ppc__) || defined(__POWERPC__) || defined(__powerpc__) || defined(__PPC__) || \
91 defined(__sparc__) || defined(__sparc)
92#define SDL_BYTEORDER SDL_BIG_ENDIAN
93#else
94#define SDL_BYTEORDER SDL_LIL_ENDIAN
95#endif
96#endif /* SDL_PLATFORM_LINUX */
97#endif /* !SDL_BYTEORDER */
98
99#ifndef SDL_FLOATWORDORDER
100/* predefs from newer gcc versions: */
101#if defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__FLOAT_WORD_ORDER__)
102#if (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
103#define SDL_FLOATWORDORDER SDL_LIL_ENDIAN
104#elif (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
105#define SDL_FLOATWORDORDER SDL_BIG_ENDIAN
106#else
107#error Unsupported endianness
108#endif /**/
109#elif defined(__MAVERICK__)
110/* For Maverick, float words are always little-endian. */
111#define SDL_FLOATWORDORDER SDL_LIL_ENDIAN
112#elif (defined(__arm__) || defined(__thumb__)) && !defined(__VFP_FP__) && !defined(__ARM_EABI__)
113/* For FPA, float words are always big-endian. */
114#define SDL_FLOATWORDORDER SDL_BIG_ENDIAN
115#else
116/* By default, assume that floats words follow the memory system mode. */
117#define SDL_FLOATWORDORDER SDL_BYTEORDER
118#endif /* __FLOAT_WORD_ORDER__ */
119#endif /* !SDL_FLOATWORDORDER */
120
121
122#include <SDL3/SDL_begin_code.h>
123/* Set up for C function definitions, even when using C++ */
124#ifdef __cplusplus
125extern "C" {
126#endif
127
128/**
129 * \file SDL_endian.h
130 */
131
132/* various modern compilers may have builtin swap */
133#if defined(__GNUC__) || defined(__clang__)
134# define HAS_BUILTIN_BSWAP16 (SDL_HAS_BUILTIN(__builtin_bswap16)) || \
135 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
136# define HAS_BUILTIN_BSWAP32 (SDL_HAS_BUILTIN(__builtin_bswap32)) || \
137 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
138# define HAS_BUILTIN_BSWAP64 (SDL_HAS_BUILTIN(__builtin_bswap64)) || \
139 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
140
141 /* this one is broken */
142# define HAS_BROKEN_BSWAP (__GNUC__ == 2 && __GNUC_MINOR__ <= 95)
143#else
144# define HAS_BUILTIN_BSWAP16 0
145# define HAS_BUILTIN_BSWAP32 0
146# define HAS_BUILTIN_BSWAP64 0
147# define HAS_BROKEN_BSWAP 0
148#endif
149
150/* Byte swap 16-bit integer. */
151#if HAS_BUILTIN_BSWAP16
152#define SDL_Swap16(x) __builtin_bswap16(x)
153#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
154#pragma intrinsic(_byteswap_ushort)
155#define SDL_Swap16(x) _byteswap_ushort(x)
156#elif defined(__i386__) && !HAS_BROKEN_BSWAP
158{
159 __asm__("xchgb %b0,%h0": "=q"(x):"0"(x));
160 return x;
161}
162#elif defined(__x86_64__)
164{
165 __asm__("xchgb %b0,%h0": "=Q"(x):"0"(x));
166 return x;
167}
168#elif (defined(__powerpc__) || defined(__ppc__))
170{
171 int result;
172
173 __asm__("rlwimi %0,%2,8,16,23": "=&r"(result):"0"(x >> 8), "r"(x));
174 return (Uint16)result;
175}
176#elif (defined(__m68k__) && !defined(__mcoldfire__))
178{
179 __asm__("rorw #8,%0": "=d"(x): "0"(x):"cc");
180 return x;
181}
182#elif defined(__WATCOMC__) && defined(__386__)
183extern __inline Uint16 SDL_Swap16(Uint16);
184#pragma aux SDL_Swap16 = \
185 "xchg al, ah" \
186 parm [ax] \
187 modify [ax];
188#else
190{
191 return SDL_static_cast(Uint16, ((x << 8) | (x >> 8)));
192}
193#endif
194
195/* Byte swap 32-bit integer. */
196#if HAS_BUILTIN_BSWAP32
197#define SDL_Swap32(x) __builtin_bswap32(x)
198#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
199#pragma intrinsic(_byteswap_ulong)
200#define SDL_Swap32(x) _byteswap_ulong(x)
201#elif defined(__i386__) && !HAS_BROKEN_BSWAP
203{
204 __asm__("bswap %0": "=r"(x):"0"(x));
205 return x;
206}
207#elif defined(__x86_64__)
209{
210 __asm__("bswapl %0": "=r"(x):"0"(x));
211 return x;
212}
213#elif (defined(__powerpc__) || defined(__ppc__))
215{
216 Uint32 result;
217
218 __asm__("rlwimi %0,%2,24,16,23": "=&r"(result): "0" (x>>24), "r"(x));
219 __asm__("rlwimi %0,%2,8,8,15" : "=&r"(result): "0" (result), "r"(x));
220 __asm__("rlwimi %0,%2,24,0,7" : "=&r"(result): "0" (result), "r"(x));
221 return result;
222}
223#elif (defined(__m68k__) && !defined(__mcoldfire__))
225{
226 __asm__("rorw #8,%0\n\tswap %0\n\trorw #8,%0": "=d"(x): "0"(x):"cc");
227 return x;
228}
229#elif defined(__WATCOMC__) && defined(__386__)
230extern __inline Uint32 SDL_Swap32(Uint32);
231#pragma aux SDL_Swap32 = \
232 "bswap eax" \
233 parm [eax] \
234 modify [eax];
235#else
237{
238 return SDL_static_cast(Uint32, ((x << 24) | ((x << 8) & 0x00FF0000) |
239 ((x >> 8) & 0x0000FF00) | (x >> 24)));
240}
241#endif
242
243/* Byte swap 64-bit integer. */
244#if HAS_BUILTIN_BSWAP64
245#define SDL_Swap64(x) __builtin_bswap64(x)
246#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
247#pragma intrinsic(_byteswap_uint64)
248#define SDL_Swap64(x) _byteswap_uint64(x)
249#elif defined(__i386__) && !HAS_BROKEN_BSWAP
251{
252 union {
253 struct {
254 Uint32 a, b;
255 } s;
256 Uint64 u;
257 } v;
258 v.u = x;
259 __asm__("bswapl %0 ; bswapl %1 ; xchgl %0,%1"
260 : "=r"(v.s.a), "=r"(v.s.b)
261 : "0" (v.s.a), "1"(v.s.b));
262 return v.u;
263}
264#elif defined(__x86_64__)
266{
267 __asm__("bswapq %0": "=r"(x):"0"(x));
268 return x;
269}
270#elif defined(__WATCOMC__) && defined(__386__)
271extern __inline Uint64 SDL_Swap64(Uint64);
272#pragma aux SDL_Swap64 = \
273 "bswap eax" \
274 "bswap edx" \
275 "xchg eax,edx" \
276 parm [eax edx] \
277 modify [eax edx];
278#else
280{
281 Uint32 hi, lo;
282
283 /* Separate into high and low 32-bit values and swap them */
284 lo = SDL_static_cast(Uint32, x & 0xFFFFFFFF);
285 x >>= 32;
286 hi = SDL_static_cast(Uint32, x & 0xFFFFFFFF);
287 x = SDL_Swap32(lo);
288 x <<= 32;
289 x |= SDL_Swap32(hi);
290 return (x);
291}
292#endif
293
294
295/**
296 * Byte-swap a floating point number.
297 *
298 * This will always byte-swap the value, whether it's currently in the native
299 * byteorder of the system or not. You should use SDL_SwapFloatLE or
300 * SDL_SwapFloatBE instead, in most cases.
301 *
302 * Note that this is a forced-inline function in a header, and not a public
303 * API function available in the SDL library (which is to say, the code is
304 * embedded in the calling program and the linker and dynamic loader will not
305 * be able to find this function inside SDL itself).
306 *
307 * \param x the value to byte-swap.
308 * \returns x, with its bytes in the opposite endian order.
309 *
310 * \threadsafety It is safe to call this function from any thread.
311 *
312 * \since This function is available since SDL 3.0.0.
313 */
315{
316 union {
317 float f;
318 Uint32 ui32;
319 } swapper;
320 swapper.f = x;
321 swapper.ui32 = SDL_Swap32(swapper.ui32);
322 return swapper.f;
323}
324
325/* remove extra macros */
326#undef HAS_BROKEN_BSWAP
327#undef HAS_BUILTIN_BSWAP16
328#undef HAS_BUILTIN_BSWAP32
329#undef HAS_BUILTIN_BSWAP64
330
331
332#ifdef SDL_WIKI_DOCUMENTATION_SECTION
333
334/**
335 * Byte-swap an unsigned 16-bit number.
336 *
337 * This will always byte-swap the value, whether it's currently in the native
338 * byteorder of the system or not. You should use SDL_Swap16LE or SDL_Swap16BE
339 * instead, in most cases.
340 *
341 * Note that this is a forced-inline function in a header, and not a public
342 * API function available in the SDL library (which is to say, the code is
343 * embedded in the calling program and the linker and dynamic loader will not
344 * be able to find this function inside SDL itself).
345 *
346 * \param x the value to byte-swap.
347 * \returns `x`, with its bytes in the opposite endian order.
348 *
349 * \threadsafety It is safe to call this function from any thread.
350 *
351 * \since This function is available since SDL 3.0.0.
352 */
353SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x) { return x_but_byteswapped; }
354
355/**
356 * Byte-swap an unsigned 32-bit number.
357 *
358 * This will always byte-swap the value, whether it's currently in the native
359 * byteorder of the system or not. You should use SDL_Swap32LE or SDL_Swap32BE
360 * instead, in most cases.
361 *
362 * Note that this is a forced-inline function in a header, and not a public
363 * API function available in the SDL library (which is to say, the code is
364 * embedded in the calling program and the linker and dynamic loader will not
365 * be able to find this function inside SDL itself).
366 *
367 * \param x the value to byte-swap.
368 * \returns `x`, with its bytes in the opposite endian order.
369 *
370 * \threadsafety It is safe to call this function from any thread.
371 *
372 * \since This function is available since SDL 3.0.0.
373 */
374SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x) { return x_but_byteswapped; }
375
376/**
377 * Byte-swap an unsigned 64-bit number.
378 *
379 * This will always byte-swap the value, whether it's currently in the native
380 * byteorder of the system or not. You should use SDL_Swap64LE or SDL_Swap64BE
381 * instead, in most cases.
382 *
383 * Note that this is a forced-inline function in a header, and not a public
384 * API function available in the SDL library (which is to say, the code is
385 * embedded in the calling program and the linker and dynamic loader will not
386 * be able to find this function inside SDL itself).
387 *
388 * \param x the value to byte-swap.
389 * \returns `x`, with its bytes in the opposite endian order.
390 *
391 * \threadsafety It is safe to call this function from any thread.
392 *
393 * \since This function is available since SDL 3.0.0.
394 */
395SDL_FORCE_INLINE Uint32 SDL_Swap64(Uint64 x) { return x_but_byteswapped; }
396
397/**
398 * Swap a 16-bit value from littleendian to native byte order.
399 *
400 * If this is running on a littleendian system, `x` is returned unchanged.
401 *
402 * This macro never references `x` more than once, avoiding side effects.
403 *
404 * \param x the value to swap, in littleendian byte order.
405 * \returns `x` in native byte order.
406 *
407 * \since This macro is available since SDL 3.0.0.
408 */
409#define SDL_Swap16LE(x) SwapOnlyIfNecessary(x)
410
411/**
412 * Swap a 32-bit value from littleendian to native byte order.
413 *
414 * If this is running on a littleendian system, `x` is returned unchanged.
415 *
416 * This macro never references `x` more than once, avoiding side effects.
417 *
418 * \param x the value to swap, in littleendian byte order.
419 * \returns `x` in native byte order.
420 *
421 * \since This macro is available since SDL 3.0.0.
422 */
423#define SDL_Swap32LE(x) SwapOnlyIfNecessary(x)
424
425/**
426 * Swap a 64-bit value from littleendian to native byte order.
427 *
428 * If this is running on a littleendian system, `x` is returned unchanged.
429 *
430 * This macro never references `x` more than once, avoiding side effects.
431 *
432 * \param x the value to swap, in littleendian byte order.
433 * \returns `x` in native byte order.
434 *
435 * \since This macro is available since SDL 3.0.0.
436 */
437#define SDL_Swap64LE(x) SwapOnlyIfNecessary(x)
438
439/**
440 * Swap a floating point value from littleendian to native byte order.
441 *
442 * If this is running on a littleendian system, `x` is returned unchanged.
443 *
444 * This macro never references `x` more than once, avoiding side effects.
445 *
446 * \param x the value to swap, in littleendian byte order.
447 * \returns `x` in native byte order.
448 *
449 * \since This macro is available since SDL 3.0.0.
450 */
451#define SDL_SwapFloatLE(x) SwapOnlyIfNecessary(x)
452
453/**
454 * Swap a 16-bit value from bigendian to native byte order.
455 *
456 * If this is running on a bigendian system, `x` is returned unchanged.
457 *
458 * This macro never references `x` more than once, avoiding side effects.
459 *
460 * \param x the value to swap, in bigendian byte order.
461 * \returns `x` in native byte order.
462 *
463 * \since This macro is available since SDL 3.0.0.
464 */
465#define SDL_Swap16BE(x) SwapOnlyIfNecessary(x)
466
467/**
468 * Swap a 32-bit value from bigendian to native byte order.
469 *
470 * If this is running on a bigendian system, `x` is returned unchanged.
471 *
472 * This macro never references `x` more than once, avoiding side effects.
473 *
474 * \param x the value to swap, in bigendian byte order.
475 * \returns `x` in native byte order.
476 *
477 * \since This macro is available since SDL 3.0.0.
478 */
479#define SDL_Swap32BE(x) SwapOnlyIfNecessary(x)
480
481/**
482 * Swap a 64-bit value from bigendian to native byte order.
483 *
484 * If this is running on a bigendian system, `x` is returned unchanged.
485 *
486 * This macro never references `x` more than once, avoiding side effects.
487 *
488 * \param x the value to swap, in bigendian byte order.
489 * \returns `x` in native byte order.
490 *
491 * \since This macro is available since SDL 3.0.0.
492 */
493#define SDL_Swap64BE(x) SwapOnlyIfNecessary(x)
494
495/**
496 * Swap a floating point value from bigendian to native byte order.
497 *
498 * If this is running on a bigendian system, `x` is returned unchanged.
499 *
500 * This macro never references `x` more than once, avoiding side effects.
501 *
502 * \param x the value to swap, in bigendian byte order.
503 * \returns `x` in native byte order.
504 *
505 * \since This macro is available since SDL 3.0.0.
506 */
507#define SDL_SwapFloatBE(x) SwapOnlyIfNecessary(x)
508
509#elif SDL_BYTEORDER == SDL_LIL_ENDIAN
510#define SDL_Swap16LE(x) (x)
511#define SDL_Swap32LE(x) (x)
512#define SDL_Swap64LE(x) (x)
513#define SDL_SwapFloatLE(x) (x)
514#define SDL_Swap16BE(x) SDL_Swap16(x)
515#define SDL_Swap32BE(x) SDL_Swap32(x)
516#define SDL_Swap64BE(x) SDL_Swap64(x)
517#define SDL_SwapFloatBE(x) SDL_SwapFloat(x)
518#else
519#define SDL_Swap16LE(x) SDL_Swap16(x)
520#define SDL_Swap32LE(x) SDL_Swap32(x)
521#define SDL_Swap64LE(x) SDL_Swap64(x)
522#define SDL_SwapFloatLE(x) SDL_SwapFloat(x)
523#define SDL_Swap16BE(x) (x)
524#define SDL_Swap32BE(x) (x)
525#define SDL_Swap64BE(x) (x)
526#define SDL_SwapFloatBE(x) (x)
527#endif
528
529/* Ends C function definitions when using C++ */
530#ifdef __cplusplus
531}
532#endif
533#include <SDL3/SDL_close_code.h>
534
535#endif /* SDL_endian_h_ */
#define __inline__
#define SDL_FORCE_INLINE
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
Definition SDL_endian.h:236
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
Definition SDL_endian.h:189
SDL_FORCE_INLINE float SDL_SwapFloat(float x)
Definition SDL_endian.h:314
SDL_FORCE_INLINE Uint64 SDL_Swap64(Uint64 x)
Definition SDL_endian.h:279
uint16_t Uint16
Definition SDL_stdinc.h:250
#define SDL_static_cast(type, expression)
Definition SDL_stdinc.h:131
uint64_t Uint64
Definition SDL_stdinc.h:290
uint32_t Uint32
Definition SDL_stdinc.h:268