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-2019, 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 |
42 | pg_bswap16(uint16 x) |
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 |
64 | pg_bswap32(uint32 x) |
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 | #ifdef WORDS_BIGENDIAN |
144 | #define DatumBigEndianToNative(x) (x) |
145 | #else /* !WORDS_BIGENDIAN */ |
146 | #if SIZEOF_DATUM == 8 |
147 | #define DatumBigEndianToNative(x) pg_bswap64(x) |
148 | #else /* SIZEOF_DATUM != 8 */ |
149 | #define DatumBigEndianToNative(x) pg_bswap32(x) |
150 | #endif /* SIZEOF_DATUM == 8 */ |
151 | #endif /* WORDS_BIGENDIAN */ |
152 | |
153 | #endif /* PG_BSWAP_H */ |
154 | |