GNU libmicrohttpd  0.9.75
mhd_bithelpers.h
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2019-2021 Karlson2k (Evgeny Grin)
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library.
17  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
26 #ifndef MHD_BITHELPERS_H
27 #define MHD_BITHELPERS_H 1
28 
29 #include "mhd_options.h"
30 #include <stdint.h>
31 #if defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
32  defined(__OPTIMIZE__)))
33 /* Declarations for VC & Clang/C2 built-ins */
34 #include <intrin.h>
35 #endif /* _MSC_FULL_VER */
36 #include "mhd_byteorder.h"
37 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN || _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
38 #include "mhd_align.h"
39 #endif /* _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN ||
40  _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN */
41 
42 #ifndef __has_builtin
43 /* Avoid precompiler errors with non-clang */
44 # define __has_builtin(x) 0
45 #endif
46 
47 
48 #ifdef MHD_HAVE___BUILTIN_BSWAP32
49 #define _MHD_BYTES_SWAP32(value32) \
50  ((uint32_t) __builtin_bswap32 ((uint32_t) value32))
51 #elif defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
52  defined(__OPTIMIZE__)))
53 /* Clang/C2 may not inline this function if optimizations are turned off. */
54 #ifndef __clang__
55 #pragma intrinsic(_byteswap_ulong)
56 #endif /* ! __clang__ */
57 #define _MHD_BYTES_SWAP32(value32) \
58  ((uint32_t) _byteswap_ulong ((uint32_t) value32))
59 #elif __has_builtin (__builtin_bswap32)
60 #define _MHD_BYTES_SWAP32(value32) \
61  ((uint32_t) __builtin_bswap32 ((uint32_t) value32))
62 #else /* ! __has_builtin(__builtin_bswap32) */
63 #define _MHD_BYTES_SWAP32(value32) \
64  ( (((uint32_t) (value32)) << 24) \
65  | ((((uint32_t) (value32)) & ((uint32_t) 0x0000FF00)) << 8) \
66  | ((((uint32_t) (value32)) & ((uint32_t) 0x00FF0000)) >> 8) \
67  | (((uint32_t) (value32)) >> 24) )
68 #endif /* ! __has_builtin(__builtin_bswap32) */
69 
70 #ifdef MHD_HAVE___BUILTIN_BSWAP64
71 #define _MHD_BYTES_SWAP64(value64) \
72  ((uint64_t) __builtin_bswap64 ((uint64_t) value64))
73 #elif defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
74  defined(__OPTIMIZE__)))
75 /* Clang/C2 may not inline this function if optimizations are turned off. */
76 #ifndef __clang__
77 #pragma intrinsic(_byteswap_uint64)
78 #endif /* ! __clang__ */
79 #define _MHD_BYTES_SWAP64(value64) \
80  ((uint64_t) _byteswap_uint64 ((uint64_t) value64))
81 #elif __has_builtin (__builtin_bswap64)
82 #define _MHD_BYTES_SWAP64(value64) \
83  ((uint64_t) __builtin_bswap64 ((uint64_t) value64))
84 #else /* ! __has_builtin(__builtin_bswap64) */
85 #define _MHD_BYTES_SWAP64(value64) \
86  ( (((uint64_t) (value64)) << 56) \
87  | ((((uint64_t) (value64)) & ((uint64_t) 0x000000000000FF00)) << 40) \
88  | ((((uint64_t) (value64)) & ((uint64_t) 0x0000000000FF0000)) << 24) \
89  | ((((uint64_t) (value64)) & ((uint64_t) 0x00000000FF000000)) << 8) \
90  | ((((uint64_t) (value64)) & ((uint64_t) 0x000000FF00000000)) >> 8) \
91  | ((((uint64_t) (value64)) & ((uint64_t) 0x0000FF0000000000)) >> 24) \
92  | ((((uint64_t) (value64)) & ((uint64_t) 0x00FF000000000000)) >> 40) \
93  | (((uint64_t) (value64)) >> 56) )
94 #endif /* ! __has_builtin(__builtin_bswap64) */
95 
96 
97 /* _MHD_PUT_64BIT_LE (addr, value64)
98  * put native-endian 64-bit value64 to addr
99  * in little-endian mode.
100  */
101 /* Slow version that works with unaligned addr and with any bytes order */
102 #define _MHD_PUT_64BIT_LE_SLOW(addr, value64) do { \
103  ((uint8_t*) (addr))[0] = (uint8_t) ((uint64_t) (value64)); \
104  ((uint8_t*) (addr))[1] = (uint8_t) (((uint64_t) (value64)) >> 8); \
105  ((uint8_t*) (addr))[2] = (uint8_t) (((uint64_t) (value64)) >> 16); \
106  ((uint8_t*) (addr))[3] = (uint8_t) (((uint64_t) (value64)) >> 24); \
107  ((uint8_t*) (addr))[4] = (uint8_t) (((uint64_t) (value64)) >> 32); \
108  ((uint8_t*) (addr))[5] = (uint8_t) (((uint64_t) (value64)) >> 40); \
109  ((uint8_t*) (addr))[6] = (uint8_t) (((uint64_t) (value64)) >> 48); \
110  ((uint8_t*) (addr))[7] = (uint8_t) (((uint64_t) (value64)) >> 56); \
111 } while (0)
112 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
113 #define _MHD_PUT_64BIT_LE(addr, value64) \
114  ((*(uint64_t*) (addr)) = (uint64_t) (value64))
115 #elif _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
116 #define _MHD_PUT_64BIT_LE(addr, value64) \
117  ((*(uint64_t*) (addr)) = _MHD_BYTES_SWAP64 (value64))
118 #else /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
119 /* Endianness was not detected or non-standard like PDP-endian */
120 #define _MHD_PUT_64BIT_LE(addr, value64) do { \
121  ((uint8_t*) (addr))[0] = (uint8_t) ((uint64_t) (value64)); \
122  ((uint8_t*) (addr))[1] = (uint8_t) (((uint64_t) (value64)) >> 8); \
123  ((uint8_t*) (addr))[2] = (uint8_t) (((uint64_t) (value64)) >> 16); \
124  ((uint8_t*) (addr))[3] = (uint8_t) (((uint64_t) (value64)) >> 24); \
125  ((uint8_t*) (addr))[4] = (uint8_t) (((uint64_t) (value64)) >> 32); \
126  ((uint8_t*) (addr))[5] = (uint8_t) (((uint64_t) (value64)) >> 40); \
127  ((uint8_t*) (addr))[6] = (uint8_t) (((uint64_t) (value64)) >> 48); \
128  ((uint8_t*) (addr))[7] = (uint8_t) (((uint64_t) (value64)) >> 56); \
129 } while (0)
130 /* Indicate that _MHD_PUT_64BIT_LE does not need aligned pointer */
131 #define _MHD_PUT_64BIT_LE_UNALIGNED 1
132 #endif /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
133 
134 /* Put result safely to unaligned address */
135 _MHD_static_inline void
136 _MHD_PUT_64BIT_LE_SAFE (void *dst, uint64_t value)
137 {
138 #ifndef _MHD_PUT_64BIT_LE_UNALIGNED
139  if (0 != ((uintptr_t) dst) % (_MHD_UINT64_ALIGN))
140  _MHD_PUT_64BIT_LE_SLOW (dst, value);
141  else
142 #endif /* ! _MHD_PUT_64BIT_BE_UNALIGNED */
143  _MHD_PUT_64BIT_LE (dst, value);
144 }
145 
146 
147 /* _MHD_PUT_32BIT_LE (addr, value32)
148  * put native-endian 32-bit value32 to addr
149  * in little-endian mode.
150  */
151 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
152 #define _MHD_PUT_32BIT_LE(addr,value32) \
153  ((*(uint32_t*) (addr)) = (uint32_t) (value32))
154 #elif _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
155 #define _MHD_PUT_32BIT_LE(addr, value32) \
156  ((*(uint32_t*) (addr)) = _MHD_BYTES_SWAP32 (value32))
157 #else /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
158 /* Endianness was not detected or non-standard like PDP-endian */
159 #define _MHD_PUT_32BIT_LE(addr, value32) do { \
160  ((uint8_t*) (addr))[0] = (uint8_t) ((uint32_t) (value32)); \
161  ((uint8_t*) (addr))[1] = (uint8_t) (((uint32_t) (value32)) >> 8); \
162  ((uint8_t*) (addr))[2] = (uint8_t) (((uint32_t) (value32)) >> 16); \
163  ((uint8_t*) (addr))[3] = (uint8_t) (((uint32_t) (value32)) >> 24); \
164 } while (0)
165 /* Indicate that _MHD_PUT_32BIT_LE does not need aligned pointer */
166 #define _MHD_PUT_32BIT_LE_UNALIGNED 1
167 #endif /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
168 
169 /* _MHD_GET_32BIT_LE (addr)
170  * get little-endian 32-bit value storied at addr
171  * and return it in native-endian mode.
172  */
173 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
174 #define _MHD_GET_32BIT_LE(addr) \
175  (*(const uint32_t*) (addr))
176 #elif _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
177 #define _MHD_GET_32BIT_LE(addr) \
178  _MHD_BYTES_SWAP32 (*(const uint32_t*) (addr))
179 #else /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
180 /* Endianness was not detected or non-standard like PDP-endian */
181 #define _MHD_GET_32BIT_LE(addr) \
182  ( ( (uint32_t) (((const uint8_t*) addr)[0])) \
183  | (((uint32_t) (((const uint8_t*) addr)[1])) << 8) \
184  | (((uint32_t) (((const uint8_t*) addr)[2])) << 16) \
185  | (((uint32_t) (((const uint8_t*) addr)[3])) << 24) )
186 /* Indicate that _MHD_GET_32BIT_LE does not need aligned pointer */
187 #define _MHD_GET_32BIT_LE_UNALIGNED 1
188 #endif /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
189 
190 
191 /* _MHD_PUT_64BIT_BE (addr, value64)
192  * put native-endian 64-bit value64 to addr
193  * in big-endian mode.
194  */
195 /* Slow version that works with unaligned addr and with any bytes order */
196 #define _MHD_PUT_64BIT_BE_SLOW(addr, value64) do { \
197  ((uint8_t*) (addr))[7] = (uint8_t) ((uint64_t) (value64)); \
198  ((uint8_t*) (addr))[6] = (uint8_t) (((uint64_t) (value64)) >> 8); \
199  ((uint8_t*) (addr))[5] = (uint8_t) (((uint64_t) (value64)) >> 16); \
200  ((uint8_t*) (addr))[4] = (uint8_t) (((uint64_t) (value64)) >> 24); \
201  ((uint8_t*) (addr))[3] = (uint8_t) (((uint64_t) (value64)) >> 32); \
202  ((uint8_t*) (addr))[2] = (uint8_t) (((uint64_t) (value64)) >> 40); \
203  ((uint8_t*) (addr))[1] = (uint8_t) (((uint64_t) (value64)) >> 48); \
204  ((uint8_t*) (addr))[0] = (uint8_t) (((uint64_t) (value64)) >> 56); \
205 } while (0)
206 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
207 #define _MHD_PUT_64BIT_BE(addr, value64) \
208  ((*(uint64_t*) (addr)) = (uint64_t) (value64))
209 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
210 #define _MHD_PUT_64BIT_BE(addr, value64) \
211  ((*(uint64_t*) (addr)) = _MHD_BYTES_SWAP64 (value64))
212 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
213 /* Endianness was not detected or non-standard like PDP-endian */
214 #define _MHD_PUT_64BIT_BE(addr, value64) _MHD_PUT_64BIT_BE_SLOW(addr, value64)
215 /* Indicate that _MHD_PUT_64BIT_BE does not need aligned pointer */
216 #define _MHD_PUT_64BIT_BE_UNALIGNED 1
217 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
218 
219 /* Put result safely to unaligned address */
220 _MHD_static_inline void
221 _MHD_PUT_64BIT_BE_SAFE (void *dst, uint64_t value)
222 {
223 #ifndef _MHD_PUT_64BIT_BE_UNALIGNED
224  if (0 != ((uintptr_t) dst) % (_MHD_UINT64_ALIGN))
225  _MHD_PUT_64BIT_BE_SLOW (dst, value);
226  else
227 #endif /* ! _MHD_PUT_64BIT_BE_UNALIGNED */
228  _MHD_PUT_64BIT_BE (dst, value);
229 }
230 
231 
232 /* _MHD_PUT_32BIT_BE (addr, value32)
233  * put native-endian 32-bit value32 to addr
234  * in big-endian mode.
235  */
236 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
237 #define _MHD_PUT_32BIT_BE(addr, value32) \
238  ((*(uint32_t*) (addr)) = (uint32_t) (value32))
239 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
240 #define _MHD_PUT_32BIT_BE(addr, value32) \
241  ((*(uint32_t*) (addr)) = _MHD_BYTES_SWAP32 (value32))
242 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
243 /* Endianness was not detected or non-standard like PDP-endian */
244 #define _MHD_PUT_32BIT_BE(addr, value32) do { \
245  ((uint8_t*) (addr))[3] = (uint8_t) ((uint32_t) (value32)); \
246  ((uint8_t*) (addr))[2] = (uint8_t) (((uint32_t) (value32)) >> 8); \
247  ((uint8_t*) (addr))[1] = (uint8_t) (((uint32_t) (value32)) >> 16); \
248  ((uint8_t*) (addr))[0] = (uint8_t) (((uint32_t) (value32)) >> 24); \
249 } while (0)
250 /* Indicate that _MHD_PUT_32BIT_BE does not need aligned pointer */
251 #define _MHD_PUT_32BIT_BE_UNALIGNED 1
252 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
253 
254 /* _MHD_GET_32BIT_BE (addr)
255  * get big-endian 32-bit value storied at addr
256  * and return it in native-endian mode.
257  */
258 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
259 #define _MHD_GET_32BIT_BE(addr) \
260  (*(const uint32_t*) (addr))
261 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
262 #define _MHD_GET_32BIT_BE(addr) \
263  _MHD_BYTES_SWAP32 (*(const uint32_t*) (addr))
264 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
265 /* Endianness was not detected or non-standard like PDP-endian */
266 #define _MHD_GET_32BIT_BE(addr) \
267  ( (((uint32_t) (((const uint8_t*) addr)[0])) << 24) \
268  | (((uint32_t) (((const uint8_t*) addr)[1])) << 16) \
269  | (((uint32_t) (((const uint8_t*) addr)[2])) << 8) \
270  | ((uint32_t) (((const uint8_t*) addr)[3])) )
271 /* Indicate that _MHD_GET_32BIT_BE does not need aligned pointer */
272 #define _MHD_GET_32BIT_BE_UNALIGNED 1
273 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
274 
275 
280 #if defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
281  defined(__OPTIMIZE__)))
282 /* Clang/C2 do not inline this function if optimizations are turned off. */
283 #ifndef __clang__
284 #pragma intrinsic(_rotr)
285 #endif /* ! __clang__ */
286 #define _MHD_ROTR32(value32, bits) \
287  ((uint32_t) _rotr ((uint32_t) (value32),(bits)))
288 #elif __has_builtin (__builtin_rotateright32)
289 #define _MHD_ROTR32(value32, bits) \
290  ((uint32_t) __builtin_rotateright32 ((value32), (bits)))
291 #else /* ! __builtin_rotateright32 */
292 _MHD_static_inline uint32_t
293 _MHD_ROTR32 (uint32_t value32, int bits)
294 {
295  bits %= 32;
296  /* Defined in form which modern compiler could optimize. */
297  return (value32 >> bits) | (value32 << (32 - bits));
298 }
299 
300 
301 #endif /* ! __builtin_rotateright32 */
302 
303 
308 #if defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
309  defined(__OPTIMIZE__)))
310 /* Clang/C2 do not inline this function if optimizations are turned off. */
311 #ifndef __clang__
312 #pragma intrinsic(_rotl)
313 #endif /* ! __clang__ */
314 #define _MHD_ROTL32(value32, bits) \
315  ((uint32_t) _rotl ((uint32_t) (value32),(bits)))
316 #elif __has_builtin (__builtin_rotateleft32)
317 #define _MHD_ROTL32(value32, bits) \
318  ((uint32_t) __builtin_rotateleft32 ((value32), (bits)))
319 #else /* ! __builtin_rotateleft32 */
320 _MHD_static_inline uint32_t
321 _MHD_ROTL32 (uint32_t value32, int bits)
322 {
323  bits %= 32;
324  /* Defined in form which modern compiler could optimize. */
325  return (value32 << bits) | (value32 >> (32 - bits));
326 }
327 
328 
329 #endif /* ! __builtin_rotateleft32 */
330 
331 
332 #endif /* ! MHD_BITHELPERS_H */
types alignment macros
#define _MHD_UINT64_ALIGN
Definition: mhd_align.h:93
#define _MHD_PUT_64BIT_BE(addr, value64)
#define _MHD_PUT_64BIT_LE_SLOW(addr, value64)
_MHD_static_inline uint32_t _MHD_ROTR32(uint32_t value32, int bits)
_MHD_static_inline void _MHD_PUT_64BIT_BE_SAFE(void *dst, uint64_t value)
#define _MHD_PUT_64BIT_LE(addr, value64)
#define _MHD_PUT_64BIT_BE_SLOW(addr, value64)
_MHD_static_inline uint32_t _MHD_ROTL32(uint32_t value32, int bits)
_MHD_static_inline void _MHD_PUT_64BIT_LE_SAFE(void *dst, uint64_t value)
additional automatic macros for MHD_config.h
macro definitions for host byte order