/* SPDX-FileCopyrightText: © 2022-2024 Decompollaborate */ /* SPDX-License-Identifier: MIT */ #ifndef RABBITIZER_UTILS_H #define RABBITIZER_UTILS_H #include #include #ifdef __cplusplus extern "C" { #endif #if !defined(__GNUC__) && !defined(__clang__) #define __attribute__(x) #endif #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L) || (defined(__cplusplus) && __cplusplus >= 201103L) #define CONST [[gnu::const]] #define DEPRECATED(reason) [[deprecated (reason)]] #define FALLTHROUGH [[fallthrough]] #define NODISCARD [[nodiscard]] #define NORETURN [[noreturn]] #define NON_NULL(...) [[gnu::nonnull (__VA_ARGS__)]] #define PURE [[gnu::pure]] #define RETURNS_NON_NULL [[gnu::returns_nonnull]] #define UNUSED [[maybe_unused]] #else #define CONST __attribute__((const)) #define DEPRECATED(reason) __attribute__((deprecated (reason))) #define FALLTHROUGH __attribute__((fallthrough)) #define NODISCARD __attribute__((warn_unused_result)) #define NORETURN _Noreturn #define NON_NULL(...) __attribute__((nonnull (__VA_ARGS__))) #define PURE __attribute__((pure)) #define RETURNS_NON_NULL __attribute__((returns_nonnull)) #define UNUSED __attribute__((unused)) #endif #if defined(_MSC_VER) # define UNREACHABLE __assume(0) #elif defined(__GNUC__) || defined(__clang__) # define UNREACHABLE __builtin_unreachable() #else # define UNREACHABLE #endif typedef enum RabTrinaryValue { RAB_TRINARY_VAL_NONE, RAB_TRINARY_VAL_FALSE, RAB_TRINARY_VAL_TRUE, } RabTrinaryValue; #define ARRAY_COUNT(arr) (sizeof(arr) / sizeof((arr)[0])) #define RAB_MAX(a, b) ((a) > (b) ? (a) : (b)) #define RAB_MIN(a, b) ((a) < (b) ? (a) : (b)) #define RAB_STRINGIFY2(x) #x #define RAB_STRINGIFY(x) RAB_STRINGIFY2(x) #define MASK(v, w) ((v) & ((1U << (w)) - 1U)) /* * the SHIFT macros take a value, a shift amount, and a width. * * For the left shift, the lower bits of the value are masked, * then shifted left. * * For the right shift, the value is shifted right, then the lower bits * are masked. * * (NOTE: SHIFTL(v, 0, 32) won't work, just use an assignment) * */ #define SHIFTL(v, s, w) (MASK((v), (w)) << (s)) #define SHIFTR(v, s, w) (MASK((v) >> (s), (w))) #define BITREPACK(fullword, v, s, w) ((SHIFTR((fullword), (s)+(w), 32U-((s)+(w))) << ((s)+(w))) | SHIFTL((v), (s), (w)) | MASK((fullword), (s))) #define BITREPACK_RIGHT(fullword, v, s, w) (SHIFTL((v), (s), (w)) | MASK((fullword), (s))) #define RABUTILS_BUFFER_ADVANCE(buffer, totalSize, expression) \ do { \ size_t __tempSize = (size_t)(expression); \ if ((buffer) != NULL) { \ (buffer) += __tempSize; \ } \ (totalSize) += __tempSize; \ } while (0) #define RABUTILS_BUFFER_WRITE_CHAR(buffer, totalSize, character) \ do { \ if ((buffer) != NULL) { \ *(buffer) = (character); \ } \ RABUTILS_BUFFER_ADVANCE(buffer, totalSize, 1); \ } while (0) #define RABUTILS_BUFFER_SPRINTF(buffer, totalSize, format, ...) \ do { \ int _len; \ if (buffer != NULL) { \ _len = sprintf(buffer, format, __VA_ARGS__); \ } else { \ _len = snprintf(NULL, 0, format, __VA_ARGS__); \ } \ assert(_len > 0); \ RABUTILS_BUFFER_ADVANCE(buffer, totalSize, _len); \ } while (0) #define RABUTILS_BUFFER_CPY(buffer, totalSize, string) \ do { \ size_t _tempSize = strlen(string); \ if ((buffer) != NULL) { \ memcpy(buffer, string, _tempSize); \ } \ RABUTILS_BUFFER_ADVANCE(buffer, totalSize, _tempSize); \ } while (0) CONST NODISCARD int32_t RabbitizerUtils_From2Complement(uint32_t number, int bits); NON_NULL(1) size_t RabbitizerUtils_CharFill(char *dst, int count, char fillchar); NON_NULL(1, 3) size_t RabbitizerUtils_escapeString(char *dst, size_t dstSize, const char *src, size_t srcSize); CONST NODISCARD uint32_t RabbitizerUtils_floatRepr_32From16(uint16_t arg); #ifdef __cplusplus } #endif #endif