Scaffolding project.
h3rald h3rald@h3rald.com
Tue, 09 Jun 2026 14:21:56 +0200
22 files changed,
2563 insertions(+),
0 deletions(-)
jump to
A
Makefile
@@ -0,0 +1,11 @@
+CC = gcc +CFLAGS = -std=c99 -Ivendor/stc/include -Wall -O2 + +SRCS = vendor/stc/stc.c src/conver.c +OBJS = $(SRCS:.c=.o) + +conver: $(OBJS) + $(CC) -o $@ $^ -lm + +clean: + rm -f $(OBJS) conver conver.exe
A
README.md
@@ -0,0 +1,3 @@
+# conver + +**conver** is a simple tool to manage projects implementing Convergent Versioning.
A
src/conver.c
@@ -0,0 +1,20 @@
+#include "conver.h" + +//// Main + +int main(int argc, char *argv[]) +{ + + if (argc > 1) + { + for (int i = 1; i < argc; i++) + { + char *arg = argv[i]; + if ((strcmp(arg, "-v") == 0 || strcmp(arg, "--version") == 0)) + { + printf("%04X\n", CONVER_VERSION); + return 0; + } + } + } +}
A
src/conver.h
@@ -0,0 +1,15 @@
+#ifndef CONVER_H +#define CONVER_H + +#define CONVER_VERSION 0x100D + +#include <stdio.h> +#include "stc/cstr.h" + +#define i_pro_key cstr +#include <stc/vec.h> + + + + +#endif // CONVER_H
A
vendor/stc/include/stc/common.h
@@ -0,0 +1,354 @@
+/* MIT License + * + * Copyright (c) 2026 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 <inttypes.h> +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> + +#ifndef ISIZE_MAX + typedef ptrdiff_t isize_t; + typedef isize_t isize; // [deprecated] + #define ISIZE_MIN PTRDIFF_MIN + #define ISIZE_MAX PTRDIFF_MAX +#endif +#if defined __GNUC__ || defined __clang__ || \ + defined __TINYC__ || _MSC_FULL_VER >= 193933428 + #define STC_HAS_TYPEOF +#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 <new> + #define c_new(T, ...) new (c_malloc(c_sizeof(T))) T(__VA_ARGS__) + #define c_literal(T) T + template<typename T, int M, int N> struct _c_Array { T data[M][N]; }; + #define c_make_array(T, ...) (_c_Array<T, 1, sizeof((T[])__VA_ARGS__)/sizeof(T)>{{__VA_ARGS__}}.data[0]) + #define c_make_array2d(T, N, ...) (_c_Array<T, sizeof((T[][N])__VA_ARGS__)/sizeof(T[N]), N>{__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_cast(sz)) + #define c_calloc(n, sz) calloc(c_i2u_cast(n), c_i2u_cast(sz)) + #define c_realloc(ptr, old_sz, sz) realloc(ptr, c_i2u_cast(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_free_obj(ptr) c_free_n(ptr, 1) +#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_t _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_countof(a) (isize_t)(sizeof(a)/sizeof 0[a]) +#define c_as_mut(Tp, p) ((Tp)(1 ? (p) : (Tp)0)) +#define c_safe_cast(T, From, x) ((T)(1 ? (x) : (From){0})) + +// expect signed ints to/from these (use with gcc -Wconversion) +#define c_sizeof (isize_t)sizeof +#define c_strlen(s) (isize_t)strlen(s) +#define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u_cast(ilen)) +#define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u_cast(ilen)) +#define c_memmove(d, s, ilen) memmove(d, s, c_i2u_cast(ilen)) +#define c_memset(d, val, ilen) memset(d, val, c_i2u_cast(ilen)) +#define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u_cast(ilen)) +// library internal, but may be useful in user code: +#define c_u2i_cast(u) (isize_t)(1 ? (u) : (size_t)1) // warns if u is signed +#define c_i2u_cast(i) (size_t)(1 ? (i) : -1) // warns if i is unsigned +#define c_uless(a, b) ((size_t)(a) < (size_t)(b)) +#define c_litstrlen(literal) (c_sizeof("" literal) - 1) + +// 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)) + +// Control block macros + +// [deprecated]: +#define c_init(...) c_make(__VA_ARGS__) +#define c_items(...) c_each_item(__VA_ARGS__) +#define c_foritems(...) for (c_each_item(__VA_ARGS__)) +#define c_foreach(...) for (c_each(__VA_ARGS__)) +#define c_foreach_kv(...) for (c_each_kv(__VA_ARGS__)) +#define c_forrange(...) for (c_range(__VA_ARGS__)) +#define c_forrange32(...) for (c_range32(__VA_ARGS__)) +#define c_arraylen(a) c_countof(a) +#define c_const_cast(Tp, p) c_as_mut(Tp, p) +// End [deprecated] + +// 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_ref(v, C, cnt) \ + C##_value* v = (C##_value*)&v; v; ) \ + for (C##_iter v##_itr_ = C##_begin(&cnt); (v = v##_itr_.ref); C##_next(&v##_itr_) + +#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_t 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_each_item(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_t, _c_i1, 0, stop) +#define c_range_2(i, stop) c_range_t_4(isize_t, i, 0, stop) +#define c_range_3(i, start, stop) c_range_t_4(isize_t, i, start, stop) +#define c_range_4(i, start, stop, step) c_range_t_5(isize_t, 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_each_item(_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_t 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_t 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_t 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_t n) { + for (isize_t i = 1; i < n; ++i) h[0] += h[0] ^ h[i]; + return h[0]; +} + +// generic typesafe swap +#ifdef STC_HAS_TYPEOF +#define c_swap(xp, yp) do { \ + __typeof__(xp) _xp = (xp), _yp = (yp); \ + __typeof__(0[xp]) _tv = *_xp; *_xp = *_yp; *_yp = _tv; \ +} while (0) +#else +#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) +#endif + +// get next power of two +STC_INLINE isize_t c_next_pow2(isize_t 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_t slen, const char *needle, isize_t 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
A
vendor/stc/include/stc/cstr.h
@@ -0,0 +1,52 @@
+/* MIT License + * + * Copyright (c) 2026 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. + */ + +/* A string type with short string optimization in C99. + * Stores up to a 22 bytes long string inside a 24 bytes string representation (x64). + */ +#define i_header // external linkage by default. override with i_static. +#include "priv/linkage.h" + +#ifndef STC_CSTR_H_INCLUDED +#define STC_CSTR_H_INCLUDED + +#include "common.h" +#include "types.h" +#include "priv/utf8_prv.h" +#include "priv/cstr_prv.h" + +#endif // STC_CSTR_H_INCLUDED + +#if defined i_implement || \ + defined STC_CSTR_CORE || \ + defined STC_CSTR_MISC || \ + defined STC_CSTR_IO || \ + defined STC_CSTR_UTF8 + #include "priv/cstr_prv.c" +#endif // i_implement + +#if defined i_import || defined STC_CSTR_UTF8 + #include "priv/utf8_prv.c" +#endif + +#include "priv/linkage2.h"
A
vendor/stc/include/stc/priv/cstr_prv.c
@@ -0,0 +1,299 @@
+/* MIT License + * + * Copyright (c) 2026 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. + */ +// ------------------- STC_CSTR_CORE -------------------- +#if !defined STC_CSTR_CORE_C_INCLUDED && \ + (defined i_implement || defined STC_CSTR_CORE) +#define STC_CSTR_CORE_C_INCLUDED + +void cstr_drop(const cstr* self) { + if (cstr_is_long(self)) + cstr_l_drop(self); +} + +cstr* cstr_take(cstr* self, const cstr s) { + if (cstr_is_long(self) && self->lon.data != s.lon.data) + cstr_l_drop(self); + *self = s; + return self; +} + +size_t cstr_hash(const cstr *self) { + csview sv = cstr_sv(self); + return c_hash_str(sv.buf); +} + +isize_t cstr_find_sv(const cstr* self, csview search) { + csview sv = cstr_sv(self); + char* res = c_strnstrn(sv.buf, sv.size, search.buf, search.size); + return res ? (res - sv.buf) : c_NPOS; +} + +char* _cstr_init(cstr* self, const isize_t len, const isize_t cap) { + if (cap > cstr_s_cap) { + self->lon.data = (char *)c_malloc(cap + 1); + cstr_l_set_size(self, len); + cstr_l_set_cap(self, cap); + return self->lon.data; + } + cstr_s_set_size(self, len); + return self->sml.data; +} + +char* cstr_reserve(cstr* self, const isize_t cap) { + if (cstr_is_long(self)) { + if (cap > cstr_l_cap(self)) { + self->lon.data = (char *)c_realloc(self->lon.data, cstr_l_cap(self) + 1, cap + 1); + cstr_l_set_cap(self, cap); + } + return self->lon.data; + } + /* from short to long: */ + if (cap > cstr_s_cap) { + char* data = (char *)c_malloc(cap + 1); + const isize_t len = cstr_s_size(self); + /* copy full short buffer to emulate realloc() */ + c_memcpy(data, self->sml.data, c_sizeof self->sml); + self->lon.data = data; + self->lon.size = (size_t)len; + cstr_l_set_cap(self, cap); + return data; + } + return self->sml.data; +} + +char* cstr_resize(cstr* self, const isize_t size, const char value) { + cstr_buf b = cstr_getbuf(self); + if (size > b.size) { + if (size > b.cap && (b.data = cstr_reserve(self, size)) == NULL) + return NULL; + c_memset(b.data + b.size, value, size - b.size); + } + _cstr_set_size(self, size); + return b.data; +} + +isize_t cstr_find_at(const cstr* self, const isize_t pos, const char* search) { + csview sv = cstr_sv(self); + if (pos > sv.size) return c_NPOS; + const char* res = strstr((char*)sv.buf + pos, search); + return res ? (res - sv.buf) : c_NPOS; +} + +char* cstr_assign_n(cstr* self, const char* str, const isize_t len) { + char* d = cstr_reserve(self, len); + if (d) { _cstr_set_size(self, len); c_memmove(d, str, len); } + return d; +} + +char* cstr_append_n(cstr* self, const char* str, const isize_t len) { + cstr_buf b = cstr_getbuf(self); + if (b.size + len > b.cap) { + const size_t off = (size_t)(str - b.data); + b.data = cstr_reserve(self, b.size*3/2 + len); + if (b.data == NULL) return NULL; + if (off <= (size_t)b.size) str = b.data + off; /* handle self append */ + } + c_memcpy(b.data + b.size, str, len); + _cstr_set_size(self, b.size + len); + return b.data; +} + +void cstr_erase(cstr* self, const isize_t pos, isize_t len) { + cstr_buf b = cstr_getbuf(self); + if (len > b.size - pos) len = b.size - pos; + c_memmove(&b.data[pos], &b.data[pos + len], b.size - (pos + len)); + _cstr_set_size(self, b.size - len); +} +#endif // STC_CSTR_CORE_C_INCLUDED + + +// ------------------- STC_CSTR_MISC -------------------- +#if !defined STC_CSTR_MISC_C_INCLUDED && \ + (defined i_implement || defined STC_CSTR_MISC) +#define STC_CSTR_MISC_C_INCLUDED + +void cstr_shrink_to_fit(cstr* self) { + cstr_buf b = cstr_getbuf(self); + if (b.size == b.cap) + return; + if (b.size > cstr_s_cap) { + self->lon.data = (char *)c_realloc(self->lon.data, cstr_l_cap(self) + 1, b.size + 1); + cstr_l_set_cap(self, b.size); + } else if (b.cap > cstr_s_cap) { + c_memcpy(self->sml.data, b.data, b.size + 1); + cstr_s_set_size(self, b.size); + c_free(b.data, b.cap + 1); + } +} + +char* _cstr_internal_move(cstr* self, const isize_t pos1, const isize_t pos2) { + cstr_buf b = cstr_getbuf(self); + if (pos1 != pos2) { + const isize_t newlen = (b.size + pos2 - pos1); + if (newlen > b.cap) + b.data = cstr_reserve(self, b.size*3/2 + pos2 - pos1); + c_memmove(&b.data[pos2], &b.data[pos1], b.size - pos1); + _cstr_set_size(self, newlen); + } + return b.data; +} + +cstr cstr_from_replace(csview in, csview search, csview repl, int32_t count) { + cstr out = cstr_init(); + isize_t from = 0; char* res; + if (count == 0) count = INT32_MAX; + if (search.size) + while (count-- && (res = c_strnstrn(in.buf + from, in.size - from, search.buf, search.size))) { + const isize_t pos = (res - in.buf); + cstr_append_n(&out, in.buf + from, pos - from); + cstr_append_n(&out, repl.buf, repl.size); + from = pos + search.size; + } + cstr_append_n(&out, in.buf + from, in.size - from); + return out; +} +#endif // STC_CSTR_MISC_C_INCLUDED + + +// ------------------- STC_CSTR_IO -------------------- +#if !defined STC_CSTR_IO_C_INCLUDED && \ + (defined i_import || defined STC_CSTR_IO) +#define STC_CSTR_IO_C_INCLUDED + +char* cstr_append_uninit(cstr *self, isize_t len) { + cstr_buf b = cstr_getbuf(self); + if (b.size + len > b.cap && (b.data = cstr_reserve(self, b.size*3/2 + len)) == NULL) + return NULL; + _cstr_set_size(self, b.size + len); + return b.data + b.size; +} + +bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { + int c = fgetc(fp); + if (c == EOF) + return false; + isize_t pos = 0; + cstr_buf b = cstr_getbuf(self); + for (;;) { + if (c == delim || c == EOF) { + _cstr_set_size(self, pos); + return true; + } + if (pos == b.cap) { + _cstr_set_size(self, pos); + char* data = cstr_reserve(self, (b.cap = b.cap*3/2 + 16)); + b.data = data; + } + b.data[pos++] = (char) c; + c = fgetc(fp); + } +} + +isize_t cstr_vfmt(cstr* self, isize_t start, const char* fmt, va_list args) { + va_list args2; + va_copy(args2, args); + const int n = vsnprintf(NULL, 0ULL, fmt, args); + vsnprintf(cstr_reserve(self, start + n) + start, (size_t)n+1, fmt, args2); + va_end(args2); + _cstr_set_size(self, start + n); + return n; +} + +cstr cstr_from_fmt(const char* fmt, ...) { + cstr s = cstr_init(); + va_list args; + va_start(args, fmt); + cstr_vfmt(&s, 0, fmt, args); + va_end(args); + return s; +} + +isize_t cstr_append_fmt(cstr* self, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + const isize_t n = cstr_vfmt(self, cstr_size(self), fmt, args); + va_end(args); + return n; +} + +/* NB! self-data in args is UB */ +isize_t cstr_printf(cstr* self, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + const isize_t n = cstr_vfmt(self, 0, fmt, args); + va_end(args); + return n; +} +#endif // STC_CSTR_IO_C_INCLUDED + +// ------------------- STC_CSTR_UTF8 -------------------- +#if !defined STC_CSTR_UTF8_C_INCLUDED && \ + (defined i_import || defined STC_CSTR_UTF8 || defined STC_UTF8_PRV_C_INCLUDED) +#define STC_CSTR_UTF8_C_INCLUDED + +#include <ctype.h> + +void cstr_u8_erase(cstr* self, const isize_t u8pos, const isize_t u8len) { + csview b = cstr_sv(self); + csview span = cutf8_subview(b.buf, u8pos, u8len); + c_memmove((void *)&span.buf[0], &span.buf[span.size], b.size - span.size - (span.buf - b.buf)); + _cstr_set_size(self, b.size - span.size); +} + +bool cstr_u8_valid(const cstr* self) + { return cutf8_valid(cstr_str(self)); } + +static int toLower(int c) + { return c >= 'A' && c <= 'Z' ? c + 32 : c; } +static int toUpper(int c) + { return c >= 'a' && c <= 'z' ? c - 32 : c; } +static struct { + int (*conv_asc)(int); + uint32_t (*conv_utf)(uint32_t); +} +fn_tocase[] = {{toLower, cutf8_casefold}, + {toLower, cutf8_tolower}, + {toUpper, cutf8_toupper}}; + +cstr cstr_tocase_sv(csview sv, int k) { + cstr out = {0}; + char *buf = cstr_reserve(&out, sv.size*3/2); + isize_t sz = 0; + cutf8_decode_t d = {.state=0}; + const char* end = sv.buf + sv.size; + + while (sv.buf < end) { + sv.buf += cutf8_decode_codepoint(&d, sv.buf, end); + + if (d.codep < 0x80) + buf[sz++] = (char)fn_tocase[k].conv_asc((int)d.codep); + else { + uint32_t cp = fn_tocase[k].conv_utf(d.codep); + sz += cutf8_encode(buf + sz, cp); + } + } + _cstr_set_size(&out, sz); + cstr_shrink_to_fit(&out); + return out; +} +#endif // i_import STC_CSTR_UTF8_C_INCLUDED
A
vendor/stc/include/stc/priv/cstr_prv.h
@@ -0,0 +1,425 @@
+/* MIT License + * + * Copyright (c) 2026 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. + */ +// IWYU pragma: private, include "stc/cstr.h" +#ifndef STC_CSTR_PRV_H_INCLUDED +#define STC_CSTR_PRV_H_INCLUDED + +#include <stdio.h> /* FILE*, vsnprintf */ +#include <stdlib.h> /* malloc */ +#include <stddef.h> /* size_t */ +#include <stdarg.h> /* cstr_vfmt() */ +/**************************** PRIVATE API **********************************/ + +#if defined __GNUC__ && !defined __clang__ + // linkage.h already does diagnostic push + // Warns wrongfully on -O3 on cstr_assign(&str, "literal longer than 23 ..."); + #pragma GCC diagnostic ignored "-Warray-bounds" +#endif + +enum { cstr_s_cap = sizeof(cstr_buf) - 2 }; +#define cstr_s_size(s) ((isize_t)(s)->sml.size) +#define cstr_s_set_size(s, len) ((s)->sml.data[(s)->sml.size = (uint8_t)(len)] = 0) +#define cstr_s_data(s) (s)->sml.data + +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + #define byte_rotl_(x, b) ((x) << (b)*8 | (x) >> (sizeof(x) - (b))*8) + #define cstr_l_cap(s) (isize_t)(~byte_rotl_((s)->lon.ncap, sizeof((s)->lon.ncap) - 1)) + #define cstr_l_set_cap(s, cap) ((s)->lon.ncap = ~byte_rotl_((uintptr_t)(cap), 1)) +#else + #define cstr_l_cap(s) (isize_t)(~(s)->lon.ncap) + #define cstr_l_set_cap(s, cap) ((s)->lon.ncap = ~(uintptr_t)(cap)) +#endif +#define cstr_l_size(s) (isize_t)((s)->lon.size) +#define cstr_l_set_size(s, len) ((s)->lon.data[(s)->lon.size = (uintptr_t)(len)] = 0) +#define cstr_l_data(s) (s)->lon.data +#define cstr_l_drop(s) c_free((s)->lon.data, cstr_l_cap(s) + 1) + +#define cstr_is_long(s) ((s)->sml.size >= 128) +extern char* _cstr_init(cstr* self, isize_t len, isize_t cap); +extern char* _cstr_internal_move(cstr* self, isize_t pos1, isize_t pos2); + +/**************************** PUBLIC API **********************************/ + +#define cstr_init() (c_literal(cstr){0}) +#define cstr_lit(literal) cstr_from_n(literal, c_litstrlen(literal)) + +extern cstr cstr_from_replace(csview sv, csview search, csview repl, int32_t count); +extern cstr cstr_from_fmt(const char* fmt, ...) c_GNUATTR(format(printf, 1, 2)); + +extern void cstr_drop(const cstr* self); +extern cstr* cstr_take(cstr* self, const cstr s); +extern char* cstr_reserve(cstr* self, isize_t cap); +extern void cstr_shrink_to_fit(cstr* self); +extern char* cstr_resize(cstr* self, isize_t size, char value); +extern isize_t cstr_find_at(const cstr* self, isize_t pos, const char* search); +extern isize_t cstr_find_sv(const cstr* self, csview search); +extern char* cstr_assign_n(cstr* self, const char* str, isize_t len); +extern char* cstr_append_n(cstr* self, const char* str, isize_t len); +extern isize_t cstr_append_fmt(cstr* self, const char* fmt, ...) c_GNUATTR(format(printf, 2, 3)); +extern char* cstr_append_uninit(cstr *self, isize_t len); + +extern bool cstr_getdelim(cstr *self, int delim, FILE *fp); +extern void cstr_erase(cstr* self, isize_t pos, isize_t len); +extern isize_t cstr_printf(cstr* self, const char* fmt, ...) c_GNUATTR(format(printf, 2, 3)); +extern isize_t cstr_vfmt(cstr* self, isize_t start, const char* fmt, va_list args); +extern size_t cstr_hash(const cstr *self); +extern bool cstr_u8_valid(const cstr* self); +extern void cstr_u8_erase(cstr* self, isize_t u8pos, isize_t u8len); + +STC_INLINE cstr_buf cstr_getbuf(cstr* s) { + return cstr_is_long(s) ? c_literal(cstr_buf){s->lon.data, cstr_l_size(s), cstr_l_cap(s)} + : c_literal(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap}; +} +STC_INLINE zsview cstr_zv(const cstr* s) { + return cstr_is_long(s) ? c_literal(zsview){s->lon.data, cstr_l_size(s)} + : c_literal(zsview){s->sml.data, cstr_s_size(s)}; +} +STC_INLINE csview cstr_sv(const cstr* s) { + return cstr_is_long(s) ? c_literal(csview){s->lon.data, cstr_l_size(s)} + : c_literal(csview){s->sml.data, cstr_s_size(s)}; +} + +STC_INLINE cstr cstr_from_n(const char* str, const isize_t len) { + cstr s; + c_memcpy(_cstr_init(&s, len, len), str, len); + return s; +} + +STC_INLINE cstr cstr_from(const char* str) + { return cstr_from_n(str, c_strlen(str)); } + +STC_INLINE cstr cstr_from_sv(csview sv) + { return cstr_from_n(sv.buf, sv.size); } + +STC_INLINE cstr cstr_from_zv(zsview zv) + { return cstr_from_n(zv.str, zv.size); } + +STC_INLINE cstr cstr_with_size(const isize_t size, const char value) { + cstr s; + c_memset(_cstr_init(&s, size, size), value, size); + return s; +} + +STC_INLINE cstr cstr_with_capacity(const isize_t cap) { + cstr s; + _cstr_init(&s, 0, cap); + return s; +} + +STC_INLINE cstr cstr_move(cstr* self) { + cstr tmp = *self; + *self = cstr_init(); + return tmp; +} + +STC_INLINE cstr cstr_clone(cstr s) { + csview sv = cstr_sv(&s); + return cstr_from_n(sv.buf, sv.size); +} + +#define SSO_CALL(s, call) (cstr_is_long(s) ? cstr_l_##call : cstr_s_##call) + +STC_INLINE void _cstr_set_size(cstr* self, isize_t len) + { SSO_CALL(self, set_size(self, len)); } + +STC_INLINE void cstr_clear(cstr* self) + { _cstr_set_size(self, 0); } + +STC_INLINE char* cstr_data(cstr* self) + { return SSO_CALL(self, data(self)); } + +STC_INLINE const char* cstr_str(const cstr* self) + { return SSO_CALL(self, data(self)); } + +STC_INLINE const char* cstr_toraw(const cstr* self) + { return SSO_CALL(self, data(self)); } + +STC_INLINE isize_t cstr_size(const cstr* self) + { return SSO_CALL(self, size(self)); } + +STC_INLINE bool cstr_is_empty(const cstr* self) + { return cstr_size(self) == 0; } + +STC_INLINE isize_t cstr_capacity(const cstr* self) + { return cstr_is_long(self) ? cstr_l_cap(self) : cstr_s_cap; } + +STC_INLINE isize_t cstr_to_index(const cstr* self, cstr_iter it) + { return it.ref - cstr_str(self); } + +STC_INLINE cstr cstr_from_s(cstr s, isize_t pos, isize_t len) + { return cstr_from_n(cstr_str(&s) + pos, len); } + +STC_INLINE csview cstr_subview(const cstr* self, isize_t pos, isize_t len) { + csview sv = cstr_sv(self); + c_assert(((size_t)pos <= (size_t)sv.size) & (len >= 0)); + if (pos + len > sv.size) len = sv.size - pos; + return c_literal(csview){sv.buf + pos, len}; +} + +STC_INLINE zsview cstr_tail(const cstr* self, isize_t len) { + c_assert(len >= 0); + csview sv = cstr_sv(self); + if (len > sv.size) len = sv.size; + return c_literal(zsview){&sv.buf[sv.size - len], len}; +} + +// BEGIN utf8 functions ===== + +STC_INLINE cstr cstr_u8_from(const char* str, isize_t u8pos, isize_t u8len) + { str = cutf8_at(str, u8pos); return cstr_from_n(str, cutf8_to_index(str, u8len)); } + +STC_INLINE isize_t cstr_u8_size(const cstr* self) + { return cutf8_count(cstr_str(self)); } + +STC_INLINE isize_t cstr_u8_to_index(const cstr* self, isize_t u8pos) + { return cutf8_to_index(cstr_str(self), u8pos); } + +STC_INLINE zsview cstr_u8_tail(const cstr* self, isize_t u8len) { + csview sv = cstr_sv(self); + const char* p = &sv.buf[sv.size]; + while (u8len && p != sv.buf) + u8len -= (*--p & 0xC0) != 0x80; + return c_literal(zsview){p, sv.size - (p - sv.buf)}; +} + +STC_INLINE csview cstr_u8_subview(const cstr* self, isize_t u8pos, isize_t u8len) + { return cutf8_subview(cstr_str(self), u8pos, u8len); } + +STC_INLINE cstr_iter cstr_u8_at(const cstr* self, isize_t u8pos) { + cstr_iter it = {.u8={{cutf8_at(cstr_str(self), u8pos)}}}; + it.chr.size = cutf8_decode_codepoint(&it.u8.dec, it.ref, NULL); + if (*it.ref == '\0') it.ref = NULL; + return it; +} + +// utf8 iterator +STC_INLINE cstr_iter cstr_begin(const cstr* self) { + cstr_iter it = {.u8={{cstr_str(self)}}}; + if (*it.ref == '\0') it.ref = NULL; + else it.chr.size = cutf8_decode_codepoint(&it.u8.dec, it.ref, NULL); + return it; +} + +STC_INLINE cstr_iter cstr_end(const cstr* self) { + (void)self; cstr_iter it = {0}; return it; +} + +STC_INLINE void cstr_next(cstr_iter* it) { + it->ref += it->chr.size; + if (*it->ref == '\0') it->ref = NULL; + else it->chr.size = cutf8_decode_codepoint(&it->u8.dec, it->ref, NULL); +} + +STC_INLINE cstr_iter cstr_advance(cstr_iter it, isize_t u8pos) { + it.ref = cutf8_offset(it.ref, u8pos); + if (*it.ref == '\0') it.ref = NULL; + else it.chr.size = cutf8_decode_codepoint(&it.u8.dec, it.ref, NULL); + return it; +} + +STC_INLINE uint32_t cstr_codepoint(const cstr_iter* it) + { return it->u8.dec.codep; } + + +// utf8 case conversion: requires `#define i_import` before including cstr.h in one TU. +extern cstr cstr_tocase_sv(csview sv, int k); + +STC_INLINE cstr cstr_casefold_sv(csview sv) + { return cstr_tocase_sv(sv, 0); } + +STC_INLINE cstr cstr_tolower_sv(csview sv) + { return cstr_tocase_sv(sv, 1); } + +STC_INLINE cstr cstr_toupper_sv(csview sv) + { return cstr_tocase_sv(sv, 2); } + +STC_INLINE cstr cstr_tolower(const char* str) + { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } + +STC_INLINE cstr cstr_toupper(const char* str) + { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } + +STC_INLINE void cstr_lowercase(cstr* self) + { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } + +STC_INLINE void cstr_uppercase(cstr* self) + { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } + +STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) { + csview sv = cstr_sv(self); + isize_t len = c_strlen(sub); + return len <= sv.size && !cutf8_icmp_sv((sv.size = len, sv), c_sv(sub, len)); +} + +STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { + csview sv = cstr_sv(self); + isize_t len = c_strlen(sub); + return len <= sv.size && !cutf8_icmp(sv.buf + sv.size - len, sub); +} + +STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2) + { return cutf8_icmp(cstr_str(s1), cstr_str(s2)); } + +STC_INLINE bool cstr_ieq(const cstr* s1, const cstr* s2) { + csview x = cstr_sv(s1), y = cstr_sv(s2); + return x.size == y.size && !cutf8_icmp_sv(x, y); +} + +STC_INLINE bool cstr_iequals(const cstr* self, const char* str) + { return !cutf8_icmp(cstr_str(self), str); } + +// END utf8 ===== + +STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2) + { return strcmp(cstr_str(s1), cstr_str(s2)); } + +STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { + csview x = cstr_sv(s1), y = cstr_sv(s2); + return x.size == y.size && !c_memcmp(x.buf, y.buf, x.size); +} + +STC_INLINE bool cstr_equals(const cstr* self, const char* str) + { return !strcmp(cstr_str(self), str); } + +STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv) + { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.buf, sv.size); } + +STC_INLINE isize_t cstr_find(const cstr* self, const char* search) { + const char *str = cstr_str(self), *res = strstr((char*)str, search); + return res ? (res - str) : c_NPOS; +} + +STC_INLINE bool cstr_contains(const cstr* self, const char* search) + { return strstr((char*)cstr_str(self), search) != NULL; } + +STC_INLINE bool cstr_contains_sv(const cstr* self, csview search) + { return cstr_find_sv(self, search) != c_NPOS; } + + +STC_INLINE bool cstr_starts_with_sv(const cstr* self, csview sub) { + if (sub.size > cstr_size(self)) return false; + return !c_memcmp(cstr_str(self), sub.buf, sub.size); +} + +STC_INLINE bool cstr_starts_with(const cstr* self, const char* sub) { + const char* str = cstr_str(self); + while (*sub && *str == *sub) ++str, ++sub; + return !*sub; +} + +STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) { + csview sv = cstr_sv(self); + if (sub.size > sv.size) return false; + return !c_memcmp(sv.buf + sv.size - sub.size, sub.buf, sub.size); +} + +STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub) + { return cstr_ends_with_sv(self, c_sv(sub, c_strlen(sub))); } + +STC_INLINE char* cstr_assign(cstr* self, const char* str) + { return cstr_assign_n(self, str, c_strlen(str)); } + +STC_INLINE char* cstr_assign_sv(cstr* self, csview sv) + { return cstr_assign_n(self, sv.buf, sv.size); } + +STC_INLINE char* cstr_copy(cstr* self, cstr s) { + csview sv = cstr_sv(&s); + return cstr_assign_n(self, sv.buf, sv.size); +} + + +STC_INLINE char* cstr_push(cstr* self, const char* chr) + { return cstr_append_n(self, chr, cutf8_chr_size(chr)); } + +STC_INLINE void cstr_pop(cstr* self) { + csview sv = cstr_sv(self); + const char* s = sv.buf + sv.size; + while ((*--s & 0xC0) == 0x80) ; + _cstr_set_size(self, (s - sv.buf)); +} + +STC_INLINE char* cstr_append(cstr* self, const char* str) + { return cstr_append_n(self, str, c_strlen(str)); } + +STC_INLINE char* cstr_append_sv(cstr* self, csview sv) + { return cstr_append_n(self, sv.buf, sv.size); } + +STC_INLINE char* cstr_append_s(cstr* self, cstr s) + { return cstr_append_sv(self, cstr_sv(&s)); } + +#define cstr_join(self, sep, vec) do { \ + struct _vec_s { cstr* data; ptrdiff_t size; } \ + *_vec = (struct _vec_s*)&(vec); \ + (void)sizeof((vec).data == _vec->data && &(vec).size == &_vec->size); \ + cstr_join_sn(self, sep, _vec->data, _vec->size); \ +} while (0); + +#define cstr_join_items(self, sep, ...) \ + cstr_join_n(self, sep, c_make_array(const char*, __VA_ARGS__), c_sizeof((const char*[])__VA_ARGS__)/c_sizeof(char*)) + +STC_INLINE void cstr_join_n(cstr* self, const char* sep, const char* arr[], isize_t n) { + const char* _sep = cstr_is_empty(self) ? "" : sep; + while (n--) { cstr_append(self, _sep); cstr_append(self, *arr++); _sep = sep; } +} +STC_INLINE void cstr_join_sn(cstr* self, const char* sep, const cstr arr[], isize_t n) { + const char* _sep = cstr_is_empty(self) ? "" : sep; + while (n--) { cstr_append(self, _sep); cstr_append_s(self, *arr++); _sep = sep; } +} + + +STC_INLINE void cstr_replace_sv(cstr* self, csview search, csview repl, int32_t count) + { cstr_take(self, cstr_from_replace(cstr_sv(self), search, repl, count)); } + +STC_INLINE void cstr_replace_nfirst(cstr* self, const char* search, const char* repl, int32_t count) + { cstr_replace_sv(self, c_sv(search, c_strlen(search)), c_sv(repl, c_strlen(repl)), count); } + +STC_INLINE void cstr_replace(cstr* self, const char* search, const char* repl) + { cstr_replace_nfirst(self, search, repl, INT32_MAX); } + + +STC_INLINE void cstr_replace_at_sv(cstr* self, isize_t pos, isize_t len, const csview repl) { + char* d = _cstr_internal_move(self, pos + len, pos + repl.size); + c_memcpy(d + pos, repl.buf, repl.size); +} +STC_INLINE void cstr_replace_at(cstr* self, isize_t pos, isize_t len, const char* repl) + { cstr_replace_at_sv(self, pos, len, c_sv(repl, c_strlen(repl))); } + +STC_INLINE void cstr_u8_replace(cstr* self, isize_t u8pos, isize_t u8len, const char* repl) { + const char* s = cstr_str(self); csview span = cutf8_subview(s, u8pos, u8len); + cstr_replace_at(self, span.buf - s, span.size, repl); +} + + +STC_INLINE void cstr_insert_sv(cstr* self, isize_t pos, csview sv) + { cstr_replace_at_sv(self, pos, 0, sv); } + +STC_INLINE void cstr_insert(cstr* self, isize_t pos, const char* str) + { cstr_replace_at_sv(self, pos, 0, c_sv(str, c_strlen(str))); } + +STC_INLINE void cstr_u8_insert(cstr* self, isize_t u8pos, const char* str) + { cstr_insert(self, cutf8_to_index(cstr_str(self), u8pos), str); } + +STC_INLINE bool cstr_getline(cstr *self, FILE *fp) + { return cstr_getdelim(self, '\n', fp); } + +#endif // STC_CSTR_PRV_H_INCLUDED
A
vendor/stc/include/stc/priv/linkage.h
@@ -0,0 +1,77 @@
+/* MIT License + * + * Copyright (c) 2026 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. + */ +#undef STC_API +#undef STC_DEF + +#if !defined i_implement && (defined STC_IMPLEMENT || defined i_import) + #define i_implement +#endif +#if !(defined i_static || defined STC_STATIC) && (defined i_header || defined STC_HEADER || defined i_implement) + #define STC_API extern + #define STC_DEF +#else + #if defined __GNUC__ || defined __clang__ || defined __INTEL_LLVM_COMPILER + #define STC_API static __attribute__((unused)) + #else + #define STC_API static inline + #endif + #define STC_DEF static + #undef i_implement + #define i_implement +#endif + +#if defined i_aux && defined i_allocator + #define _i_aux_alloc +#endif +#ifndef i_allocator + #define i_allocator c +#endif +#ifndef i_free + #define i_malloc c_JOIN(i_allocator, _malloc) + #define i_calloc c_JOIN(i_allocator, _calloc) + #define i_realloc c_JOIN(i_allocator, _realloc) + #define i_free c_JOIN(i_allocator, _free) +#endif + +#if defined __clang__ && !defined __cplusplus + #pragma clang diagnostic push + #pragma clang diagnostic warning "-Wall" + #pragma clang diagnostic warning "-Wextra" + #pragma clang diagnostic warning "-Wpedantic" + #pragma clang diagnostic warning "-Wconversion" + #pragma clang diagnostic warning "-Wwrite-strings" + // ignored + #pragma clang diagnostic ignored "-Wmissing-field-initializers" +#elif defined __GNUC__ && !defined __cplusplus + #pragma GCC diagnostic push + #pragma GCC diagnostic warning "-Wall" + #pragma GCC diagnostic warning "-Wextra" + #pragma GCC diagnostic warning "-Wpedantic" + #pragma GCC diagnostic warning "-Wconversion" + #pragma GCC diagnostic warning "-Wwrite-strings" + // ignored + #pragma GCC diagnostic ignored "-Wclobbered" + #pragma GCC diagnostic ignored "-Wimplicit-fallthrough=3" + #pragma GCC diagnostic ignored "-Wstringop-overflow=" + #pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif
A
vendor/stc/include/stc/priv/linkage2.h
@@ -0,0 +1,42 @@
+/* MIT License + * + * Copyright (c) 2026 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. + */ + +#undef i_aux +#undef _i_aux_alloc + +#undef i_allocator +#undef i_malloc +#undef i_calloc +#undef i_realloc +#undef i_free + +#undef i_static +#undef i_header +#undef i_implement +#undef i_import + +#if defined __clang__ && !defined __cplusplus + #pragma clang diagnostic pop +#elif defined __GNUC__ && !defined __cplusplus + #pragma GCC diagnostic pop +#endif
A
vendor/stc/include/stc/priv/template.h
@@ -0,0 +1,320 @@
+/* MIT License + * + * Copyright (c) 2026 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. + */ +// IWYU pragma: private +#ifndef _i_template +#define _i_template + +#ifndef STC_TEMPLATE_H_INCLUDED +#define STC_TEMPLATE_H_INCLUDED + + #define _c_MEMB(name) c_JOIN(Self, name) + #define _c_DEFTYPES(macro, SELF, ...) macro(SELF, __VA_ARGS__) + #define _m_value _c_MEMB(_value) + #define _m_key _c_MEMB(_key) + #define _m_mapped _c_MEMB(_mapped) + #define _m_rmapped _c_MEMB(_rmapped) + #define _m_raw _c_MEMB(_raw) + #define _m_keyraw _c_MEMB(_keyraw) + #define _m_iter _c_MEMB(_iter) + #define _m_result _c_MEMB(_result) + #define _m_node _c_MEMB(_node) + + #define c_OPTION(flag) ((i_opt) & (flag)) + #define c_declared (1<<0) + #define c_no_atomic (1<<1) + #define c_use_arc2 (1<<2) + #define c_use_rc2 c_use_arc2 + #define c_no_clone (1<<3) + #define c_use_cmp (1<<5) + #define c_use_eq (1<<6) + #define c_use_compare (c_use_cmp | c_use_eq) + #define c_compare_key (1<<7) + #define c_class_key (1<<8) + #define c_class_val (1<<9) + #define c_pro_key (1<<10) + #define c_pro_val (1<<11) + + #define c_use_comp c_use_compare // [deprecated] + #define c_comp_key c_compare_key // [deprecated] + #define c_keycomp c_compare_key // [deprecated] + #define c_cmpclass c_compare_key // [deprecated] + #define c_keyclass c_class_key // [deprecated] + #define c_valclass c_class_val // [deprecated] + #define c_keypro c_pro_key // [deprecated] + #define c_valpro c_pro_val // [deprecated] +#endif +#ifdef i_keycomp // [deprecated] + #define i_compare_key i_keycomp +#elif defined i_comp_key // [deprecated] + #define i_compare_key i_comp_key +#elif defined i_keyclass // [deprecated] + #define i_class_key i_keyclass +#elif defined i_keypro // [deprecated] + #define i_pro_key i_keypro +#endif +#if defined i_valclass // [deprecated] + #define i_class_val i_valclass +#elif defined i_valpro // [deprecated] + #define i_pro_val i_valpro +#endif + +#if defined T && !defined i_type + #define i_type T +#endif +#if defined i_type && c_NUMARGS(i_type) > 1 + #define Self c_GETARG(1, i_type) + #define i_key c_GETARG(2, i_type) + #ifdef _i_is_map + #define i_val c_GETARG(3, i_type) + #if c_NUMARGS(i_type) == 4 + #define i_opt c_GETARG(4, i_type)+0 + #endif + #elif c_NUMARGS(i_type) >= 3 + #define i_opt c_GETARG(3, i_type)+0 + #endif +#elif !defined Self && defined i_type + #define Self i_type +#elif !defined Self + #define Self c_JOIN(_i_prefix, i_tag) +#endif + +#if defined i_aux && c_NUMARGS(i_aux) == 2 + // shorthand for defining i_aux AND i_allocator as a one-liner combo. + #define _i_aux_alloc + #define _i_aux_def c_GETARG(1, i_aux) aux; + #undef i_allocator // override: + #define i_allocator c_GETARG(2, i_aux) +#elif defined i_aux + #define _i_aux_def i_aux aux; +#else + #define _i_aux_def +#endif + +#if c_OPTION(c_declared) + #define i_declared +#endif +#if c_OPTION(c_use_cmp) + #define i_use_cmp +#endif +#if c_OPTION(c_use_eq) + #define i_use_eq +#endif +#if c_OPTION(c_no_clone) || defined _i_is_arc + #define i_no_clone +#endif +#if c_OPTION(c_class_key) + #define i_class_key i_key +#endif +#if c_OPTION(c_class_val) + #define i_class_val i_val +#endif +#if c_OPTION(c_compare_key) + #define i_compare_key i_key + #define i_use_cmp + #define i_use_eq +#endif +#if c_OPTION(c_pro_key) + #define i_pro_key i_key +#endif +#if c_OPTION(c_pro_val) + #define i_pro_val i_val +#endif + +#if defined i_pro_key + #define i_class_key i_pro_key + #define i_compare_key c_JOIN(i_pro_key, _raw) +#endif + +#if defined i_compare_key + #define i_keyraw i_compare_key +#elif defined i_class_key && !defined i_keyraw + // Also bind comparisons functions when c_class_key is specified. + #define i_compare_key i_key +#elif defined i_keyraw && !defined i_keyfrom + // Define _i_no_put when i_keyfrom is not explicitly defined and i_keyraw is. + // In this case, i_keytoraw needs to be defined (may be done later in this file). + #define _i_no_put +#endif + +// Bind to i_key "class members": _clone, _drop, _from and _toraw (when conditions are met). +#if defined i_class_key + #ifndef i_key + #define i_key i_class_key + #endif + #if !defined i_keyclone && !defined i_no_clone + #define i_keyclone c_JOIN(i_class_key, _clone) + #endif + #ifndef i_keydrop + #define i_keydrop c_JOIN(i_class_key, _drop) + #endif + #if !defined i_keyfrom && defined i_keyraw + #define i_keyfrom c_JOIN(i_class_key, _from) + #endif + #if !defined i_keytoraw && defined i_keyraw + #define i_keytoraw c_JOIN(i_class_key, _toraw) + #endif +#endif + +// Define when container has support for sorting (cmp) and linear search (eq) +#if defined i_use_cmp || defined i_cmp || defined i_less || defined _i_sorted + #define _i_has_cmp +#endif +#if defined i_use_eq || defined i_eq || defined i_hash || defined _i_hasher + #define _i_has_eq +#endif + +// Bind to i_compare_key "class members": _cmp, _eq and _hash (when conditions are met). +#if defined i_compare_key + #if !(defined i_cmp || defined i_less) && defined _i_has_cmp + #define i_cmp c_JOIN(i_compare_key, _cmp) + #endif + #if !defined i_eq && defined _i_has_eq + #define i_eq c_JOIN(i_compare_key, _eq) + #endif + #if !(defined i_hash || defined i_no_hash) + #define i_hash c_JOIN(i_compare_key, _hash) + #endif +#endif + +#if !defined i_key + #error "No i_key defined" +#elif defined i_keyraw && !(c_OPTION(c_compare_key) || defined i_keytoraw) + #error "If i_compare_key / i_keyraw is defined, i_keytoraw must be defined too" +#elif !defined i_no_clone && (defined i_keyclone ^ defined i_keydrop) + #error "Both i_keyclone and i_keydrop must be defined, if any (unless i_no_clone defined)." +#elif defined i_from || defined i_drop + #error "i_from / i_drop not supported. Use i_keyfrom/i_keydrop" +#elif defined i_keyto || defined i_valto + #error i_keyto / i_valto not supported. Use i_keytoraw / i_valtoraw +#elif defined i_keyraw && defined i_use_cmp && !defined _i_has_cmp + #error "For smap / sset / pqueue, i_cmp or i_less must be defined when i_keyraw is defined." +#endif + +// Fill in missing i_eq, i_less, i_cmp functions with defaults. +#if !defined i_eq + #define i_eq(x, y) *x == *y // works for integral types + #define _i_has_default_eq +#endif +#if !defined i_less && defined i_cmp + #define i_less(x, y) (i_cmp(x, y)) < 0 +#elif !defined i_less + #define i_less(x, y) *x < *y // works for integral types +#endif +#if !defined i_cmp && defined i_less + #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y)) +#endif +#if !(defined i_hash || defined i_no_hash) + #define i_hash c_default_hash +#endif + +#define _i_no_emplace +#define _i_is_trivial + +#ifndef i_tag + #define i_tag i_key +#endif +#ifndef i_keyfrom + #define i_keyfrom c_default_clone +#else + #undef _i_no_emplace +#endif +#ifndef i_keyraw + #define i_keyraw i_key +#endif +#ifndef i_keytoraw + #define i_keytoraw c_default_toraw +#endif +#ifndef i_keyclone + #define i_keyclone c_default_clone +#endif +#ifndef i_keydrop + #define i_keydrop c_default_drop +#else + #undef _i_is_trivial +#endif + +#if defined _i_is_map // ---- process hashmap/sortedmap value i_val, ... ---- + +#if defined i_pro_val + #define i_class_val i_pro_val + #define i_valraw c_JOIN(i_pro_val, _raw) +#endif + +#ifdef i_class_val + #ifndef i_val + #define i_val i_class_val + #endif + #if !defined i_valclone && !defined i_no_clone + #define i_valclone c_JOIN(i_class_val, _clone) + #endif + #ifndef i_valdrop + #define i_valdrop c_JOIN(i_class_val, _drop) + #endif + #if !defined i_valfrom && defined i_valraw + #define i_valfrom c_JOIN(i_class_val, _from) + #endif + #if !defined i_valtoraw && defined i_valraw + #define i_valtoraw c_JOIN(i_class_val, _toraw) + #endif +#endif + +#ifndef i_val + #error "i_val* must be defined for maps" +#elif defined i_valraw && !defined i_valtoraw + #error "If i_valraw is defined, i_valtoraw must be defined too" +#elif !defined i_no_clone && (defined i_valclone ^ defined i_valdrop) + #error "Both i_valclone and i_valdrop must be defined, if any" +#endif + +#ifndef i_valfrom + #define i_valfrom c_default_clone + #ifdef i_valraw + #define _i_no_put + #endif +#else + #undef _i_no_emplace +#endif +#ifndef i_valraw + #define i_valraw i_val +#endif +#ifndef i_valtoraw + #define i_valtoraw c_default_toraw +#endif +#ifndef i_valclone + #define i_valclone c_default_clone +#endif +#ifndef i_valdrop + #define i_valdrop c_default_drop +#else + #undef _i_is_trivial +#endif + +#endif // !_i_is_map + +#ifndef i_val + #define i_val i_key +#endif +#ifndef i_valraw + #define i_valraw i_keyraw +#endif +#endif // STC_TEMPLATE_H_INCLUDED
A
vendor/stc/include/stc/priv/template2.h
@@ -0,0 +1,77 @@
+/* MIT License + * + * Copyright (c) 2026 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. + */ +// IWYU pragma: private +#undef T // alias for i_type +#undef i_type +#undef i_class +#undef i_tag +#undef i_opt +#undef i_capacity + +#undef i_compare_key // define i_keyraw, and bind i_cmp, i_eq, i_hash "class members" +#undef i_class_key +#undef i_pro_key +#undef i_cmpclass // [deprecated] +#undef i_keycomp // [deprecated] +#undef i_keyclass // [deprecated] +#undef i_keypro // [deprecated] + +#undef i_key +#undef i_keyclone +#undef i_keydrop +#undef i_keyraw +#undef i_keyfrom +#undef i_keytoraw +#undef i_cmp +#undef i_less +#undef i_eq +#undef i_hash + +#undef i_class_val +#undef i_pro_val +#undef i_valclass // [deprecated] +#undef i_valpro // [deprecated] + +#undef i_val +#undef i_valclone +#undef i_valdrop +#undef i_valraw +#undef i_valfrom +#undef i_valtoraw + +#undef i_use_cmp +#undef i_use_eq +#undef i_no_hash +#undef i_no_clone +#undef i_declared + +#undef _i_no_put +#undef _i_no_emplace +#undef _i_is_trivial +#undef _i_aux_def +#undef _i_has_cmp +#undef _i_has_eq +#undef _i_has_default_eq +#undef _i_prefix +#undef _i_template +#undef Self
A
vendor/stc/include/stc/priv/utf8_decode.h
@@ -0,0 +1,41 @@
+/* MIT License + * + * Copyright (c) 2026 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_UTF8_DECODE_H_INCLUDED +#define STC_UTF8_DECODE_H_INCLUDED + +enum { cutf8_ACCEPT=0, cutf8_REJECT=12 }; + +extern int cutf8_decode_codepoint(cutf8_decode_t* d, const char* s, const char* end); // s < end +extern uint32_t cutf8_peek(const char* s); + +static inline uint32_t cutf8_decode(cutf8_decode_t* d, const uint32_t byte) { + /* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */ + extern const uint8_t cutf8_dtab[]; /* utf8_decode.c */ + + const uint32_t type = cutf8_dtab[byte]; + d->codep = d->state ? (byte & 0x3fu) | (d->codep << 6) + : (0xffU >> type) & byte; + return d->state = cutf8_dtab[256 + d->state + type]; +} + +#endif // STC_UTF8_DECODE_H_INCLUDED
A
vendor/stc/include/stc/priv/utf8_prv.h
@@ -0,0 +1,172 @@
+/* MIT License + * + * Copyright (c) 2026 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. + */ +// IWYU pragma: private, include "stc/utf8.h" +#ifndef STC_UTF8_PRV_H_INCLUDED +#define STC_UTF8_PRV_H_INCLUDED + +#include <ctype.h> + +// The following functions assume valid utf8 strings: + +/* number of bytes in a utf8 codepoint given its first byte */ +STC_INLINE int cutf8_chr_size(const char *s) { + // Every nibble represents the utf8 length given the + // first 4 bits of a utf8 encoded byte. + return (int)((0x4322000011111111ull >> (((uint8_t)*s >> 4) << 2)) & 0xf); +} + +/* number of codepoints in the utf8 string s */ +STC_INLINE isize_t cutf8_count(const char *s) { + isize_t size = 0; + while (*s) + size += (*++s & 0xC0) != 0x80; + return size; +} + +STC_INLINE isize_t cutf8_count_n(const char *s, isize_t nbytes) { + isize_t size = 0; + while (nbytes-- != 0 && *s != 0) { + size += (*++s & 0xC0) != 0x80; + } + return size; +} + +STC_INLINE const char* cutf8_at(const char *s, isize_t u8pos) { + while ((u8pos > 0) & (*s != 0)) + u8pos -= (*++s & 0xC0) != 0x80; + c_assert(u8pos == 0); + return s; +} + +STC_INLINE const char* cutf8_offset(const char* s, isize_t u8pos) { + int inc = 1; + if (u8pos < 0) u8pos = -u8pos, inc = -1; + while (u8pos && *s) + u8pos -= (*(s += inc) & 0xC0) != 0x80; + c_assert(u8pos == 0); + return s; +} + +STC_INLINE isize_t cutf8_to_index(const char* s, isize_t u8pos) + { return cutf8_at(s, u8pos) - s; } + +STC_INLINE csview cutf8_subview(const char *s, isize_t u8pos, isize_t u8len) { + csview span; + span.buf = cutf8_at(s, u8pos); + span.size = cutf8_to_index(span.buf, u8len); + return span; +} + +// ------------------------------------------------------ +// Functions below must be linked with utf8_prv.c and utf8_decode.c +// To call them, either define i_import before including +// one of cstr, csview, zsview, or link with src/libstc.a + +#include "utf8_decode.h" + +extern bool cutf8_valid(const char* s); +extern bool cutf8_valid_n(const char* s, isize_t nbytes); +extern int cutf8_encode(char *out, uint32_t c); +extern uint32_t cutf8_casefold(uint32_t c); +extern uint32_t cutf8_tolower(uint32_t c); +extern uint32_t cutf8_toupper(uint32_t c); +extern int cutf8_icmp_sv(const csview s1, const csview s2); + +STC_INLINE uint32_t cutf8_peek_at(const char* s, isize_t offset) + { return cutf8_peek(cutf8_offset(s, offset)); } + +STC_INLINE bool cutf8_isupper(uint32_t c) + { return c < 128 ? (c >= 'A') & (c <= 'Z') : cutf8_tolower(c) != c; } + +STC_INLINE bool cutf8_islower(uint32_t c) + { return c < 128 ? (c >= 'a') & (c <= 'z') : cutf8_toupper(c) != c; } + +/* case-insensitive utf8 string comparison */ +STC_INLINE int cutf8_icmp(const char* s1, const char* s2) { + return cutf8_icmp_sv(c_sv(s1, INTPTR_MAX), c_sv(s2, INTPTR_MAX)); +} + +// ------------------------------------------------------ +// Functions below must be linked with ucd_prv.c content + +enum cutf8_group { + U8G_Cc, U8G_L, U8G_Lm, U8G_Lt, U8G_Nd, U8G_Nl, U8G_No, + U8G_P, U8G_Pc, U8G_Pd, U8G_Pe, U8G_Pf, U8G_Pi, U8G_Ps, + U8G_Sc, U8G_Sk, U8G_Sm, U8G_Zl, U8G_Zp, U8G_Zs, + U8G_Arabic, U8G_Bengali, U8G_Cyrillic, + U8G_Devanagari, U8G_Georgian, U8G_Greek, + U8G_Han, U8G_Hiragana, U8G_Katakana, + U8G_Latin, U8G_Thai, + U8G_SIZE +}; + +extern bool cutf8_isgroup(int group, uint32_t c); + +STC_INLINE bool cutf8_isdigit(uint32_t c) + { return c < 128 ? (c >= '0') & (c <= '9') : cutf8_isgroup(U8G_Nd, c); } + +STC_INLINE bool cutf8_isalpha(uint32_t c) + { return (c < 128 ? isalpha((int)c) != 0 : cutf8_isgroup(U8G_L, c)); } + +STC_INLINE bool cutf8_iscased(uint32_t c) { + if (c < 128) return isalpha((int)c) != 0; + return cutf8_toupper(c) != c || cutf8_tolower(c) != c || cutf8_isgroup(U8G_Lt, c); +} + +STC_INLINE bool cutf8_isalnum(uint32_t c) { + if (c < 128) return isalnum((int)c) != 0; + return cutf8_isgroup(U8G_L, c) || cutf8_isgroup(U8G_Nd, c); +} + +STC_INLINE bool cutf8_isword(uint32_t c) { + if (c < 128) return (isalnum((int)c) != 0) | (c == '_'); + return cutf8_isgroup(U8G_L, c) || cutf8_isgroup(U8G_Nd, c) || cutf8_isgroup(U8G_Pc, c); +} + +STC_INLINE bool cutf8_isblank(uint32_t c) { + if (c < 128) return (c == ' ') | (c == '\t'); + return cutf8_isgroup(U8G_Zs, c); +} + +STC_INLINE bool cutf8_isspace(uint32_t c) { + if (c < 128) return isspace((int)c) != 0; + return ((c == 8232) | (c == 8233)) || cutf8_isgroup(U8G_Zs, c); +} + +#define c_lowerbound(T, c, at, less, N, ret) do { \ + int _n = N, _i = 0, _mid = _n/2; \ + T _c = c; \ + while (_n > 0) { \ + if (less(at((_i + _mid)), &_c)) { \ + _i += _mid + 1; \ + _n -= _mid + 1; \ + _mid = _n*7/8; \ + } else { \ + _n = _mid; \ + _mid = _n/8; \ + } \ + } \ + *(ret) = _i; \ +} while (0) + +#endif // STC_UTF8_PRV_H_INCLUDED
A
vendor/stc/include/stc/sys/finalize.h
@@ -0,0 +1,5 @@
+#ifndef i_extend + #include "../priv/linkage2.h" + #include "../priv/template2.h" +#endif +#undef i_extend
A
vendor/stc/include/stc/types.h
@@ -0,0 +1,234 @@
+/* MIT License + * + * Copyright (c) 2026 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_TYPES_H_INCLUDED +#define STC_TYPES_H_INCLUDED + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> + +#define c_true(...) __VA_ARGS__ +#define c_false(...) + +#define declare_rc(C, KEY) declare_arc(C, KEY) +#define declare_rc2(SELF, VAL) declare_arc2(SELF, VAL) +#define declare_list(C, KEY) _declare_list(C, KEY,) +#define declare_stack(C, KEY) _declare_stack(C, KEY,) +#define declare_vec(C, KEY) _declare_stack(C, KEY,) +#define declare_pqueue(C, KEY) _declare_stack(C, KEY,) +#define declare_queue(C, KEY) _declare_queue(C, KEY,) +#define declare_deque(C, KEY) _declare_queue(C, KEY,) +#define declare_hashmap(C, KEY, VAL) _declare_htable(C, c_true, c_false, KEY, VAL,) +#define declare_hashset(C, KEY) _declare_htable(C, c_false, c_true, KEY, KEY,) +#define declare_sortedmap(C, KEY, VAL) _declare_aatree(C, c_true, c_false, KEY, VAL,) +#define declare_sortedset(C, KEY) _declare_aatree(C, c_false, c_true, KEY, KEY,) + +#define declare_list_aux(C, KEY, AUX) _declare_list(C, KEY, AUX aux;) +#define declare_stack_aux(C, KEY, AUX) _declare_stack(C, KEY, AUX aux;) +#define declare_vec_aux(C, KEY, AUX) _declare_stack(C, KEY, AUX aux;) +#define declare_pqueue_aux(C, KEY, AUX) _declare_stack(C, KEY, AUX aux;) +#define declare_queue_aux(C, KEY, AUX) _declare_queue(C, KEY, AUX aux;) +#define declare_deque_aux(C, KEY, AUX) _declare_queue(C, KEY, AUX aux;) +#define declare_hashmap_aux(C, KEY, VAL) _declare_htable(C, c_true, c_false, KEY, VAL, AUX aux;) +#define declare_hashset_aux(C, KEY) _declare_htable(C, c_false, c_true, KEY, KEY, AUX aux;) +#define declare_sortedmap_aux(C, KEY, VAL) _declare_aatree(C, c_true, c_false, KEY, VAL, AUX aux;) +#define declare_sortedset_aux(C, KEY) _declare_aatree(C, c_false, c_true, KEY, KEY, AUX aux;) + +typedef struct { uint32_t state, codep; } cutf8_decode_t; + +// csview : non-null terminated string view +typedef const char csview_value; +typedef struct csview { + csview_value* buf; + ptrdiff_t size; +} csview; + +typedef union { + struct { csview chr; csview_value* end; cutf8_decode_t dec; } u8; + csview chr; + csview_value* ref; +} csview_iter; + +#define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) +#define c_sv_1(STRLIT) c_sv_2(STRLIT, c_litstrlen(STRLIT)) +#define c_sv_2(str, n) (c_literal(csview){str, n}) +#define c_svfmt "%.*s" +#define c_svarg(sv) (int)(sv).size, (sv).buf // printf(c_svfmt "\n", c_svarg(sv)); + +// zsview : zero-terminated string view +typedef csview_value zsview_value; +typedef struct zsview { + zsview_value* str; + ptrdiff_t size; +} zsview; + +typedef union { + struct { csview chr; cutf8_decode_t dec; } u8; + csview chr; + zsview_value* ref; +} zsview_iter; + +#define c_zv(literal) (c_literal(zsview){literal, c_litstrlen(literal)}) + +// cstr : zero-terminated owning string (short string optimized - sso) +typedef char cstr_value; +typedef struct { cstr_value* data; intptr_t size, cap; } cstr_buf; +typedef union cstr { + struct { cstr_value data[ sizeof(cstr_buf) - 1 ]; uint8_t size; } sml; + struct { cstr_value* data; uintptr_t size; uintptr_t ncap; } lon; +} cstr; + +typedef union { + struct { csview chr; cutf8_decode_t dec; } u8; + csview chr; // utf8 character/codepoint + const cstr_value* ref; +} cstr_iter; + +// 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 declare_arc(SELF, VAL) \ + typedef VAL SELF##_value; \ + typedef struct SELF##_ctrl SELF##_ctrl; \ +\ + typedef union SELF { \ + SELF##_value* get; \ + SELF##_ctrl* ctrl; \ + } SELF + +#define declare_arc2(SELF, VAL) \ + typedef VAL SELF##_value; \ + typedef struct SELF##_ctrl SELF##_ctrl; \ +\ + typedef struct SELF { \ + SELF##_value* get; \ + SELF##_ctrl* ctrl2; \ + } SELF + +#define declare_box(SELF, VAL) \ + typedef VAL SELF##_value; \ +\ + typedef struct SELF { \ + SELF##_value* get; \ + } SELF + +#define _declare_queue(SELF, VAL, AUXDEF) \ + typedef VAL SELF##_value; \ +\ + typedef struct SELF { \ + SELF##_value *cbuf; \ + ptrdiff_t start, end, capmask; \ + AUXDEF \ + } SELF; \ +\ + typedef struct { \ + SELF##_value *ref; \ + ptrdiff_t pos; \ + const SELF* _s; \ + } SELF##_iter + +#define _declare_list(SELF, VAL, AUXDEF) \ + typedef VAL SELF##_value; \ + typedef struct SELF##_node SELF##_node; \ +\ + typedef struct { \ + SELF##_value *ref; \ + SELF##_node *const *_last, *prev; \ + } SELF##_iter; \ +\ + typedef struct SELF { \ + SELF##_node *last; \ + AUXDEF \ + } SELF + +#define _declare_htable(SELF, MAP_ONLY, SET_ONLY, KEY, VAL, AUXDEF) \ + typedef KEY SELF##_key; \ + typedef VAL SELF##_mapped; \ +\ + typedef SET_ONLY( SELF##_key ) \ + MAP_ONLY( struct SELF##_value ) \ + SELF##_value, SELF##_entry; \ +\ + typedef struct { \ + SELF##_value *ref; \ + size_t idx; \ + bool inserted; \ + uint8_t hashx; \ + uint16_t dist; \ + } SELF##_result; \ +\ + typedef struct { \ + SELF##_value *ref, *_end; \ + struct hmap_meta *_mref; \ + } SELF##_iter; \ +\ + typedef struct SELF { \ + SELF##_value* table; \ + struct hmap_meta* meta; \ + ptrdiff_t size, bucket_count; \ + AUXDEF \ + } SELF + +#define _declare_aatree(SELF, MAP_ONLY, SET_ONLY, KEY, VAL, AUXDEF) \ + typedef KEY SELF##_key; \ + typedef VAL SELF##_mapped; \ + typedef struct SELF##_node SELF##_node; \ +\ + typedef SET_ONLY( SELF##_key ) \ + MAP_ONLY( struct SELF##_value ) \ + SELF##_value, SELF##_entry; \ +\ + typedef struct { \ + SELF##_value *ref; \ + bool inserted; \ + } SELF##_result; \ +\ + typedef struct { \ + SELF##_value *ref; \ + SELF##_node *_d; \ + int _top; \ + int32_t _tn, _st[36]; \ + } SELF##_iter; \ +\ + typedef struct SELF { \ + SELF##_node *nodes; \ + int32_t root, disp, head, size, capacity; \ + AUXDEF \ + } SELF + +#define _declare_inplace_stack(SELF, VAL, CAP, AUXDEF) \ + typedef VAL SELF##_value; \ + typedef struct { SELF##_value *ref, *end; } SELF##_iter; \ + typedef struct SELF { ptrdiff_t size; SELF##_value data[CAP]; AUXDEF } SELF + +#define _declare_stack(SELF, VAL, AUXDEF) \ + typedef VAL SELF##_value; \ + typedef struct { SELF##_value *ref, *end; } SELF##_iter; \ + typedef struct SELF { SELF##_value *data; ptrdiff_t size, capacity; AUXDEF } SELF + +#endif // STC_TYPES_H_INCLUDED
A
vendor/stc/include/stc/vec.h
@@ -0,0 +1,403 @@
+/* MIT License + * + * Copyright (c) 2026 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. + */ + +/* +#define i_implement +#include <stc/cstr.h> +#include <stc/types.h> + +declare_vec(vec_i32, int); + +typedef struct MyStruct { + vec_i32 int_vec; + cstr name; +} MyStruct; + +#define i_key float +#include <stc/vec.h> + +#define i_pro_key cstr // cstr is a "pro"-type +#include <stc/vec.h> + +#define T vec_i32, int32_t, (c_declared) +#include <stc/vec.h> + +int main(void) { + vec_i32 vec = {0}; + vec_i32_push(&vec, 123); + vec_i32_drop(&vec); + + vec_float fvec = {0}; + vec_float_push(&fvec, 123.3); + vec_float_drop(&fvec); + + vec_cstr svec = {0}; + vec_cstr_emplace(&svec, "Hello, friend"); + vec_cstr_drop(&svec); +} +*/ +#include "priv/linkage.h" +#include "types.h" + +#ifndef STC_VEC_H_INCLUDED +#define STC_VEC_H_INCLUDED +#include "common.h" +#include <stdlib.h> + +#define _it2_ptr(it1, it2) (it1.ref && !it2.ref ? it1.end : it2.ref) +#define _it_ptr(it) (it.ref ? it.ref : it.end) +#endif // STC_VEC_H_INCLUDED + +#ifndef _i_prefix + #define _i_prefix vec_ +#endif +#include "priv/template.h" + +#ifndef i_declared + _c_DEFTYPES(_declare_stack, Self, i_key, _i_aux_def); +#endif +typedef i_keyraw _m_raw; +STC_API void _c_MEMB(_drop)(const Self* cself); +STC_API void _c_MEMB(_clear)(Self* self); +STC_API bool _c_MEMB(_reserve)(Self* self, isize_t cap); +STC_API bool _c_MEMB(_resize)(Self* self, isize_t size, _m_value null); +STC_API _m_iter _c_MEMB(_erase_n)(Self* self, isize_t idx, isize_t n); +STC_API _m_iter _c_MEMB(_insert_uninit)(Self* self, isize_t idx, isize_t n); +#if defined _i_has_eq +STC_API _m_iter _c_MEMB(_find_in)(const Self* self, _m_iter it1, _m_iter it2, _m_raw raw); +#endif // _i_has_eq + +STC_INLINE void _c_MEMB(_value_drop)(const Self* self, _m_value* val) + { (void)self; i_keydrop(val); } + +STC_INLINE Self _c_MEMB(_move)(Self *self) { + Self m = *self; + self->capacity = self->size = 0; + self->data = NULL; + return m; +} + +STC_INLINE void _c_MEMB(_take)(Self *self, Self unowned) { + _c_MEMB(_drop)(self); + *self = unowned; +} + +STC_INLINE _m_value* _c_MEMB(_push)(Self* self, _m_value value) { + if (self->size == self->capacity) + if (!_c_MEMB(_reserve)(self, self->size*2 + 4)) + return NULL; + _m_value *v = self->data + self->size++; + *v = value; + return v; +} + +#ifndef _i_no_put +STC_INLINE void _c_MEMB(_put_n)(Self* self, const _m_raw* raw, isize_t n) + { while (n--) _c_MEMB(_push)(self, i_keyfrom((*raw))), ++raw; } +#endif + +#ifndef _i_no_emplace +STC_API _m_iter _c_MEMB(_emplace_n)(Self* self, isize_t idx, const _m_raw raw[], isize_t n); + +STC_INLINE _m_value* _c_MEMB(_emplace)(Self* self, _m_raw raw) + { return _c_MEMB(_push)(self, i_keyfrom(raw)); } + +STC_INLINE _m_value* _c_MEMB(_emplace_back)(Self* self, _m_raw raw) + { return _c_MEMB(_push)(self, i_keyfrom(raw)); } + +STC_INLINE _m_iter _c_MEMB(_emplace_at)(Self* self, _m_iter it, _m_raw raw) + { return _c_MEMB(_emplace_n)(self, _it_ptr(it) - self->data, &raw, 1); } +#endif // !_i_no_emplace + +#ifndef i_no_clone +STC_API void _c_MEMB(_copy)(Self* self, const Self* other); +STC_API _m_iter _c_MEMB(_copy_to)(Self* self, isize_t idx, const _m_value arr[], isize_t n); +STC_API Self _c_MEMB(_clone)(Self vec); +STC_INLINE _m_value _c_MEMB(_value_clone)(const Self* self, _m_value val) + { (void)self; return i_keyclone(val); } +#endif // !i_no_clone + +STC_INLINE isize_t _c_MEMB(_size)(const Self* self) { return self->size; } +STC_INLINE isize_t _c_MEMB(_capacity)(const Self* self) { return self->capacity; } +STC_INLINE bool _c_MEMB(_is_empty)(const Self* self) { return !self->size; } +STC_INLINE _m_raw _c_MEMB(_value_toraw)(const _m_value* val) { return i_keytoraw(val); } +STC_INLINE const _m_value* _c_MEMB(_front)(const Self* self) { return self->data; } +STC_INLINE _m_value* _c_MEMB(_front_mut)(Self* self) { return self->data; } +STC_INLINE const _m_value* _c_MEMB(_back)(const Self* self) { return &self->data[self->size - 1]; } +STC_INLINE _m_value* _c_MEMB(_back_mut)(Self* self) { return &self->data[self->size - 1]; } + +STC_INLINE void _c_MEMB(_pop)(Self* self) + { c_assert(self->size); _m_value* p = &self->data[--self->size]; i_keydrop(p); } +STC_INLINE _m_value _c_MEMB(_pull)(Self* self) + { c_assert(self->size); return self->data[--self->size]; } +STC_INLINE _m_value* _c_MEMB(_push_back)(Self* self, _m_value value) + { return _c_MEMB(_push)(self, value); } +STC_INLINE void _c_MEMB(_pop_back)(Self* self) { _c_MEMB(_pop)(self); } + +#ifndef _i_aux_alloc + STC_INLINE Self _c_MEMB(_init)(void) + { return c_literal(Self){0}; } + + STC_INLINE Self _c_MEMB(_with_capacity)(isize_t cap) + { Self out = {_i_new_n(_m_value, cap), 0, cap}; return out; } + + STC_INLINE Self _c_MEMB(_with_size_uninit)(isize_t size) + { Self out = {_i_new_n(_m_value, size), size, size}; return out; } + + STC_INLINE Self _c_MEMB(_with_size)(isize_t size, _m_raw default_raw) { + Self out = {_i_new_n(_m_value, size), size, size}; + while (size) out.data[--size] = i_keyfrom(default_raw); + return out; + } + + #ifndef _i_no_put + STC_INLINE Self _c_MEMB(_from_n)(const _m_raw* raw, isize_t n) { + Self out = _c_MEMB(_with_capacity)(n); + _c_MEMB(_put_n)(&out, raw, n); return out; + } + #endif +#endif + +STC_INLINE void _c_MEMB(_shrink_to_fit)(Self* self) + { _c_MEMB(_reserve)(self, c_NPOS); } + +STC_INLINE _m_iter +_c_MEMB(_insert_n)(Self* self, const isize_t idx, const _m_value arr[], const isize_t n) { + _m_iter it = _c_MEMB(_insert_uninit)(self, idx, n); + if (it.ref) + c_memcpy(it.ref, arr, n*c_sizeof *arr); + return it; +} + +STC_INLINE _m_iter _c_MEMB(_insert_at)(Self* self, _m_iter it, const _m_value value) { + return _c_MEMB(_insert_n)(self, _it_ptr(it) - self->data, &value, 1); +} + +STC_INLINE _m_iter _c_MEMB(_erase_at)(Self* self, _m_iter it) { + return _c_MEMB(_erase_n)(self, it.ref - self->data, 1); +} + +STC_INLINE _m_iter _c_MEMB(_erase_range)(Self* self, _m_iter i1, _m_iter i2) { + return _c_MEMB(_erase_n)(self, i1.ref - self->data, _it2_ptr(i1, i2) - i1.ref); +} + +STC_INLINE const _m_value* _c_MEMB(_at)(const Self* self, const isize_t idx) { + c_assert(c_uless(idx, self->size)); return self->data + idx; +} + +STC_INLINE _m_value* _c_MEMB(_at_mut)(Self* self, const isize_t idx) { + c_assert(c_uless(idx, self->size)); return self->data + idx; +} + +// iteration + +STC_INLINE _m_iter _c_MEMB(_begin)(const Self* self) { + _m_iter it = {(_m_value*)self->data, (_m_value*)self->data}; + if (self->size) it.end += self->size; + else it.ref = NULL; + return it; +} + +STC_INLINE _m_iter _c_MEMB(_rbegin)(const Self* self) { + _m_iter it = {(_m_value*)self->data, (_m_value*)self->data}; + if (self->size) { it.ref += self->size - 1; it.end -= 1; } + else it.ref = NULL; + return it; +} + +STC_INLINE _m_iter _c_MEMB(_end)(const Self* self) + { (void)self; _m_iter it = {0}; return it; } + +STC_INLINE _m_iter _c_MEMB(_rend)(const Self* self) + { (void)self; _m_iter it = {0}; return it; } + +STC_INLINE void _c_MEMB(_next)(_m_iter* it) + { if (++it->ref == it->end) it->ref = NULL; } + +STC_INLINE void _c_MEMB(_rnext)(_m_iter* it) + { if (--it->ref == it->end) it->ref = NULL; } + +STC_INLINE _m_iter _c_MEMB(_advance)(_m_iter it, size_t n) { + if ((it.ref += n) >= it.end) it.ref = NULL; + return it; +} + +STC_INLINE isize_t _c_MEMB(_index)(const Self* self, _m_iter it) + { return (it.ref - self->data); } + +STC_INLINE void _c_MEMB(_adjust_end_)(Self* self, isize_t n) + { self->size += n; } + +#if defined _i_has_eq +STC_INLINE _m_iter _c_MEMB(_find)(const Self* self, _m_raw raw) + { return _c_MEMB(_find_in)(self, _c_MEMB(_begin)(self), _c_MEMB(_end)(self), raw); } + +STC_INLINE bool _c_MEMB(_contains)(const Self* self, _m_raw raw) + { return _c_MEMB(_find)(self, raw).ref != NULL; } + +STC_INLINE bool _c_MEMB(_eq)(const Self* self, const Self* other) { +#ifdef _i_has_default_eq + return c_memcmp(self->data, other->data, self->size*c_sizeof(_m_value)) == 0; +#else + if (self->size != other->size) return false; + for (isize_t i = 0; i < self->size; ++i) { + const _m_raw _rx = i_keytoraw((self->data+i)), _ry = i_keytoraw((other->data+i)); + if (!(i_eq((&_rx), (&_ry)))) return false; + } + return true; +#endif +} +#endif // _i_has_eq + +#if defined _i_has_cmp +#include "priv/sort_prv.h" +#endif // _i_has_cmp + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined i_implement + +STC_DEF void +_c_MEMB(_clear)(Self* self) { + if (self->size == 0) return; + _m_value *p = self->data + self->size; + while (p-- != self->data) { i_keydrop(p); } + self->size = 0; +} + +STC_DEF void +_c_MEMB(_drop)(const Self* cself) { + Self* self = (Self*)cself; + if (self->capacity == 0) + return; + _c_MEMB(_clear)(self); + _i_free_n(self->data, self->capacity); +} + +STC_DEF bool +_c_MEMB(_reserve)(Self* self, const isize_t cap) { + isize_t n = cap == c_NPOS ? self->size : cap; + if ((cap > self->capacity) & (n != self->capacity)) { + _m_value* d = (_m_value*)_i_realloc_n(self->data, self->capacity, n); + if (d == NULL) return false; + self->data = d; + self->capacity = n; + } + return self->data != NULL; +} + +STC_DEF bool +_c_MEMB(_resize)(Self* self, const isize_t len, _m_value null) { + if (!_c_MEMB(_reserve)(self, len)) + return false; + const isize_t n = self->size; + for (isize_t i = len; i < n; ++i) + { i_keydrop((self->data + i)); } + for (isize_t i = n; i < len; ++i) + self->data[i] = null; + self->size = len; + return true; +} + +STC_DEF _m_iter +_c_MEMB(_insert_uninit)(Self* self, const isize_t idx, const isize_t n) { + if (self->size + n >= self->capacity) + if (!_c_MEMB(_reserve)(self, self->size*3/2 + n)) + return _c_MEMB(_end)(self); + + _m_value *pos = self->data + idx; + c_memmove(pos + n, pos, (self->size - idx)*c_sizeof *pos); + self->size += n; + return c_literal(_m_iter){pos, self->data + self->size}; +} + +STC_DEF _m_iter +_c_MEMB(_erase_n)(Self* self, const isize_t idx, const isize_t len) { + c_assert(idx + len <= self->size); + _m_value* d = self->data + idx, *p = d, *end = self->data + self->size; + for (isize_t i = 0; i < len; ++i, ++p) + { i_keydrop(p); } + memmove(d, p, (size_t)(end - p)*sizeof *d); + self->size -= len; + return c_literal(_m_iter){p == end ? NULL : d, end - len}; +} + +#ifndef i_no_clone +STC_DEF void +_c_MEMB(_copy)(Self* self, const Self* other) { + if (self == other) return; + _c_MEMB(_clear)(self); + _c_MEMB(_reserve)(self, other->size); + self->size = other->size; + for (c_range(i, other->size)) + self->data[i] = i_keyclone((other->data[i])); +} + +STC_DEF Self +_c_MEMB(_clone)(Self vec) { + Self out = vec, *self = &out; (void)self; + out.data = NULL; out.size = out.capacity = 0; + _c_MEMB(_reserve)(&out, vec.size); + out.size = vec.size; + for (c_range(i, vec.size)) + out.data[i] = i_keyclone(vec.data[i]); + return out; +} + +STC_DEF _m_iter +_c_MEMB(_copy_to)(Self* self, const isize_t idx, + const _m_value arr[], const isize_t n) { + _m_iter it = _c_MEMB(_insert_uninit)(self, idx, n); + if (it.ref) + for (_m_value* p = it.ref, *q = p + n; p != q; ++arr) + *p++ = i_keyclone((*arr)); + return it; +} +#endif // !i_no_clone + +#ifndef _i_no_emplace +STC_DEF _m_iter +_c_MEMB(_emplace_n)(Self* self, const isize_t idx, const _m_raw raw[], isize_t n) { + _m_iter it = _c_MEMB(_insert_uninit)(self, idx, n); + if (it.ref) + for (_m_value* p = it.ref; n--; ++raw, ++p) + *p = i_keyfrom((*raw)); + return it; +} +#endif // !_i_no_emplace + +#if defined _i_has_eq +STC_DEF _m_iter +_c_MEMB(_find_in)(const Self* self, _m_iter i1, _m_iter i2, _m_raw raw) { + (void)self; + const _m_value* p2 = _it2_ptr(i1, i2); + for (; i1.ref != p2; ++i1.ref) { + const _m_raw r = i_keytoraw(i1.ref); + if (i_eq((&raw), (&r))) + return i1; + } + i2.ref = NULL; + return i2; +} +#endif // _i_has_eq +#endif // i_implement +#include "sys/finalize.h"
A
vendor/stc/src/cstr_core.c
@@ -0,0 +1,2 @@
+#define STC_CSTR_CORE +#include "../include/stc/cstr.h"
A
vendor/stc/src/cstr_misc.c
@@ -0,0 +1,2 @@
+#define STC_CSTR_MISC +#include "../include/stc/cstr.h"
A
vendor/stc/stc.c
@@ -0,0 +1,4 @@
+// Selectively including some files out of STC v6.0 RC4 +// Commit 6574a39b26cf24c32fc58ed585209b35c34c7998 +#include "src/cstr_core.c" +#include "src/cstr_misc.c"