/* MIT License * * Copyright (c) 2025 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 STC_COMMON_H_INCLUDED #define STC_COMMON_H_INCLUDED #ifdef _MSC_VER #pragma warning(disable: 4116 4996) // unnamed type definition in parentheses #endif #include #include #include #include #include typedef ptrdiff_t isize; #ifndef STC_NO_INT_DEFS typedef int8_t int8; typedef uint8_t uint8; typedef int16_t int16; typedef uint16_t uint16; typedef int32_t int32; typedef uint32_t uint32; typedef int64_t int64; typedef uint64_t uint64; #endif #if !defined STC_HAS_TYPEOF && (_MSC_FULL_VER >= 193933428 || \ defined __GNUC__ || defined __clang__ || defined __TINYC__) #define STC_HAS_TYPEOF 1 #endif #if defined __GNUC__ #define c_GNUATTR(...) __attribute__((__VA_ARGS__)) #else #define c_GNUATTR(...) #endif #define STC_INLINE static inline c_GNUATTR(unused) #define c_ZI PRIiPTR #define c_ZU PRIuPTR #define c_NPOS INTPTR_MAX // Macro overloading feature support #define c_MACRO_OVERLOAD(name, ...) \ c_JOIN(name ## _,c_NUMARGS(__VA_ARGS__))(__VA_ARGS__) #define c_JOIN0(a, b) a ## b #define c_JOIN(a, b) c_JOIN0(a, b) #define c_NUMARGS(...) _c_APPLY_ARG_N((__VA_ARGS__, _c_RSEQ_N)) #define _c_APPLY_ARG_N(args) _c_ARG_N args #define _c_RSEQ_N 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, #define _c_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,N,...) N // Saturated overloading // #define foo(...) foo_I(__VA_ARGS__, c_COMMA_N(foo_3), c_COMMA_N(foo_2), c_COMMA_N(foo_1),)(__VA_ARGS__) // #define foo_I(a,b,c, n, ...) c_TUPLE_AT_1(n, foo_n,) #define c_TUPLE_AT_1(x,y,...) y #define c_COMMA_N(x) ,x #define c_EXPAND(...) __VA_ARGS__ // Select arg, e.g. for #define i_type A,B then c_GETARG(2, i_type) is B #define c_GETARG(N, ...) c_ARG_##N(__VA_ARGS__,) #define c_ARG_1(a, ...) a #define c_ARG_2(a, b, ...) b #define c_ARG_3(a, b, c, ...) c #define c_ARG_4(a, b, c, d, ...) d #define _i_new_n(T, n) ((T*)i_malloc((n)*c_sizeof(T))) #define _i_new_zeros(T, n) ((T*)i_calloc(n, c_sizeof(T))) #define _i_realloc_n(ptr, old_n, n) i_realloc(ptr, (old_n)*c_sizeof *(ptr), (n)*c_sizeof *(ptr)) #define _i_free_n(ptr, n) i_free(ptr, (n)*c_sizeof *(ptr)) #ifndef __cplusplus #define c_new(T, ...) ((T*)c_safe_memcpy(c_malloc(c_sizeof(T)), ((T[]){__VA_ARGS__}), c_sizeof(T))) #define c_literal(T) (T) #define c_make_array(T, ...) ((T[])__VA_ARGS__) #define c_make_array2d(T, N, ...) ((T[][N])__VA_ARGS__) #else #include #define c_new(T, ...) new (c_malloc(c_sizeof(T))) T(__VA_ARGS__) #define c_literal(T) T template struct _c_Array { T data[M][N]; }; #define c_make_array(T, ...) (_c_Array{{__VA_ARGS__}}.data[0]) #define c_make_array2d(T, N, ...) (_c_Array{__VA_ARGS__}.data) #endif #ifdef STC_ALLOCATOR #define c_malloc c_JOIN(STC_ALLOCATOR, _malloc) #define c_calloc c_JOIN(STC_ALLOCATOR, _calloc) #define c_realloc c_JOIN(STC_ALLOCATOR, _realloc) #define c_free c_JOIN(STC_ALLOCATOR, _free) #else #define c_malloc(sz) malloc(c_i2u_size(sz)) #define c_calloc(n, sz) calloc(c_i2u_size(n), c_i2u_size(sz)) #define c_realloc(ptr, old_sz, sz) realloc(ptr, c_i2u_size(1 ? (sz) : (old_sz))) #define c_free(ptr, sz) ((void)(sz), free(ptr)) #endif #define c_new_n(T, n) ((T*)c_malloc((n)*c_sizeof(T))) #define c_free_n(ptr, n) c_free(ptr, (n)*c_sizeof *(ptr)) #define c_realloc_n(ptr, old_n, n) c_realloc(ptr, (old_n)*c_sizeof *(ptr), (n)*c_sizeof *(ptr)) #define c_delete_n(T, ptr, n) do { \ T* _tp = ptr; isize _n = n, _i = _n; \ while (_i--) T##_drop((_tp + _i)); \ c_free(_tp, _n*c_sizeof(T)); \ } while (0) #define c_static_assert(expr) (void)sizeof(int[(expr) ? 1 : -1]) #if defined STC_NDEBUG || defined NDEBUG #define c_assert(expr) (void)sizeof(expr) #else #define c_assert(expr) assert(expr) #endif #define c_container_of(p, C, m) ((C*)((char*)(1 ? (p) : &((C*)0)->m) - offsetof(C, m))) #define c_const_cast(Tp, p) ((Tp)(1 ? (p) : (Tp)0)) #define c_litstrlen(literal) (c_sizeof("" literal) - 1) #define c_countof(a) (isize)(sizeof(a)/sizeof 0[a]) #define c_arraylen(a) c_countof(a) // [deprecated]? // expect signed ints to/from these (use with gcc -Wconversion) #define c_sizeof (isize)sizeof #define c_strlen(s) (isize)strlen(s) #define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u_size(ilen)) #define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u_size(ilen)) #define c_memmove(d, s, ilen) memmove(d, s, c_i2u_size(ilen)) #define c_memset(d, val, ilen) memset(d, val, c_i2u_size(ilen)) #define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u_size(ilen)) // library internal, but may be useful in user code: #define c_u2i_size(u) (isize)(1 ? (u) : (size_t)1) // warns if u is signed #define c_i2u_size(i) (size_t)(1 ? (i) : -1) // warns if i is unsigned #define c_uless(a, b) ((size_t)(a) < (size_t)(b)) #define c_safe_cast(T, From, x) ((T)(1 ? (x) : (From){0})) // x, y are i_keyraw* type, which defaults to i_key*. vp is i_key* type. #define c_memcmp_eq(x, y) (memcmp(x, y, sizeof *(x)) == 0) #define c_default_eq(x, y) (*(x) == *(y)) #define c_default_less(x, y) (*(x) < *(y)) #define c_default_cmp(x, y) (c_default_less(y, x) - c_default_less(x, y)) #define c_default_hash(vp) c_hash_n(vp, sizeof *(vp)) #define c_default_clone(v) (v) #define c_default_toraw(vp) (*(vp)) #define c_default_drop(vp) ((void) (vp)) // non-owning char pointer typedef const char* cstr_raw; #define cstr_raw_cmp(x, y) strcmp(*(x), *(y)) #define cstr_raw_eq(x, y) (cstr_raw_cmp(x, y) == 0) #define cstr_raw_hash(vp) c_hash_str(*(vp)) #define cstr_raw_clone(v) (v) #define cstr_raw_drop(vp) ((void)vp) // Control block macros // [deprecated]: #define c_init(...) c_make(__VA_ARGS__) #define c_forlist(...) for (c_items(_VA_ARGS__)) #define c_foritems(...) for (c_items(__VA_ARGS__)) #define c_foreach(...) for (c_each(__VA_ARGS__)) #define c_foreach_n(...) for (c_each_n(__VA_ARGS__)) #define c_foreach_kv(...) for (c_each_kv(__VA_ARGS__)) #define c_foreach_reverse(...) for (c_each_reverse(__VA_ARGS__)) #define c_forrange(...) for (c_range(__VA_ARGS__)) #define c_forrange32(...) for (c_range32(__VA_ARGS__)) // New: #define c_each(...) c_MACRO_OVERLOAD(c_each, __VA_ARGS__) #define c_each_3(it, C, cnt) \ C##_iter it = C##_begin(&cnt); it.ref; C##_next(&it) #define c_each_4(it, C, start, end) \ _c_each(it, C, start, (end).ref, _) #define c_each_n(...) c_MACRO_OVERLOAD(c_each_n, __VA_ARGS__) #define c_each_n_3(it, C, cnt) c_each_n_4(it, C, cnt, INTPTR_MAX) #define c_each_n_4(it, C, cnt, n) \ struct {C##_iter iter; C##_value* ref; isize size, index;} \ it = {.iter=C##_begin(&cnt), .size=n}; (it.ref = it.iter.ref) && it.index < it.size; C##_next(&it.iter), ++it.index #define c_each_reverse(...) c_MACRO_OVERLOAD(c_each_reverse, __VA_ARGS__) #define c_each_reverse_3(it, C, cnt) /* works for stack, vec, queue, deque */ \ C##_iter it = C##_rbegin(&cnt); it.ref; C##_rnext(&it) #define c_each_reverse_4(it, C, start, end) \ _c_each(it, C, start, (end).ref, _r) #define _c_each(it, C, start, endref, rev) /* private */ \ C##_iter it = (start), *_endref_##it = c_safe_cast(C##_iter*, C##_value*, endref) \ ; it.ref != (C##_value*)_endref_##it; C##rev##next(&it) #define c_each_kv(...) c_MACRO_OVERLOAD(c_each_kv, __VA_ARGS__) #define c_each_kv_4(key, val, C, cnt) /* structured binding for maps */ \ _c_each_kv(key, val, C, C##_begin(&cnt), NULL) #define c_each_kv_5(key, val, C, start, end) \ _c_each_kv(key, val, C, start, (end).ref) #define _c_each_kv(key, val, C, start, endref) /* private */ \ const C##_key *key = (const C##_key*)&key; key; ) \ for (C##_mapped *val; key; key = NULL) \ for (C##_iter _it_##key = start, *_endref_##key = c_safe_cast(C##_iter*, C##_value*, endref); \ _it_##key.ref != (C##_value*)_endref_##key && (key = &_it_##key.ref->first, val = &_it_##key.ref->second); \ C##_next(&_it_##key) #define c_items(it, T, ...) \ struct {T* ref; int size, index;} \ it = {.ref=c_make_array(T, __VA_ARGS__), .size=(int)(sizeof((T[])__VA_ARGS__)/sizeof(T))} \ ; it.index < it.size ; ++it.ref, ++it.index // c_range, c_range32: python-like int range iteration #define c_range_t(...) c_MACRO_OVERLOAD(c_range_t, __VA_ARGS__) #define c_range_t_3(T, i, stop) c_range_t_4(T, i, 0, stop) #define c_range_t_4(T, i, start, stop) \ T i=start, _c_end_##i=stop; i < _c_end_##i; ++i #define c_range_t_5(T, i, start, stop, step) \ T i=start, _c_inc_##i=step, _c_end_##i=(stop) - (_c_inc_##i > 0) \ ; (_c_inc_##i > 0) == (i <= _c_end_##i) ; i += _c_inc_##i #define c_range(...) c_MACRO_OVERLOAD(c_range, __VA_ARGS__) #define c_range_1(stop) c_range_t_4(isize, _c_i1, 0, stop) #define c_range_2(i, stop) c_range_t_4(isize, i, 0, stop) #define c_range_3(i, start, stop) c_range_t_4(isize, i, start, stop) #define c_range_4(i, start, stop, step) c_range_t_5(isize, i, start, stop, step) #define c_range32(...) c_MACRO_OVERLOAD(c_range32, __VA_ARGS__) #define c_range32_2(i, stop) c_range_t_4(int32_t, i, 0, stop) #define c_range32_3(i, start, stop) c_range_t_4(int32_t, i, start, stop) #define c_range32_4(i, start, stop, step) c_range_t_5(int32_t, i, start, stop, step) // make container from a literal list #define c_make(C, ...) \ C##_from_n(c_make_array(C##_raw, __VA_ARGS__), c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) // put multiple raw-type elements from a literal list into a container #define c_put_items(C, cnt, ...) \ C##_put_n(cnt, c_make_array(C##_raw, __VA_ARGS__), c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) // drop multiple containers of same type #define c_drop(C, ...) \ do { for (c_items(_c_i2, C*, {__VA_ARGS__})) C##_drop(*_c_i2.ref); } while(0) // RAII scopes #define c_defer(...) \ for (int _c_i3 = 0; _c_i3++ == 0; __VA_ARGS__) #define c_with(...) c_MACRO_OVERLOAD(c_with, __VA_ARGS__) #define c_with_2(init, deinit) \ for (int _c_i4 = 0; _c_i4 == 0; ) for (init; _c_i4++ == 0; deinit) #define c_with_3(init, condition, deinit) \ for (int _c_i5 = 0; _c_i5 == 0; ) for (init; _c_i5++ == 0 && (condition); deinit) // General functions STC_INLINE void* c_safe_memcpy(void* dst, const void* src, isize size) { return dst ? memcpy(dst, src, (size_t)size) : NULL; } #if INTPTR_MAX == INT64_MAX #define FNV_BASIS 0xcbf29ce484222325 #define FNV_PRIME 0x00000100000001b3 #else #define FNV_BASIS 0x811c9dc5 #define FNV_PRIME 0x01000193 #endif STC_INLINE size_t c_basehash_n(const void* key, isize len) { const uint8_t* msg = (const uint8_t*)key; size_t h = FNV_BASIS, block = 0; while (len >= c_sizeof h) { memcpy(&block, msg, sizeof h); h ^= block; h *= FNV_PRIME; msg += c_sizeof h; len -= c_sizeof h; } while (len--) { h ^= *(msg++); h *= FNV_PRIME; } return h; } STC_INLINE size_t c_hash_n(const void* key, isize len) { uint64_t b8; uint32_t b4; switch (len) { case 8: memcpy(&b8, key, 8); return (size_t)(b8 * 0xc6a4a7935bd1e99d); case 4: memcpy(&b4, key, 4); return b4 * FNV_BASIS; default: return c_basehash_n(key, len); } } STC_INLINE size_t c_hash_str(const char *str) { const uint8_t* msg = (const uint8_t*)str; size_t h = FNV_BASIS; while (*msg) { h ^= *(msg++); h *= FNV_PRIME; } return h; } #define c_hash_mix(...) /* non-commutative hash combine */ \ c_hash_mix_n(c_make_array(size_t, {__VA_ARGS__}), c_sizeof((size_t[]){__VA_ARGS__})/c_sizeof(size_t)) STC_INLINE size_t c_hash_mix_n(size_t h[], isize n) { for (isize i = 1; i < n; ++i) h[0] += h[0] ^ h[i]; return h[0]; } // generic typesafe swap #define c_swap(xp, yp) do { \ (void)sizeof((xp) == (yp)); \ char _tv[sizeof *(xp)]; \ void *_xp = xp, *_yp = yp; \ memcpy(_tv, _xp, sizeof _tv); \ memcpy(_xp, _yp, sizeof _tv); \ memcpy(_yp, _tv, sizeof _tv); \ } while (0) // get next power of two STC_INLINE isize c_next_pow2(isize n) { n--; n |= n >> 1, n |= n >> 2; n |= n >> 4, n |= n >> 8; n |= n >> 16; #if INTPTR_MAX == INT64_MAX n |= n >> 32; #endif return n + 1; } STC_INLINE char* c_strnstrn(const char *str, isize slen, const char *needle, isize nlen) { if (nlen == 0) 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; } #endif // STC_COMMON_H_INCLUDED