/* MIT License * * Copyright (c) 2023 Tyge Løvset * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef CCOMMON_H_INCLUDED #define CCOMMON_H_INCLUDED #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include "priv/altnames.h" #include "priv/raii.h" #define c_NPOS INTPTR_MAX #define c_ZI PRIiPTR #define c_ZU PRIuPTR #if defined STC_NDEBUG || defined NDEBUG #define c_ASSERT(expr) (void)(0) #else #define c_ASSERT(expr) assert(expr) #endif #if defined(_MSC_VER) #pragma warning(disable: 4116 4996) // unnamed type definition in parentheses #define STC_FORCE_INLINE static __forceinline #elif defined(__GNUC__) || defined(__clang__) #define STC_FORCE_INLINE static inline __attribute((always_inline)) #else #define STC_FORCE_INLINE static inline #endif #define STC_INLINE static inline /* Macro overloading feature support based on: https://rextester.com/ONP80107 */ #define c_MACRO_OVERLOAD(name, ...) \ c_PASTE(c_CONCAT(name,_), c_NUMARGS(__VA_ARGS__))(__VA_ARGS__) #define c_CONCAT(a, b) a ## b #define c_PASTE(a, b) c_CONCAT(a, b) #define c_EXPAND(...) __VA_ARGS__ #define c_NUMARGS(...) _c_APPLY_ARG_N((__VA_ARGS__, _c_RSEQ_N)) #define _c_APPLY_ARG_N(args) c_EXPAND(_c_ARG_N args) #define _c_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 #define _c_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ _14, _15, _16, N, ...) N #ifdef __cplusplus #include #define _i_alloc(T) static_cast(i_malloc(c_sizeof(T))) #define _i_new(T, ...) new (_i_alloc(T)) T(__VA_ARGS__) #define c_new(T, ...) new (malloc(sizeof(T))) T(__VA_ARGS__) #define c_LITERAL(T) T #else #define _i_alloc(T) ((T*)i_malloc(c_sizeof(T))) #define _i_new(T, ...) ((T*)memcpy(_i_alloc(T), (T[]){__VA_ARGS__}, sizeof(T))) #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), (T[]){__VA_ARGS__}, sizeof(T))) #define c_LITERAL(T) (T) #endif #define c_malloc(sz) malloc(c_i2u(sz)) #define c_calloc(n, sz) calloc(c_i2u(n), c_i2u(sz)) #define c_realloc(p, sz) realloc(p, c_i2u(sz)) #define c_free(p) free(p) #define c_delete(T, ptr) do { T *_tp = ptr; T##_drop(_tp); free(_tp); } while (0) #define c_static_assert(b) ((int)(0*sizeof(int[(b) ? 1 : -1]))) #define c_container_of(p, C, m) ((C*)((char*)(1 ? (p) : &((C*)0)->m) - offsetof(C, m))) #define c_const_cast(T, p) ((T)(p) + 0*sizeof((T)0 == (p))) #define c_swap(T, xp, yp) do { T *_xp = xp, *_yp = yp, \ _tv = *_xp; *_xp = *_yp; *_yp = _tv; } while (0) #define c_sizeof (intptr_t)sizeof #define c_strlen(s) (intptr_t)strlen(s) #define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u(ilen)) #define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u(ilen)) #define c_memmove(d, s, ilen) memmove(d, s, c_i2u(ilen)) #define c_memset(d, val, ilen) memset(d, val, c_i2u(ilen)) #define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u(ilen)) #define c_u2i(u) ((intptr_t)((u) + 0*sizeof((u) == 1U))) #define c_i2u(i) ((size_t)(i) + 0*sizeof((i) == 1)) #define c_LTu(a, b) ((size_t)(a) < (size_t)(b)) // x and y are i_keyraw* type, defaults to i_key*: #define c_default_cmp(x, y) (c_default_less(y, x) - c_default_less(x, y)) #define c_default_less(x, y) (*(x) < *(y)) #define c_default_eq(x, y) (*(x) == *(y)) #define c_memcmp_eq(x, y) (memcmp(x, y, sizeof *(x)) == 0) #define c_default_hash(x) cfasthash(x, c_sizeof(*(x))) #define c_default_clone(v) (v) #define c_default_toraw(vp) (*(vp)) #define c_default_drop(vp) ((void) (vp)) #define c_option(flag) ((i_opt) & (flag)) #define c_is_forward (1<<0) #define c_no_atomic (1<<1) #define c_no_clone (1<<2) #define c_no_emplace (1<<3) #define c_no_cmp (1<<4) #define c_no_hash (1<<5) /* Function macros and others */ #define c_make(C, ...) \ C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) #define c_litstrlen(literal) (c_sizeof("" literal) - 1) #define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a]) // Non-owning c-string typedef const char* crawstr; #define crawstr_clone(s) (s) #define crawstr_drop(p) ((void)p) #define crawstr_cmp(xp, yp) strcmp(*(xp), *(yp)) #define crawstr_hash(p) cstrhash(*(p)) #define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) #define c_sv_1(lit) c_sv_2(lit, c_litstrlen(lit)) #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) #define c_SV(sv) (int)(sv).size, (sv).str // print csview: use format "%.*s" #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { uint32_t u4; uint64_t u8; switch (len) { case 8: memcpy(&u8, key, 8); return u8*0xc6a4a7935bd1e99d; case 4: memcpy(&u4, key, 4); return u4*0xc6a4a7935bd1e99d; case 0: return 1; } const uint8_t *x = (const uint8_t*)key; uint64_t h = *x, n = (uint64_t)len >> 3; len &= 7; while (n--) { memcpy(&u8, x, 8), x += 8; h += u8*0xc6a4a7935bd1e99d; } while (len--) h = (h << 10) - h - *x++; return c_ROTL(h, 26) ^ h; } STC_INLINE uint64_t cstrhash(const char *str) { return cfasthash(str, c_strlen(str)); } STC_INLINE char* cstrnstrn(const char *str, const char *needle, intptr_t slen, const intptr_t nlen) { if (!nlen) return (char *)str; if (nlen > slen) return NULL; slen -= nlen; do { if (*str == *needle && !c_memcmp(str, needle, nlen)) return (char *)str; ++str; } while (slen--); return NULL; } /* Control block macros */ #define c_foreach(...) c_MACRO_OVERLOAD(c_foreach, __VA_ARGS__) #define c_foreach_3(it, C, cnt) \ for (C##_iter it = C##_begin(&cnt); it.ref; C##_next(&it)) #define c_foreach_4(it, C, start, finish) \ for (C##_iter it = start, *_endref = (C##_iter*)(finish).ref \ ; it.ref != (C##_value*)_endref; C##_next(&it)) #define c_foreach_rv(it, C, cnt) \ for (C##_iter it = {.ref=C##_end(&cnt).end - 1, .end=(cnt).data - 1} \ ; it.ref != it.end; --it.ref) #define c_forpair(key, val, C, cnt) /* structured binding */ \ for (struct {C##_iter it; const C##_key* key; C##_mapped* val;} _ = {.it=C##_begin(&cnt)} \ ; _.it.ref && (_.key = &_.it.ref->first, _.val = &_.it.ref->second) \ ; C##_next(&_.it)) #define c_forrange(...) c_MACRO_OVERLOAD(c_forrange, __VA_ARGS__) #define c_forrange_1(stop) c_forrange_3(_c_i, 0, stop) #define c_forrange_2(i, stop) c_forrange_3(i, 0, stop) #define c_forrange_3(i, start, stop) \ for (long long i=start, _end=(long long)(stop); i < _end; ++i) #define c_forrange_4(i, start, stop, step) \ for (long long i=start, _inc=step, _end=(long long)(stop) - (_inc > 0) \ ; (_inc > 0) ^ (i > _end); i += _inc) #ifndef __cplusplus #define c_forlist(it, T, ...) \ for (struct {T* ref; int size, index;} \ it = {.ref=(T[])__VA_ARGS__, .size=(int)(sizeof((T[])__VA_ARGS__)/sizeof(T))} \ ; it.index < it.size; ++it.ref, ++it.index) #else #include #define c_forlist(it, T, ...) \ for (struct {std::initializer_list _il; std::initializer_list::iterator data, ref; size_t size, index;} \ it = {._il=__VA_ARGS__, .data=it._il.begin(), .ref=it.data, .size=it._il.size()} \ ; it.index < it.size; ++it.ref, ++it.index) #endif #define c_drop(C, ...) \ do { c_forlist (_i, C*, {__VA_ARGS__}) C##_drop(*_i.ref); } while(0) #endif // CCOMMON_H_INCLUDED #undef STC_API #undef STC_DEF #if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \ defined(i_implement) || defined(STC_IMPLEMENT)) #define STC_API extern #define STC_DEF #else #define i_static #define STC_API static inline #define STC_DEF static inline #endif #if defined(STC_EXTERN) #define i_extern #endif #if defined(i_static) || defined(STC_IMPLEMENT) #define i_implement #endif