mhd_bithelpers.h (16542B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2019-2023 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 20 /** 21 * @file microhttpd/mhd_bithelpers.h 22 * @brief macros for bits manipulations 23 * @author Karlson2k (Evgeny Grin) 24 */ 25 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 # define _MHD_has_builtin_dummy 1 46 #endif 47 48 MHD_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE_ 49 50 #ifdef MHD_HAVE___BUILTIN_BSWAP32 51 #define _MHD_BYTES_SWAP32(value32) \ 52 ((uint32_t) __builtin_bswap32 ((uint32_t) value32)) 53 #elif defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \ 54 defined(__OPTIMIZE__))) 55 /* Clang/C2 may not inline this function if optimizations are turned off. */ 56 #ifndef __clang__ 57 #pragma intrinsic(_byteswap_ulong) 58 #endif /* ! __clang__ */ 59 #define _MHD_BYTES_SWAP32(value32) \ 60 ((uint32_t) _byteswap_ulong ((uint32_t) value32)) 61 #elif \ 62 __has_builtin (__builtin_bswap32) 63 #define _MHD_BYTES_SWAP32(value32) \ 64 ((uint32_t) __builtin_bswap32 ((uint32_t) value32)) 65 #else /* ! __has_builtin(__builtin_bswap32) */ 66 #define _MHD_BYTES_SWAP32(value32) \ 67 ( (((uint32_t) (value32)) << 24) \ 68 | ((((uint32_t) (value32)) & ((uint32_t) 0x0000FF00)) << 8) \ 69 | ((((uint32_t) (value32)) & ((uint32_t) 0x00FF0000)) >> 8) \ 70 | (((uint32_t) (value32)) >> 24) ) 71 #endif /* ! __has_builtin(__builtin_bswap32) */ 72 73 #ifdef MHD_HAVE___BUILTIN_BSWAP64 74 #define _MHD_BYTES_SWAP64(value64) \ 75 ((uint64_t) __builtin_bswap64 ((uint64_t) value64)) 76 #elif defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \ 77 defined(__OPTIMIZE__))) 78 /* Clang/C2 may not inline this function if optimizations are turned off. */ 79 #ifndef __clang__ 80 #pragma intrinsic(_byteswap_uint64) 81 #endif /* ! __clang__ */ 82 #define _MHD_BYTES_SWAP64(value64) \ 83 ((uint64_t) _byteswap_uint64 ((uint64_t) value64)) 84 #elif \ 85 __has_builtin (__builtin_bswap64) 86 #define _MHD_BYTES_SWAP64(value64) \ 87 ((uint64_t) __builtin_bswap64 ((uint64_t) value64)) 88 #else /* ! __has_builtin(__builtin_bswap64) */ 89 #define _MHD_BYTES_SWAP64(value64) \ 90 ( (((uint64_t) (value64)) << 56) \ 91 | ((((uint64_t) (value64)) & ((uint64_t) 0x000000000000FF00)) << 40) \ 92 | ((((uint64_t) (value64)) & ((uint64_t) 0x0000000000FF0000)) << 24) \ 93 | ((((uint64_t) (value64)) & ((uint64_t) 0x00000000FF000000)) << 8) \ 94 | ((((uint64_t) (value64)) & ((uint64_t) 0x000000FF00000000)) >> 8) \ 95 | ((((uint64_t) (value64)) & ((uint64_t) 0x0000FF0000000000)) >> 24) \ 96 | ((((uint64_t) (value64)) & ((uint64_t) 0x00FF000000000000)) >> 40) \ 97 | (((uint64_t) (value64)) >> 56) ) 98 #endif /* ! __has_builtin(__builtin_bswap64) */ 99 100 101 /* _MHD_PUT_64BIT_LE (addr, value64) 102 * put native-endian 64-bit value64 to addr 103 * in little-endian mode. 104 */ 105 /* Slow version that works with unaligned addr and with any bytes order */ 106 #define _MHD_PUT_64BIT_LE_SLOW(addr, value64) do { \ 107 ((uint8_t*) (addr))[0] = (uint8_t) ((uint64_t) (value64)); \ 108 ((uint8_t*) (addr))[1] = (uint8_t) (((uint64_t) (value64)) >> 8); \ 109 ((uint8_t*) (addr))[2] = (uint8_t) (((uint64_t) (value64)) >> 16); \ 110 ((uint8_t*) (addr))[3] = (uint8_t) (((uint64_t) (value64)) >> 24); \ 111 ((uint8_t*) (addr))[4] = (uint8_t) (((uint64_t) (value64)) >> 32); \ 112 ((uint8_t*) (addr))[5] = (uint8_t) (((uint64_t) (value64)) >> 40); \ 113 ((uint8_t*) (addr))[6] = (uint8_t) (((uint64_t) (value64)) >> 48); \ 114 ((uint8_t*) (addr))[7] = (uint8_t) (((uint64_t) (value64)) >> 56); \ 115 } while (0) 116 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN 117 #define _MHD_PUT_64BIT_LE(addr, value64) \ 118 ((*(uint64_t*) (addr)) = (uint64_t) (value64)) 119 #elif _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN 120 #define _MHD_PUT_64BIT_LE(addr, value64) \ 121 ((*(uint64_t*) (addr)) = _MHD_BYTES_SWAP64 (value64)) 122 #else /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */ 123 /* Endianness was not detected or non-standard like PDP-endian */ 124 #define _MHD_PUT_64BIT_LE(addr, value64) do { \ 125 ((uint8_t*) (addr))[0] = (uint8_t) ((uint64_t) (value64)); \ 126 ((uint8_t*) (addr))[1] = (uint8_t) (((uint64_t) (value64)) >> 8); \ 127 ((uint8_t*) (addr))[2] = (uint8_t) (((uint64_t) (value64)) >> 16); \ 128 ((uint8_t*) (addr))[3] = (uint8_t) (((uint64_t) (value64)) >> 24); \ 129 ((uint8_t*) (addr))[4] = (uint8_t) (((uint64_t) (value64)) >> 32); \ 130 ((uint8_t*) (addr))[5] = (uint8_t) (((uint64_t) (value64)) >> 40); \ 131 ((uint8_t*) (addr))[6] = (uint8_t) (((uint64_t) (value64)) >> 48); \ 132 ((uint8_t*) (addr))[7] = (uint8_t) (((uint64_t) (value64)) >> 56); \ 133 } while (0) 134 /* Indicate that _MHD_PUT_64BIT_LE does not need aligned pointer */ 135 #define _MHD_PUT_64BIT_LE_UNALIGNED 1 136 #endif /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */ 137 138 /* Put result safely to unaligned address */ 139 _MHD_static_inline void 140 _MHD_PUT_64BIT_LE_SAFE (void *dst, uint64_t value) 141 { 142 #ifndef _MHD_PUT_64BIT_LE_UNALIGNED 143 if (0 != ((uintptr_t) dst) % (_MHD_UINT64_ALIGN)) 144 _MHD_PUT_64BIT_LE_SLOW (dst, value); 145 else 146 #endif /* ! _MHD_PUT_64BIT_LE_UNALIGNED */ 147 _MHD_PUT_64BIT_LE (dst, value); 148 } 149 150 151 /* _MHD_PUT_32BIT_LE (addr, value32) 152 * put native-endian 32-bit value32 to addr 153 * in little-endian mode. 154 */ 155 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN 156 #define _MHD_PUT_32BIT_LE(addr,value32) \ 157 ((*(uint32_t*) (addr)) = (uint32_t) (value32)) 158 #elif _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN 159 #define _MHD_PUT_32BIT_LE(addr, value32) \ 160 ((*(uint32_t*) (addr)) = _MHD_BYTES_SWAP32 (value32)) 161 #else /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */ 162 /* Endianness was not detected or non-standard like PDP-endian */ 163 #define _MHD_PUT_32BIT_LE(addr, value32) do { \ 164 ((uint8_t*) (addr))[0] = (uint8_t) ((uint32_t) (value32)); \ 165 ((uint8_t*) (addr))[1] = (uint8_t) (((uint32_t) (value32)) >> 8); \ 166 ((uint8_t*) (addr))[2] = (uint8_t) (((uint32_t) (value32)) >> 16); \ 167 ((uint8_t*) (addr))[3] = (uint8_t) (((uint32_t) (value32)) >> 24); \ 168 } while (0) 169 /* Indicate that _MHD_PUT_32BIT_LE does not need aligned pointer */ 170 #define _MHD_PUT_32BIT_LE_UNALIGNED 1 171 #endif /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */ 172 173 /* _MHD_GET_32BIT_LE (addr) 174 * get little-endian 32-bit value storied at addr 175 * and return it in native-endian mode. 176 */ 177 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN 178 #define _MHD_GET_32BIT_LE(addr) \ 179 (*(const uint32_t*) (addr)) 180 #elif _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN 181 #define _MHD_GET_32BIT_LE(addr) \ 182 _MHD_BYTES_SWAP32 (*(const uint32_t*) (addr)) 183 #else /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */ 184 /* Endianness was not detected or non-standard like PDP-endian */ 185 #define _MHD_GET_32BIT_LE(addr) \ 186 ( ( (uint32_t) (((const uint8_t*) addr)[0])) \ 187 | (((uint32_t) (((const uint8_t*) addr)[1])) << 8) \ 188 | (((uint32_t) (((const uint8_t*) addr)[2])) << 16) \ 189 | (((uint32_t) (((const uint8_t*) addr)[3])) << 24) ) 190 /* Indicate that _MHD_GET_32BIT_LE does not need aligned pointer */ 191 #define _MHD_GET_32BIT_LE_UNALIGNED 1 192 #endif /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */ 193 194 195 /* _MHD_PUT_64BIT_BE (addr, value64) 196 * put native-endian 64-bit value64 to addr 197 * in big-endian mode. 198 */ 199 /* Slow version that works with unaligned addr and with any bytes order */ 200 #define _MHD_PUT_64BIT_BE_SLOW(addr, value64) do { \ 201 ((uint8_t*) (addr))[7] = (uint8_t) ((uint64_t) (value64)); \ 202 ((uint8_t*) (addr))[6] = (uint8_t) (((uint64_t) (value64)) >> 8); \ 203 ((uint8_t*) (addr))[5] = (uint8_t) (((uint64_t) (value64)) >> 16); \ 204 ((uint8_t*) (addr))[4] = (uint8_t) (((uint64_t) (value64)) >> 24); \ 205 ((uint8_t*) (addr))[3] = (uint8_t) (((uint64_t) (value64)) >> 32); \ 206 ((uint8_t*) (addr))[2] = (uint8_t) (((uint64_t) (value64)) >> 40); \ 207 ((uint8_t*) (addr))[1] = (uint8_t) (((uint64_t) (value64)) >> 48); \ 208 ((uint8_t*) (addr))[0] = (uint8_t) (((uint64_t) (value64)) >> 56); \ 209 } while (0) 210 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN 211 #define _MHD_PUT_64BIT_BE(addr, value64) \ 212 ((*(uint64_t*) (addr)) = (uint64_t) (value64)) 213 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN 214 #define _MHD_PUT_64BIT_BE(addr, value64) \ 215 ((*(uint64_t*) (addr)) = _MHD_BYTES_SWAP64 (value64)) 216 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */ 217 /* Endianness was not detected or non-standard like PDP-endian */ 218 #define _MHD_PUT_64BIT_BE(addr, value64) _MHD_PUT_64BIT_BE_SLOW(addr, value64) 219 /* Indicate that _MHD_PUT_64BIT_BE does not need aligned pointer */ 220 #define _MHD_PUT_64BIT_BE_UNALIGNED 1 221 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */ 222 223 /* Put result safely to unaligned address */ 224 _MHD_static_inline void 225 _MHD_PUT_64BIT_BE_SAFE (void *dst, uint64_t value) 226 { 227 #ifndef _MHD_PUT_64BIT_BE_UNALIGNED 228 if (0 != ((uintptr_t) dst) % (_MHD_UINT64_ALIGN)) 229 _MHD_PUT_64BIT_BE_SLOW (dst, value); 230 else 231 #endif /* ! _MHD_PUT_64BIT_BE_UNALIGNED */ 232 _MHD_PUT_64BIT_BE (dst, value); 233 } 234 235 236 /* _MHD_GET_64BIT_BE (addr) 237 * load 64-bit value located at addr in big endian mode. 238 */ 239 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN 240 #define _MHD_GET_64BIT_BE(addr) \ 241 (*(const uint64_t*) (addr)) 242 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN 243 #define _MHD_GET_64BIT_BE(addr) \ 244 _MHD_BYTES_SWAP64 (*(const uint64_t*) (addr)) 245 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */ 246 /* Endianness was not detected or non-standard like PDP-endian */ 247 #define _MHD_GET_64BIT_BE(addr) \ 248 ( (((uint64_t) (((const uint8_t*) addr)[0])) << 56) \ 249 | (((uint64_t) (((const uint8_t*) addr)[1])) << 48) \ 250 | (((uint64_t) (((const uint8_t*) addr)[2])) << 40) \ 251 | (((uint64_t) (((const uint8_t*) addr)[3])) << 32) \ 252 | (((uint64_t) (((const uint8_t*) addr)[4])) << 24) \ 253 | (((uint64_t) (((const uint8_t*) addr)[5])) << 16) \ 254 | (((uint64_t) (((const uint8_t*) addr)[6])) << 8) \ 255 | ((uint64_t) (((const uint8_t*) addr)[7])) ) 256 /* Indicate that _MHD_GET_64BIT_BE does not need aligned pointer */ 257 #define _MHD_GET_64BIT_BE_ALLOW_UNALIGNED 1 258 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */ 259 260 261 /* _MHD_PUT_32BIT_BE (addr, value32) 262 * put native-endian 32-bit value32 to addr 263 * in big-endian mode. 264 */ 265 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN 266 #define _MHD_PUT_32BIT_BE(addr, value32) \ 267 ((*(uint32_t*) (addr)) = (uint32_t) (value32)) 268 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN 269 #define _MHD_PUT_32BIT_BE(addr, value32) \ 270 ((*(uint32_t*) (addr)) = _MHD_BYTES_SWAP32 (value32)) 271 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */ 272 /* Endianness was not detected or non-standard like PDP-endian */ 273 #define _MHD_PUT_32BIT_BE(addr, value32) do { \ 274 ((uint8_t*) (addr))[3] = (uint8_t) ((uint32_t) (value32)); \ 275 ((uint8_t*) (addr))[2] = (uint8_t) (((uint32_t) (value32)) >> 8); \ 276 ((uint8_t*) (addr))[1] = (uint8_t) (((uint32_t) (value32)) >> 16); \ 277 ((uint8_t*) (addr))[0] = (uint8_t) (((uint32_t) (value32)) >> 24); \ 278 } while (0) 279 /* Indicate that _MHD_PUT_32BIT_BE does not need aligned pointer */ 280 #define _MHD_PUT_32BIT_BE_UNALIGNED 1 281 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */ 282 283 /* _MHD_GET_32BIT_BE (addr) 284 * get big-endian 32-bit value storied at addr 285 * and return it in native-endian mode. 286 */ 287 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN 288 #define _MHD_GET_32BIT_BE(addr) \ 289 (*(const uint32_t*) (addr)) 290 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN 291 #define _MHD_GET_32BIT_BE(addr) \ 292 _MHD_BYTES_SWAP32 (*(const uint32_t*) (addr)) 293 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */ 294 /* Endianness was not detected or non-standard like PDP-endian */ 295 #define _MHD_GET_32BIT_BE(addr) \ 296 ( (((uint32_t) (((const uint8_t*) addr)[0])) << 24) \ 297 | (((uint32_t) (((const uint8_t*) addr)[1])) << 16) \ 298 | (((uint32_t) (((const uint8_t*) addr)[2])) << 8) \ 299 | ((uint32_t) (((const uint8_t*) addr)[3])) ) 300 /* Indicate that _MHD_GET_32BIT_BE does not need aligned pointer */ 301 #define _MHD_GET_32BIT_BE_UNALIGNED 1 302 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */ 303 304 305 /** 306 * Rotate right 32-bit value by number of bits. 307 * bits parameter must be more than zero and must be less than 32. 308 */ 309 #if defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \ 310 defined(__OPTIMIZE__))) 311 /* Clang/C2 do not inline this function if optimizations are turned off. */ 312 #ifndef __clang__ 313 #pragma intrinsic(_rotr) 314 #endif /* ! __clang__ */ 315 #define _MHD_ROTR32(value32, bits) \ 316 ((uint32_t) _rotr ((uint32_t) (value32),(bits))) 317 #elif __has_builtin (__builtin_rotateright32) 318 #define _MHD_ROTR32(value32, bits) \ 319 ((uint32_t) __builtin_rotateright32 ((value32), (bits))) 320 #else /* ! __builtin_rotateright32 */ 321 _MHD_static_inline uint32_t 322 _MHD_ROTR32 (uint32_t value32, int bits) 323 { 324 bits %= 32; 325 if (0 == bits) 326 return value32; 327 /* Defined in form which modern compiler could optimize. */ 328 return (value32 >> bits) | (value32 << (32 - bits)); 329 } 330 331 332 #endif /* ! __builtin_rotateright32 */ 333 334 335 /** 336 * Rotate left 32-bit value by number of bits. 337 * bits parameter must be more than zero and must be less than 32. 338 */ 339 #if defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \ 340 defined(__OPTIMIZE__))) 341 /* Clang/C2 do not inline this function if optimizations are turned off. */ 342 #ifndef __clang__ 343 #pragma intrinsic(_rotl) 344 #endif /* ! __clang__ */ 345 #define _MHD_ROTL32(value32, bits) \ 346 ((uint32_t) _rotl ((uint32_t) (value32),(bits))) 347 #elif __has_builtin (__builtin_rotateleft32) 348 #define _MHD_ROTL32(value32, bits) \ 349 ((uint32_t) __builtin_rotateleft32 ((value32), (bits))) 350 #else /* ! __builtin_rotateleft32 */ 351 _MHD_static_inline uint32_t 352 _MHD_ROTL32 (uint32_t value32, int bits) 353 { 354 bits %= 32; 355 if (0 == bits) 356 return value32; 357 /* Defined in form which modern compiler could optimize. */ 358 return (value32 << bits) | (value32 >> (32 - bits)); 359 } 360 361 362 #endif /* ! __builtin_rotateleft32 */ 363 364 365 /** 366 * Rotate right 64-bit value by number of bits. 367 * bits parameter must be more than zero and must be less than 64. 368 */ 369 #if defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \ 370 defined(__OPTIMIZE__))) 371 /* Clang/C2 do not inline this function if optimisations are turned off. */ 372 #ifndef __clang__ 373 #pragma intrinsic(_rotr64) 374 #endif /* ! __clang__ */ 375 #define _MHD_ROTR64(value64, bits) \ 376 ((uint64_t) _rotr64 ((uint64_t) (value64),(bits))) 377 #elif __has_builtin (__builtin_rotateright64) 378 #define _MHD_ROTR64(value64, bits) \ 379 ((uint64_t) __builtin_rotateright64 ((value64), (bits))) 380 #else /* ! __builtin_rotateright64 */ 381 _MHD_static_inline uint64_t 382 _MHD_ROTR64 (uint64_t value64, int bits) 383 { 384 bits %= 64; 385 if (0 == bits) 386 return value64; 387 /* Defined in form which modern compiler could optimise. */ 388 return (value64 >> bits) | (value64 << (64 - bits)); 389 } 390 391 392 #endif /* ! __builtin_rotateright64 */ 393 394 MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_ 395 396 #ifdef _MHD_has_builtin_dummy 397 /* Remove macro function replacement to avoid misdetection in files which 398 * include this header */ 399 # undef __has_builtin 400 #endif 401 402 #endif /* ! MHD_BITHELPERS_H */