PostgreSQL Source Code  git master
pg_bswap.h
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_bswap.h
4  * Byte swapping.
5  *
6  * Macros for reversing the byte order of 16, 32 and 64-bit unsigned integers.
7  * For example, 0xAABBCCDD becomes 0xDDCCBBAA. These are just wrappers for
8  * built-in functions provided by the compiler where support exists.
9  *
10  * Note that all of these functions accept unsigned integers as arguments and
11  * return the same. Use caution when using these wrapper macros with signed
12  * integers.
13  *
14  * Copyright (c) 2015-2024, PostgreSQL Global Development Group
15  *
16  * src/include/port/pg_bswap.h
17  *
18  *-------------------------------------------------------------------------
19  */
20 #ifndef PG_BSWAP_H
21 #define PG_BSWAP_H
22 
23 
24 /*
25  * In all supported versions msvc provides _byteswap_* functions in stdlib.h,
26  * already included by c.h.
27  */
28 
29 
30 /* implementation of uint16 pg_bswap16(uint16) */
31 #if defined(HAVE__BUILTIN_BSWAP16)
32 
33 #define pg_bswap16(x) __builtin_bswap16(x)
34 
35 #elif defined(_MSC_VER)
36 
37 #define pg_bswap16(x) _byteswap_ushort(x)
38 
39 #else
40 
41 static inline uint16
43 {
44  return
45  ((x << 8) & 0xff00) |
46  ((x >> 8) & 0x00ff);
47 }
48 
49 #endif /* HAVE__BUILTIN_BSWAP16 */
50 
51 
52 /* implementation of uint32 pg_bswap32(uint32) */
53 #if defined(HAVE__BUILTIN_BSWAP32)
54 
55 #define pg_bswap32(x) __builtin_bswap32(x)
56 
57 #elif defined(_MSC_VER)
58 
59 #define pg_bswap32(x) _byteswap_ulong(x)
60 
61 #else
62 
63 static inline uint32
65 {
66  return
67  ((x << 24) & 0xff000000) |
68  ((x << 8) & 0x00ff0000) |
69  ((x >> 8) & 0x0000ff00) |
70  ((x >> 24) & 0x000000ff);
71 }
72 
73 #endif /* HAVE__BUILTIN_BSWAP32 */
74 
75 
76 /* implementation of uint64 pg_bswap64(uint64) */
77 #if defined(HAVE__BUILTIN_BSWAP64)
78 
79 #define pg_bswap64(x) __builtin_bswap64(x)
80 
81 
82 #elif defined(_MSC_VER)
83 
84 #define pg_bswap64(x) _byteswap_uint64(x)
85 
86 #else
87 
88 static inline uint64
89 pg_bswap64(uint64 x)
90 {
91  return
92  ((x << 56) & UINT64CONST(0xff00000000000000)) |
93  ((x << 40) & UINT64CONST(0x00ff000000000000)) |
94  ((x << 24) & UINT64CONST(0x0000ff0000000000)) |
95  ((x << 8) & UINT64CONST(0x000000ff00000000)) |
96  ((x >> 8) & UINT64CONST(0x00000000ff000000)) |
97  ((x >> 24) & UINT64CONST(0x0000000000ff0000)) |
98  ((x >> 40) & UINT64CONST(0x000000000000ff00)) |
99  ((x >> 56) & UINT64CONST(0x00000000000000ff));
100 }
101 #endif /* HAVE__BUILTIN_BSWAP64 */
102 
103 
104 /*
105  * Portable and fast equivalents for ntohs, ntohl, htons, htonl,
106  * additionally extended to 64 bits.
107  */
108 #ifdef WORDS_BIGENDIAN
109 
110 #define pg_hton16(x) (x)
111 #define pg_hton32(x) (x)
112 #define pg_hton64(x) (x)
113 
114 #define pg_ntoh16(x) (x)
115 #define pg_ntoh32(x) (x)
116 #define pg_ntoh64(x) (x)
117 
118 #else
119 
120 #define pg_hton16(x) pg_bswap16(x)
121 #define pg_hton32(x) pg_bswap32(x)
122 #define pg_hton64(x) pg_bswap64(x)
123 
124 #define pg_ntoh16(x) pg_bswap16(x)
125 #define pg_ntoh32(x) pg_bswap32(x)
126 #define pg_ntoh64(x) pg_bswap64(x)
127 
128 #endif /* WORDS_BIGENDIAN */
129 
130 
131 /*
132  * Rearrange the bytes of a Datum from big-endian order into the native byte
133  * order. On big-endian machines, this does nothing at all. Note that the C
134  * type Datum is an unsigned integer type on all platforms.
135  *
136  * One possible application of the DatumBigEndianToNative() macro is to make
137  * bitwise comparisons cheaper. A simple 3-way comparison of Datums
138  * transformed by the macro (based on native, unsigned comparisons) will return
139  * the same result as a memcmp() of the corresponding original Datums, but can
140  * be much cheaper. It's generally safe to do this on big-endian systems
141  * without any special transformation occurring first.
142  *
143  * If SIZEOF_DATUM is not defined, then postgres.h wasn't included and these
144  * macros probably shouldn't be used, so we define nothing. Note that
145  * SIZEOF_DATUM == 8 would evaluate as 0 == 8 in that case, potentially
146  * leading to the wrong implementation being selected and confusing errors, so
147  * defining nothing is safest.
148  */
149 #ifdef SIZEOF_DATUM
150 #ifdef WORDS_BIGENDIAN
151 #define DatumBigEndianToNative(x) (x)
152 #else /* !WORDS_BIGENDIAN */
153 #if SIZEOF_DATUM == 8
154 #define DatumBigEndianToNative(x) pg_bswap64(x)
155 #else /* SIZEOF_DATUM != 8 */
156 #define DatumBigEndianToNative(x) pg_bswap32(x)
157 #endif /* SIZEOF_DATUM == 8 */
158 #endif /* WORDS_BIGENDIAN */
159 #endif /* SIZEOF_DATUM */
160 
161 #endif /* PG_BSWAP_H */
unsigned short uint16
Definition: c.h:492
unsigned int uint32
Definition: c.h:493
int x
Definition: isn.c:71
static uint16 pg_bswap16(uint16 x)
Definition: pg_bswap.h:42
static uint64 pg_bswap64(uint64 x)
Definition: pg_bswap.h:89
static uint32 pg_bswap32(uint32 x)
Definition: pg_bswap.h:64