diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index e1294317..0c268f2c 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -1,7 +1,7 @@ name: Benchmark jobs: benchmark: - runs-on: ubuntu-latest + runs-on: codspeed-macro steps: - name: Checkout Repo uses: actions/checkout@v4 diff --git a/pyproject.toml b/pyproject.toml index 8641d1f9..56a02f38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,6 @@ build-backend = "poetry.core.masonry.api" [tool.ruff] extend-exclude = [ "tests/reference", - "src/finchlite/codegen/stc", ] line-length = 88 @@ -65,4 +64,4 @@ section-order = [ [tool.mypy] ignore_missing_imports = true -exclude = ["tests/reference", "src/finchlite/codegen/stc", "(^|/)benchmarks/"] +exclude = ["tests/reference", "(^|/)benchmarks/"] diff --git a/src/finchlite/codegen/__init__.py b/src/finchlite/codegen/__init__.py index 7a43d28a..b58b898a 100644 --- a/src/finchlite/codegen/__init__.py +++ b/src/finchlite/codegen/__init__.py @@ -1,10 +1,6 @@ from .buffers import ( - CHashTable, - CHashTableFType, MallocBuffer, MallocBufferFType, - NumbaHashTable, - NumbaHashTableFType, NumpyBuffer, NumpyBufferFType, SafeBuffer, @@ -39,8 +35,6 @@ "CCode", "CCompiler", "CGenerator", - "CHashTable", - "CHashTableFType", "CKernel", "CLibrary", "CLowerer", @@ -52,8 +46,6 @@ "NumbaCode", "NumbaCompiler", "NumbaGenerator", - "NumbaHashTable", - "NumbaHashTableFType", "NumbaKernel", "NumbaLibrary", "NumbaLowerer", diff --git a/src/finchlite/codegen/buffers/__init__.py b/src/finchlite/codegen/buffers/__init__.py index 34e9e1c5..39bc28ae 100644 --- a/src/finchlite/codegen/buffers/__init__.py +++ b/src/finchlite/codegen/buffers/__init__.py @@ -1,20 +1,10 @@ -from .hashtable import ( - CHashTable, - CHashTableFType, - NumbaHashTable, - NumbaHashTableFType, -) from .malloc_buffer import MallocBuffer, MallocBufferFType from .numpy_buffer import NumpyBuffer, NumpyBufferFType from .safe_buffer import SafeBuffer, SafeBufferFType __all__ = [ - "CHashTable", - "CHashTableFType", "MallocBuffer", "MallocBufferFType", - "NumbaHashTable", - "NumbaHashTableFType", "NumpyBuffer", "NumpyBufferFType", "SafeBuffer", diff --git a/src/finchlite/codegen/buffers/hashtable.py b/src/finchlite/codegen/buffers/hashtable.py deleted file mode 100644 index 7e067b6a..00000000 --- a/src/finchlite/codegen/buffers/hashtable.py +++ /dev/null @@ -1,581 +0,0 @@ -from __future__ import annotations - -import ctypes -from dataclasses import dataclass -from pathlib import Path -from textwrap import dedent -from typing import Any, NamedTuple - -import numpy as np - -import numba - -from finchlite.algebra import FType, ImmutableStructFType -from finchlite.codegen.c_codegen import ( - CContext, - CDictFType, - CStackFType, - c_eq, - c_hash, - c_type, - construct_from_c, - load_shared_lib, - serialize_to_c, -) -from finchlite.codegen.numba_codegen import ( - NumbaContext, - NumbaDictFType, - NumbaStackFType, - construct_from_numba, - numba_jitclass_type, - serialize_to_numba, -) -from finchlite.finch_assembly import AssemblyExpression, Dict, Stack - -stcpath = Path(__file__).parents[1] / "stc" / "include" -hashmap_h = stcpath / "stc" / "hashmap.h" - - -class NumbaDictFields(NamedTuple): - """ - This is a field that extracts out the dictionary from the obj variable. Its - purpose is so that we can extract out dictionary from obj in unpack, do - computations on the dictionary variable, and re-insert that into obj in - repack. - """ - - dct: str - obj: str - - -class CDictFields(NamedTuple): - """ - A tuple that stores the variable names for accessing the hash table - (manipulated directly in C) and the python object. - """ - - dct: str - obj: str - - -class CHashTableStruct(ctypes.Structure): - _fields_ = [ - ("dct", ctypes.c_void_p), - ("obj", ctypes.py_object), - ] - - -@dataclass -class CHashMethods: - init: str - exists: str - load: str - store: str - cleanup: str - - -@dataclass -class CHashTableLibrary: - library: ctypes.CDLL - methods: CHashMethods - hmap_t: str - - -# implement the hash table datastructures -class CHashTable(Dict): - """ - CHashTable class that basically connects up to an STC library. - """ - - libraries: dict[CHashTableFType, CHashTableLibrary] = {} - - @classmethod - def gen_code( - cls, - ctx: CContext, - hashmap_ftype: CHashTableFType, - inline: bool = False, - ) -> tuple[CHashMethods, str]: - # dereference both key and value types; as given, they are both pointers. - key_type = hashmap_ftype.key_type - value_type = hashmap_ftype.value_type - keytype_c = ctx.ctype_name(c_type(key_type)) - valuetype_c = ctx.ctype_name(c_type(value_type)) - hmap_t = ctx.freshen("hmap") - - hash_macro = c_hash(key_type, ctx) - eq_macro = c_eq(key_type, ctx) - - ctx.add_header("#include ") - - # these headers should just be added to the headers list. - # deduplication is catastrophic here. - ctx.headers.append(f"#define T {hmap_t}, {keytype_c}, {valuetype_c}") - ctx.headers.append(f"#define i_eq {eq_macro}") - ctx.headers.append(f"#define i_hash {hash_macro}") - ctx.headers.append(f'#include "{hashmap_h}"') - - methods = CHashMethods( - init=ctx.freshen("finch_hmap_init"), - exists=ctx.freshen("finch_hmap_exists"), - load=ctx.freshen("finch_hmap_load"), - store=ctx.freshen("finch_hmap_store"), - cleanup=ctx.freshen("finch_hmap_cleanup"), - ) - # register these methods in the datastructures. - ctx.datastructures[CHashTableFType(key_type, value_type)] = methods - inline_s = "static inline " if inline else "" - - # basically for the load functions, you need to provide a variable that - # can be copied. - # Yeah, so which API's should we use for load and store? - lib_code = dedent( - f""" - {inline_s}void* - {methods.init}() {{ - void* ptr = malloc(sizeof({hmap_t})); - memset(ptr, 0, sizeof({hmap_t})); - return ptr; - }} - - {inline_s}bool - {methods.exists}( - {hmap_t} *dct, {keytype_c} key - ) {{ - return {hmap_t}_contains(dct, key); - }} - - {inline_s}{valuetype_c} - {methods.load}( - {hmap_t} *dct, {keytype_c} key - ) {{ - const {valuetype_c}* internal_val = {hmap_t}_at(dct, key); - return *internal_val; - }} - - {inline_s}void - {methods.store}( - {hmap_t} *dct, {keytype_c} key, {valuetype_c} value - ) {{ - {hmap_t}_insert_or_assign(dct, key, value); - }} - - {inline_s}void - {methods.cleanup}( - void* ptr - ) {{ - {hmap_t}* hptr = ptr; - {hmap_t}_drop(hptr); - free(hptr); - }} - """ - ) - ctx.add_header(lib_code) - - return methods, hmap_t - - @classmethod - def compile( - cls, - hashmap_ftype: CHashTableFType, - ) -> CHashTableLibrary: - """ - Compile a library to use for the c hash table. - """ - key_type = hashmap_ftype.key_type - value_type = hashmap_ftype.value_type - - if hashmap_ftype in cls.libraries: - return cls.libraries[hashmap_ftype] - - ctx = CContext() - methods, hmap_t = cls.gen_code(ctx, hashmap_ftype) - code = ctx.emit_global() - lib = load_shared_lib(code) - - # get keystruct and value types - KeyStruct = c_type(key_type) - ValueStruct = c_type(value_type) - - init_func = getattr(lib, methods.init) - init_func.argtypes = [] - init_func.restype = ctypes.c_void_p - - # Exists: Takes (map*, key) -> returns bool - exists_func = getattr(lib, methods.exists) - exists_func.argtypes = [ctypes.c_void_p, KeyStruct] - exists_func.restype = ctypes.c_bool - - # Load: Takes (map*, key) -> returns value - load_func = getattr(lib, methods.load) - load_func.argtypes = [ - ctypes.c_void_p, - KeyStruct, - ] - load_func.restype = ValueStruct - - # Store: Takes (map*, key, val) -> returns void - store_func = getattr(lib, methods.store) - store_func.argtypes = [ - ctypes.c_void_p, - KeyStruct, - ValueStruct, - ] - store_func.restype = None - - # Cleanup: Takes (map*) -> returns void - cleanup_func = getattr(lib, methods.cleanup) - cleanup_func.argtypes = [ctypes.c_void_p] - cleanup_func.restype = None - - cls.libraries[hashmap_ftype] = CHashTableLibrary(lib, methods, hmap_t) - return cls.libraries[hashmap_ftype] - - def __init__(self, key_type, value_type, dct: dict | None = None): - """ - Constructor for the C Hash Table - """ - self._key_type = key_type - self._value_type = value_type - - # _key_type and _value_type must be placed prior to this so we can get - # hashmap initialization like this. - self.lib = self.__class__.compile(self.ftype) - - # these are blank fields we need when serializing or smth - self._struct: Any = None - self._self_obj: Any = None - - if dct is None: - dct = {} - self.dct = getattr(self.lib.library, self.lib.methods.init)() - for key, value in dct.items(): - # if some error happens, the serialization will handle it. - self.store(key, value) - - def __del__(self): - if not hasattr(self, "lib") or not hasattr(self, "dct"): - return - getattr(self.lib.library, self.lib.methods.cleanup)(self.dct) - - def exists(self, idx) -> np.bool: - c_key = serialize_to_c(self.ftype.key_type, idx) - c_value = getattr(self.lib.library, self.lib.methods.exists)(self.dct, c_key) - return np.bool(c_value) - - def load(self, idx): - c_key = serialize_to_c(self.ftype.key_type, idx) - c_value = getattr(self.lib.library, self.lib.methods.load)(self.dct, c_key) - return construct_from_c(self.ftype.value_type, c_value) - - def store(self, idx, val): - c_key = serialize_to_c(self.ftype.key_type, idx) - c_value = serialize_to_c(self.ftype.value_type, val) - getattr(self.lib.library, self.lib.methods.store)(self.dct, c_key, c_value) - - def __str__(self): - return f"c_hashtable({self.dct})" - - @property - def ftype(self): - return CHashTableFType(self._key_type, self._value_type) - - -class CHashTableFType(CDictFType, CStackFType): - """ - An implementation of Hash Tables using the stc library. - """ - - def __init__( - self, key_type: ImmutableStructFType, value_type: ImmutableStructFType - ): - # these should both be immutable structs/POD types. - # we will enforce this once the immutable struct PR is merged. - self._key_type = key_type - self._value_type = value_type - - def __eq__(self, other): - if not isinstance(other, CHashTableFType): - return False - return self.key_type == other.key_type and self.value_type == other.value_type - - def __call__(self): - return CHashTable(self.key_type, self.value_type, {}) - - def __str__(self): - return f"chashtable_t({self.key_type}, {self.value_type})" - - def __repr__(self): - return f"CHashTableFType({self.key_type}, {self.value_type})" - - @property - def key_type(self): - """ - Returns the type of elements used as the keys of the hash table. - """ - return self._key_type - - @property - def value_type(self): - """ - Returns the type of elements used as the value of the hash table. - """ - return self._value_type - - def __hash__(self): - """ - This method needs to be here because you are going to be using this - type as a key in dictionaries. - """ - return hash(("CHashTableFType", self.key_type, self.value_type)) - - """ - Methods for the C Backend - This requires an external library (stc) to work. - """ - - def c_type(self): - return ctypes.POINTER(CHashTableStruct) - - def c_existsdict(self, ctx: CContext, dct: Stack, idx: AssemblyExpression): - assert isinstance(dct.obj, CDictFields) - methods: CHashMethods = ctx.datastructures[self] - return f"{ctx.feed}{methods.exists}({dct.obj.dct}, {ctx(idx)})" - - def c_storedict( - self, - ctx: CContext, - dct: Stack, - idx: AssemblyExpression, - value: AssemblyExpression, - ): - assert isinstance(dct.obj, CDictFields) - methods: CHashMethods = ctx.datastructures[self] - ctx.exec(f"{ctx.feed}{methods.store}({dct.obj.dct}, {ctx(idx)}, {ctx(value)});") - - def c_loaddict(self, ctx: CContext, dct: Stack, idx: AssemblyExpression): - """ - Get an expression where we can get the value corresponding to a key. - """ - assert isinstance(dct.obj, CDictFields) - methods: CHashMethods = ctx.datastructures[self] - - return f"{methods.load}({dct.obj.dct}, {ctx(idx)})" - - def c_unpack(self, ctx: CContext, var_n: str, val: AssemblyExpression): - """ - Unpack the map into C context. - """ - assert val.result_type == self - data = ctx.freshen(var_n, "data") - # Add all the stupid header stuff from above. - if self not in ctx.datastructures: - CHashTable.gen_code(ctx, self, inline=True) - - ctx.exec(f"{ctx.feed}void* {data} = {ctx(val)}->dct;") - return CDictFields(data, var_n) - - def c_repack(self, ctx: CContext, lhs: str, obj: CDictFields): - """ - Repack the map out of C context. - """ - ctx.exec(f"{ctx.feed}{lhs}->dct = {obj.dct};") - - def serialize_to_c(self, obj: CHashTable): - """ - Serialize the Hash Map to a CHashMap structure. - This datatype will then immediately get turned into a struct. - """ - assert isinstance(obj, CHashTable) - dct = ctypes.c_void_p(obj.dct) - struct = CHashTableStruct(dct, obj) - # We NEED this for stupid ownership reasons. - obj._self_obj = ctypes.py_object(obj) - obj._struct = struct - return ctypes.pointer(struct) - - def deserialize_from_c(self, obj: CHashTable, res): - """ - Update our hash table based on how the C call modified the CHashTableStruct. - """ - assert isinstance(res, ctypes.POINTER(CHashTableStruct)) - assert isinstance(res.contents.obj, CHashTable) - - obj.dct = res.contents.dct - - def construct_from_c(self, c_dct): - """ - Construct a CHashTable from a C-compatible structure. - - c_map is a pointer to a CHashTableStruct - """ - raise NotImplementedError - - -class NumbaHashTable(Dict): - """ - A Hash Table implementation that integrates cleanly with the numba backend. - """ - - def __init__( - self, - key_type: FType, - value_type: FType, - dct: dict[tuple, tuple] | None = None, - ): - self._key_type = key_type - self._value_type = value_type - - self._numba_key_type = numba_jitclass_type(key_type) - self._numba_value_type = numba_jitclass_type(value_type) - - if dct is None: - dct = {} - self.dct = numba.typed.Dict.empty( - key_type=self._numba_key_type, value_type=self._numba_value_type - ) - for key, value in dct.items(): - self.dct[key] = value - - @property - def ftype(self): - """ - Returns the finch type of this hash table. - """ - return NumbaHashTableFType(self._key_type, self._value_type) - - def exists(self, idx) -> np.bool: - """ - Exists function of the numba hash table. - It will accept an object with TupleFType and return a bool. - """ - idx = serialize_to_numba(self.key_type, idx) - return np.bool(idx in self.dct) - - def load(self, idx): - idx = serialize_to_numba(self.key_type, idx) - result = self.dct[idx] - return construct_from_numba(self.value_type, result) - - def store(self, idx, val): - idx = serialize_to_numba(self.key_type, idx) - val = serialize_to_numba(self.value_type, val) - self.dct[idx] = val - - def __str__(self): - return f"numba_hashtable({self.dct})" - - -class NumbaHashTableFType(NumbaDictFType, NumbaStackFType): - """ - An implementation of Hash Tables using the stc library. - """ - - def __init__( - self, key_type: ImmutableStructFType, value_type: ImmutableStructFType - ): - self._key_type = key_type - self._value_type = value_type - - def __eq__(self, other): - if not isinstance(other, NumbaHashTableFType): - return False - return self.key_type == other.key_type and self.value_type == other.value_type - - def __call__(self): - return NumbaHashTable(self._key_type, self._value_type, {}) - - def __str__(self): - return f"numba_hashtable_t({self.key_type}, {self.value_type})" - - def __repr__(self): - return f"NumbaHashTableFType({self.key_type}, {self.value_type})" - - @property - def key_type(self): - """ - Returns the type of elements used as the keys of the hash table. - (some integer tuple) - """ - return self._key_type - - @property - def value_type(self): - """ - Returns the type of elements used as the value of the hash table. - (some integer tuple) - """ - return self._value_type - - def __hash__(self): - """ - This method needs to be here because you are going to be using this - type as a key in dictionaries. - """ - return hash(("NumbaHashTableFType", self.key_type, self.value_type)) - - """ - Methods for the Numba Backend - """ - - def numba_jitclass_type(self) -> numba.types.Type: - numba_key_type = numba_jitclass_type(self.key_type) - numba_value_type = numba_jitclass_type(self.value_type) - return numba.types.ListType( - numba.types.DictType(numba_key_type, numba_value_type) - ) - - def numba_type(self): - return list - - def numba_existsdict(self, ctx: NumbaContext, dct: Stack, idx: AssemblyExpression): - assert isinstance(dct.obj, NumbaDictFields) - return f"{ctx(idx)} in {dct.obj.dct}" - - def numba_loaddict(self, ctx: NumbaContext, dct: Stack, idx: AssemblyExpression): - assert isinstance(dct.obj, NumbaDictFields) - return f"{dct.obj.dct}[{ctx(idx)}]" - - def numba_storedict( - self, - ctx: NumbaContext, - dct: Stack, - idx: AssemblyExpression, - value: AssemblyExpression, - ): - assert isinstance(dct.obj, NumbaDictFields) - ctx.exec(f"{ctx.feed}{dct.obj.dct}[{ctx(idx)}] = {ctx(value)}") - - def numba_unpack( - self, ctx: NumbaContext, var_n: str, val: AssemblyExpression - ) -> NumbaDictFields: - """ - Unpack the dictionary into numba context. - """ - # the val field will always be asm.Variable(var_n, var_t) - dct = ctx.freshen(var_n, "dct") - ctx.exec(f"{ctx.feed}{dct} = {ctx(val)}[0]") - - return NumbaDictFields(dct, var_n) - - def numba_repack(self, ctx: NumbaContext, lhs: str, obj: NumbaDictFields): - """ - Repack the dictionary from Numba context. - """ - # obj is the fields corresponding to the self.slots[lhs] - ctx.exec(f"{ctx.feed}{lhs}[0] = {obj.dct}") - - def serialize_to_numba(self, obj: NumbaHashTable): - """ - Serialize the hash table to a Numba-compatible object. - """ - return numba.typed.List([obj.dct]) - - def deserialize_from_numba(self, obj: NumbaHashTable, numba_dct: list[dict]): - obj.dct = numba_dct[0] - - def construct_from_numba(self, numba_dct): - """ - Construct a numba dictionary from a Numba-compatible object. - """ - return NumbaHashTable(self.key_type, self.value_type, numba_dct[0]) diff --git a/src/finchlite/codegen/buffers/malloc_buffer.py b/src/finchlite/codegen/buffers/malloc_buffer.py index e6446dc5..1f718d3b 100644 --- a/src/finchlite/codegen/buffers/malloc_buffer.py +++ b/src/finchlite/codegen/buffers/malloc_buffer.py @@ -72,7 +72,7 @@ def gen_code( free=ctx.freshen("mallocbuffer_free"), resize=ctx.freshen("mallocbuffer_resize"), ) - ctx.datastructures[ftype] = methods + ctx.buffer_methods[ftype] = methods buffer_type = ctx.ctype_name(CMallocBufferStruct) elt_type = ctx.ctype_name(c_type(ftype.element_type)) @@ -305,10 +305,10 @@ def c_store( def c_resize(self, ctx: CContext, buf: Stack, new_len: AssemblyExpression): assert isinstance(buf.obj, CBufferFields) - if self not in ctx.datastructures: + if self not in ctx.buffer_methods: raise Exception("A Mallocbuffer must be unpacked before being operated on!") - methods: CMallocBufferMethods = ctx.datastructures[self] + methods: CMallocBufferMethods = ctx.buffer_methods[self] new_len = ctx(ctx.cache("len", new_len)) data = buf.obj.data @@ -329,7 +329,7 @@ def c_unpack(self, ctx: CContext, var_n, val): t = ctx.ctype_name(c_type(self.element_type)) ctx.add_header("#include ") - if self not in ctx.datastructures: + if self not in ctx.buffer_methods: MallocBufferBackend.gen_code(ctx, self, inline=True) ctx.exec( diff --git a/src/finchlite/codegen/c_codegen/__init__.py b/src/finchlite/codegen/c_codegen/__init__.py index de5d320e..cfffd5f1 100644 --- a/src/finchlite/codegen/c_codegen/__init__.py +++ b/src/finchlite/codegen/c_codegen/__init__.py @@ -4,19 +4,15 @@ CBufferFType, CCompiler, CContext, - CDictFType, CGenerator, - CHashableFType, CKernel, CLibrary, CNAryOperator, COperator, CStackFType, CUnaryOperator, - c_eq, c_function_call, c_function_name, - c_hash, c_literal, c_type, construct_from_c, @@ -34,9 +30,7 @@ "CCode", "CCompiler", "CContext", - "CDictFType", "CGenerator", - "CHashableFType", "CKernel", "CLibrary", "CLowerer", @@ -44,10 +38,8 @@ "COperator", "CStackFType", "CUnaryOperator", - "c_eq", "c_function_call", "c_function_name", - "c_hash", "c_literal", "c_type", "construct_from_c", diff --git a/src/finchlite/codegen/c_codegen/c.py b/src/finchlite/codegen/c_codegen/c.py index 4fdf06ce..4e2e69f9 100644 --- a/src/finchlite/codegen/c_codegen/c.py +++ b/src/finchlite/codegen/c_codegen/c.py @@ -5,10 +5,9 @@ import tempfile from abc import ABC, abstractmethod from collections import namedtuple -from collections.abc import Hashable from functools import lru_cache from pathlib import Path -from typing import Any, TypedDict +from typing import Any import numpy as np @@ -26,7 +25,7 @@ ftype, ) from finchlite.algebra.algebra import FinchOperator -from finchlite.finch_assembly import BufferFType, DictFType +from finchlite.finch_assembly import BufferFType from finchlite.symbolic import Context, Namespace, ScopedDict, UnvalidatedForm from finchlite.util import config, file_cache from finchlite.util.logging import LOG_BACKEND_C @@ -70,9 +69,6 @@ def c_function_call(self, ctx: Any, *args: Any) -> Any: return c_unary_function_call(self.c_symbol, ctx, *args) -common_h = Path(__file__).parents[1] / "stc" / "include" / "stc" / "common.h" - - @file_cache(ext=config.get("shared_library_suffix"), domain="c") def create_shared_lib(filename, c_code, cc, cflags): """ @@ -522,7 +518,7 @@ def __init__( self.fptr = fptr self.types = types self.slots = slots - self.datastructures: dict[Hashable, Any] = {} + self.buffer_methods: dict[Any, Any] = {} def add_header(self, header): if header not in self._headerset: @@ -735,24 +731,6 @@ def __call__(self, prgm: asm.AssemblyNode): if not isinstance(buf_t, CBufferFType): raise TypeError(f"Expected C buffer type, got: {buf_t}") return buf_t.c_length(self, buf) - case asm.LoadDict(map, idx): - map = self.resolve(map) - map_t = map.result_type - if not isinstance(map_t, CDictFType): - raise TypeError(f"Expected C dict type, got: {map_t}") - return map_t.c_loaddict(self, map, idx) - case asm.ExistsDict(map, idx): - map = self.resolve(map) - map_t = map.result_type - if not isinstance(map_t, CDictFType): - raise TypeError(f"Expected C dict type, got: {map_t}") - return map_t.c_existsdict(self, map, idx) - case asm.StoreDict(map, idx, val): - map = self.resolve(map) - map_t = map.result_type - if not isinstance(map_t, CDictFType): - raise TypeError(f"Expected C dict type, got: {map_t}") - return map_t.c_storedict(self, map, idx, val) case asm.Block(bodies): ctx_2 = self.block() for body in bodies: @@ -1071,177 +1049,10 @@ def tuple_construct_from_c(fmt: TupleFType, c_struct): return tuple(args) -class CHashableFType(FType): - @abstractmethod - def c_hash(self, ctx: CContext) -> str: - """ - Emit code from CContext that takes an expression and returns the NAME - of a macro that performs our hashing with STC functions. - - Please reference finch_assembly/struct.py for reference. - - The macro should take one argument (type of fmt*, so there is one layer - of indirection) and expand to an expression that returns a size_t of - the final hash. - - The main idea for implementing this is for unpacked structs where you - want the unused bytes to be set to zero. - - This is important to note for immutable structs because you need to do - something like &var_n->property if you want to do recursive hashing. - """ - ... - - @abstractmethod - def c_eq(self, ctx: CContext) -> str: - """ - Emit code from CContext that takes an expression and returns the NAME - of a macro that can be used to check. - - The macro should take two arguments (each a type of fmt*, so there is - one layer of indirection) and expand to an expression that checks - equality. - - The main idea for implementing this is for unpacked structs where you - want the unused bytes to be set to zero. - - This is important to note for immutable structs because you need to do - something like &var_n->property if you want to do recursive hashing. - """ - - -def c_hash(fmt: FType, ctx: "CContext"): - """ - Expand to the name of a macro that c hash can use for hashing fmt. - - Args: - ctx: CContext object - var_n: name to be supplied. It is a placeholder for a variable with - type fmt* (so indirection) - """ - match fmt: - case CHashableFType(): - return fmt.c_hash(ctx) - case algebra.ftypes.FDTypeNumpy() | algebra.int_ | algebra.float_: - return c_hash_default(fmt, ctx) - case ImmutableStructFType() | TupleFType(): - return c_hash_struct(fmt, ctx) - case _: - raise NotImplementedError(f"No C hash mapping for {fmt}") - - -def c_hash_default(fmt: FType, ctx: "CContext"): - ctx.add_header(f'#include "{common_h}"') - return "c_default_hash" - - -class CHashableProperties(TypedDict): - eq: str | None - hash: str | None - - -def c_hash_struct(fmt: ImmutableStructFType, ctx: "CContext"): - if fmt in ctx.datastructures: - properties: CHashableProperties = ctx.datastructures[fmt] - if properties.get("hash") is not None: - return properties["hash"] - else: - ctx.datastructures[fmt] = {} - - macros = [c_hash(fmt2, ctx) for fmt2 in fmt.struct_fieldtypes] - name = ctx.freshen("hash") - ctx.datastructures[fmt]["hash"] = name - - # implement recursion with &{var_n}->{struct_field} - var_n = ctx.freshen("var") - args = ",".join( - f"{macro}(&({var_n})->{field})" - for macro, field in zip(macros, fmt.struct_fieldnames, strict=False) - ) - ctx.add_header(f"#define {name}({var_n}) c_hash_mix({args})") - return name - - -def c_eq(fmt: FType, ctx: "CContext"): - """ - Expand to the name of a macro that c eq can use for checking equivalence of fmt. - - Args: - ctx: CContext object - var_n: name to be supplied. It is a placeholder for a variable with - type fmt* (so indirection) - """ - match fmt: - case CHashableFType(): - return fmt.c_eq(ctx) - case algebra.ftypes.FDTypeNumpy() | algebra.int_ | algebra.float_: - return c_eq_default(fmt, ctx) - case ImmutableStructFType() | TupleFType(): - return c_eq_struct(fmt, ctx) - case _: - raise NotImplementedError(f"No C equality mapping for {fmt}") - - -def c_eq_default(fmt: FType, ctx: "CContext"): - ctx.add_header(f'#include "{common_h}"') - return "c_default_eq" - - -def c_eq_struct(fmt: ImmutableStructFType, ctx: "CContext"): - if fmt in ctx.datastructures: - properties: CHashableProperties = ctx.datastructures[fmt] - if properties.get("eq") is not None: - return properties["eq"] - else: - ctx.datastructures[fmt] = {} - - macros = [c_eq(fmt, ctx) for fmt in fmt.struct_fieldtypes] - name = ctx.freshen("eq") - ctx.datastructures[fmt]["eq"] = name - - # implement recursion with &{var_n}->{struct_field} - var1_n = ctx.freshen("var") - var2_n = ctx.freshen("var") - args = " && ".join( - f"{macro}(&({var1_n})->{field}, &({var2_n})->{field})" - for macro, field in zip(macros, fmt.struct_fieldnames, strict=False) - ) - ctx.add_header(f"#define {name}({var1_n}, {var2_n}) ({args})") - return name - - -class CDictFType(DictFType, CArgumentFType, ABC): - """ - Abstract base class for the ftype of dictionaries. The ftype defines how - the data in a Map is organized and accessed. - """ - - @abstractmethod - def c_existsdict(self, ctx, map, idx): - """ - Return C code which checks whether a given key exists in a map. - """ - ... - - @abstractmethod - def c_loaddict(self, ctx, map, idx): - """ - Return C code which gets a value corresponding to a certain key. - """ - ... - - @abstractmethod - def c_storedict(self, ctx, buffer, idx, value): - """ - Return C code which stores a certain value given a certain integer tuple key. - """ - ... - - class CBufferFType(BufferFType, CArgumentFType, ABC): """ - Abstract base class for the ftype of datastructures. The ftype defines how - the data in an Buffer is organized and accessed. + Abstract base class for the ftype of buffers. The ftype defines how the + data in a Buffer is organized and accessed. """ @abstractmethod diff --git a/src/finchlite/codegen/dev_doc.md b/src/finchlite/codegen/dev_doc.md index 3ab50bf6..6369398c 100644 --- a/src/finchlite/codegen/dev_doc.md +++ b/src/finchlite/codegen/dev_doc.md @@ -2,7 +2,7 @@ ## What is serialize/construct/unpack/... ? -When a complex data structure, such as a hash table or array, gets passed into a +When a complex data structure, such as an array, gets passed into a kernel (C or Numba) as an argument, there are five different stages that are performed: @@ -12,8 +12,7 @@ performed: 2. Inside the kernel, the data structure is unpacked to reveal the underlying data structure. 3. The kernel modifies this data structure. The modifications it should do are - provided by assembly instructions. See the hashtable implementation for - reference on how these mutations work. + provided by assembly instructions. 4. The kernel has finished making its modifications. It's time to _repack_ the data structure. 5. The kernel has finished running. If we have mutated the serialized data @@ -28,8 +27,8 @@ The function that turns an object in the kernel back into a python object is called `construct_from_c(fmt, obj)` or `construct_from_numba(fmt, obj)`. It is only called for the object being returned by the kernel. -Unpacking is only implemented for arrays and hash tables. It should not be -implemented for scalar types. +Unpacking is only implemented for arrays. It should not be implemented for scalar +types. ### C Example @@ -115,80 +114,3 @@ names that were used in the unpacking. Unpack and Repack require numba codegen contexts to freshen variables and emit initialization code. - -## Hash Table Data Types - -Hash Tables may have keys and values that have the following finch types: -1. A scalar (as defined in numpy or python) -2. An FType inheriting from `ImmutableStructFType` - -Nothing else is currently supported nor is intended to be supported. - -All `ImmutableStructFType`'s will get serialized to typed tuples for numba. - -The C Context requires `c_hash` and `c_eq` behavior for a type that wants to be -hashed. Custom ftypes can implement this by subclassing `CHashableFType`; scalar, -immutable struct, and tuple ftypes are handled by the standard match cases in -`c_hash` and `c_eq`. Each method returns the *name* of a macro that will get -expanded for hashing or equality. See the outline below for how these functions -work: - -```python -class CustomFType(FType, CHashableFType): - def c_hash(self, ctx: "CContext"): - ctx.add_header(f'#include "{common_h}"') - return "custom_hash" - - def c_eq(self, ctx: "CContext"): - ctx.add_header(f'#include "{common_h}"') - return "custom_eq" - -# For immutable structs with fields. -def c_hash_struct(fmt: ImmutableStructFType, ctx: "CContext"): - # this should be true in whatever structs we have. - assert isinstance(fmt, Hashable) - if fmt in ctx.datastructures: - properties: CHashableProperties = ctx.datastructures[fmt] - if properties.get("hash") is not None: - return properties["hash"] - else: - ctx.datastructures[fmt] = {} - - macros = [c_hash(fmt, ctx) for fmt in fmt.struct_fieldtypes] - name = ctx.freshen("hash") - ctx.datastructures[fmt]["hash"] = name - - # implement recursion with &{var_n}->{struct_field} - var_n = ctx.freshen("var") - args = ",".join( - f"{macro}(&({var_n})->{field})" - for macro, field in zip(macros, fmt.struct_fieldnames, strict=False) - ) - ctx.add_header(f"#define {name}({var_n}) c_hash_mix({args})") - return name - - -def c_eq_struct(fmt: ImmutableStructFType, ctx: "CContext"): - # this should be true in whatever structs we have. - assert isinstance(fmt, Hashable) - if fmt in ctx.datastructures: - properties: CHashableProperties = ctx.datastructures[fmt] - if properties.get("eq") is not None: - return properties["eq"] - else: - ctx.datastructures[fmt] = {} - - macros = [c_eq(fmt, ctx) for fmt in fmt.struct_fieldtypes] - name = ctx.freshen("eq") - ctx.datastructures[fmt]["eq"] = name - - # implement recursion with &{var_n}->{struct_field} - var1_n = ctx.freshen("var") - var2_n = ctx.freshen("var") - args = " && ".join( - f"{macro}(&({var1_n})->{field}, &({var2_n})->{field})" - for macro, field in zip(macros, fmt.struct_fieldnames, strict=False) - ) - ctx.add_header(f"#define {name}({var1_n}, {var2_n}) ({args})") - return name -``` diff --git a/src/finchlite/codegen/numba_codegen/__init__.py b/src/finchlite/codegen/numba_codegen/__init__.py index fe7d1d1d..caff558b 100644 --- a/src/finchlite/codegen/numba_codegen/__init__.py +++ b/src/finchlite/codegen/numba_codegen/__init__.py @@ -4,7 +4,6 @@ NumbaBufferFType, NumbaCompiler, NumbaContext, - NumbaDictFType, NumbaGenerator, NumbaKernel, NumbaLibrary, @@ -36,7 +35,6 @@ "NumbaCode", "NumbaCompiler", "NumbaContext", - "NumbaDictFType", "NumbaGenerator", "NumbaKernel", "NumbaLibrary", diff --git a/src/finchlite/codegen/numba_codegen/numba.py b/src/finchlite/codegen/numba_codegen/numba.py index 62c6d270..21f93dd3 100644 --- a/src/finchlite/codegen/numba_codegen/numba.py +++ b/src/finchlite/codegen/numba_codegen/numba.py @@ -19,7 +19,6 @@ fisinstance, ) from finchlite.finch_assembly import BufferFType -from finchlite.finch_assembly.dct import DictFType from finchlite.symbolic import Context, Namespace, ScopedDict, UnvalidatedForm from finchlite.util.logging import LOG_BACKEND_NUMBA @@ -439,34 +438,6 @@ def struct_construct_from_numba(fmt: StructFType, numba_struct): return fmt.from_fields(*args) -class NumbaDictFType(DictFType, NumbaArgumentFType, ABC): - """ - Abstract base class for the ftype of datastructures. The ftype defines how - the data in a Map is organized and accessed. - """ - - @abstractmethod - def numba_existsdict(self, ctx: "NumbaContext", map, idx): - """ - Return numba code which checks whether a given key exists in a map. - """ - ... - - @abstractmethod - def numba_loaddict(self, ctx, buffer, idx): - """ - Return numba code which gets a value corresponding to a certain key. - """ - ... - - @abstractmethod - def numba_storedict(self, ctx, buffer, idx, value): - """ - Return C code which stores a certain value given a certain integer tuple key. - """ - ... - - class NumbaBufferFType(BufferFType, NumbaArgumentFType, ABC): @abstractmethod def numba_length(self, ctx: "NumbaContext", buffer): @@ -769,24 +740,6 @@ def __call__(self, prgm: asm.AssemblyNode): if not isinstance(buf_t, NumbaBufferFType): raise TypeError(f"Expected numba buffer type, got: {buf_t}") return buf_t.numba_length(self, buf) - case asm.LoadDict(dct, idx): - dct = self.resolve(dct) - dct_t = dct.result_type - if not isinstance(dct_t, NumbaDictFType): - raise TypeError(f"Expected numba dict type, got: {dct_t}") - return dct_t.numba_loaddict(self, dct, idx) - case asm.ExistsDict(dct, idx): - dct = self.resolve(dct) - dct_t = dct.result_type - if not isinstance(dct_t, NumbaDictFType): - raise TypeError(f"Expected numba dict type, got: {dct_t}") - return dct_t.numba_existsdict(self, dct, idx) - case asm.StoreDict(dct, idx, val): - dct = self.resolve(dct) - dct_t = dct.result_type - if not isinstance(dct_t, NumbaDictFType): - raise TypeError(f"Expected numba dict type, got: {dct_t}") - return dct_t.numba_storedict(self, dct, idx, val) case asm.Block(bodies): ctx_2 = self.block() if bodies == (): diff --git a/src/finchlite/codegen/stc/.gitattributes b/src/finchlite/codegen/stc/.gitattributes deleted file mode 100644 index 8626e4b5..00000000 --- a/src/finchlite/codegen/stc/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -* text=auto - -*.h linguist-language=C -*.c linguist-language=C diff --git a/src/finchlite/codegen/stc/.github/workflows/meson.yml b/src/finchlite/codegen/stc/.github/workflows/meson.yml deleted file mode 100644 index 04adfdb2..00000000 --- a/src/finchlite/codegen/stc/.github/workflows/meson.yml +++ /dev/null @@ -1,171 +0,0 @@ -name: CI - -on: - pull_request: - push: - -jobs: - meson-build-and-tests: - runs-on: ${{ matrix.platform }} - name: ${{ matrix.platform }}, ${{ matrix.mode.name }} ${{ matrix.flavor }} - strategy: - fail-fast: false - matrix: - flavor: - - debug - - release - mode: - - name: default - args: -Dtests=enabled - extra_envs: {} - - # Alternative compiler setups - - name: gcc - args: -Dtests=enabled - extra_envs: - CC: gcc - CXX: g++ - - name: clang - args: -Dtests=enabled - extra_envs: - CC: clang - CXX: clang++ - - - name: sanitize - args: >- - "-Db_sanitize=address,undefined" - extra_envs: {} - - # This is for MSVC, which only supports AddressSanitizer. - # https://learn.microsoft.com/en-us/cpp/sanitizers/ - - name: sanitize+asanonly - args: -Db_sanitize=address - extra_envs: - ASAN_OPTIONS: report_globals=0:halt_on_error=1:abort_on_error=1:print_summary=1 - - - name: clang+sanitize - args: >- - "-Db_sanitize=address,undefined" - extra_envs: - CC: clang - CXX: clang++ - - name: clang+msan - args: -Db_sanitize=memory - extra_envs: - CC: clang - CXX: clang++ - - # default clang on GitHub hosted runners is from MSYS2. - # Use Visual Studio supplied clang-cl instead. - - name: clang-cl+sanitize - args: >- - "-Db_sanitize=address,undefined" - extra_envs: - CC: clang-cl - CXX: clang-cl - - name: clang-cl+msan - args: -Db_sanitize=memory - extra_envs: - CC: clang-cl - CXX: clang-cl - platform: - - ubuntu-22.04 - - windows-2022 - - macos-latest - - exclude: - # clang-cl only makes sense on windows. - - platform: ubuntu-22.04 - mode: - name: clang-cl+sanitize - - platform: macos-latest - mode: - name: clang-cl+sanitize - - platform: ubuntu-22.04 - mode: - name: clang-cl+msan - - platform: macos-latest - mode: - name: clang-cl+msan - - # Use clang-cl instead of MSYS2 clang. - # - # we already tested clang+sanitize on linux, - # if this doesn't work, it should be an issue for MSYS2 team to consider. - - platform: windows-2022 - mode: - name: clang - - platform: windows-2022 - mode: - name: clang+sanitize - - platform: windows-2022 - mode: - name: clang+msan - - # MSVC-only sanitizers - - platform: ubuntu-22.04 - mode: - name: sanitize+asanonly - - platform: macos-latest - mode: - name: sanitize+asanonly - - platform: windows-2022 - mode: - name: sanitize - - # clang is the default on macos - # also gcc is an alias to clang - - platform: macos-latest - mode: - name: clang - - platform: macos-latest - mode: - name: gcc - - # gcc is the default on linux - - platform: ubuntu-22.04 - mode: - name: gcc - - # only run sanitizer tests on linux - # - # gcc/clang's codegen shouldn't massively change across platforms, - # and linux supports most of the sanitizers. - - platform: macos-latest - mode: - name: clang+sanitize - - platform: macos-latest - mode: - # macos does not support msan - name: clang+msan - - platform: macos-latest - mode: - name: sanitize - steps: - - name: Setup meson - run: | - pipx install meson ninja - - name: Checkout - uses: actions/checkout@v4 - - name: Activate MSVC and Configure - if: ${{ matrix.platform == 'windows-2022' }} - env: ${{ matrix.mode.extra_envs }} - run: | - meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} --vsenv - - name: Configuring - if: ${{ matrix.platform != 'windows-2022' }} - env: ${{ matrix.mode.extra_envs }} - run: | - meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} - - name: Building - run: | - meson compile -C build-${{ matrix.flavor }} - - name: Running tests - env: ${{ matrix.mode.extra_envs }} - run: | - meson test -C build-${{ matrix.flavor }} --timeout-multiplier 0 - - uses: actions/upload-artifact@v4 - if: failure() - with: - name: ${{ matrix.platform }}-${{ matrix.mode.name }}-${{ matrix.flavor }}-logs - path: build-${{ matrix.flavor }}/meson-logs diff --git a/src/finchlite/codegen/stc/.gitignore b/src/finchlite/codegen/stc/.gitignore deleted file mode 100644 index a13304f9..00000000 --- a/src/finchlite/codegen/stc/.gitignore +++ /dev/null @@ -1,47 +0,0 @@ -# Folders -stuff/* -build*/ - -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb diff --git a/src/finchlite/codegen/stc/LICENSE b/src/finchlite/codegen/stc/LICENSE deleted file mode 100644 index 8d473c41..00000000 --- a/src/finchlite/codegen/stc/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -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. diff --git a/src/finchlite/codegen/stc/Makefile b/src/finchlite/codegen/stc/Makefile deleted file mode 100644 index 9efcc3c0..00000000 --- a/src/finchlite/codegen/stc/Makefile +++ /dev/null @@ -1,108 +0,0 @@ -# GNU Makefile for STC. Linux/Mac + Windows for gcc, clang and tcc (TinyC). -# On Windows, makefile requires mkdir, rm, and printf, which are all -# found in the C:\Program Files\Git\usr\bin folder. -# Use 'make CC=gcc' (or clang or tcc), or set CC in the environment. -# Currently only release build. - -ifeq ($(origin CC),default) - CC := gcc -endif -ifeq ($(origin CXX),default) - CXX := g++ -endif - -CFLAGS ?= -std=c11 -Iinclude -O3 -MMD -Werror -Wpedantic -Wall -Wextra -Wconversion -Wno-missing-field-initializers -CXXFLAGS ?= -std=c++20 -Iinclude -O3 -MMD -Wall -ifeq ($(CC),tcc) - AR_RCS ?= tcc -ar rcs -else - AR_RCS ?= ar rcs -endif -MKDIR_P ?= mkdir -p -RM_F ?= rm -f - -ifeq ($(OS),Windows_NT) - DOTEXE := .exe - BUILDDIR := build/Windows_$(CC) - LDFLAGS += -fopenmp -else -# CC_VER := $(shell $(CC) -dumpversion | cut -f1 -d.) - BUILDDIR := build/$(shell uname)_$(CC) - LDFLAGS += -lm - # Check preprocessor macros to detect clang compiler - IS_CLANG_COMPILER := $(shell echo '' | $(CC) -dM -E -x c - | grep -q '__clang__' > /dev/null 2>&1 && echo 1 || echo 0) - ifneq ($(IS_CLANG_COMPILER),1) - LDFLAGS += -fopenmp - CFLAGS += -Wno-clobbered - endif -endif - -OBJ_DIR := $(BUILDDIR) - -LIB_NAME := stc -LIB_LIST := cstr_core cstr_io cstr_utf8 cregex csview cspan fmt random stc_core -LIB_SRCS := $(LIB_LIST:%=src/%.c) -LIB_OBJS := $(LIB_SRCS:%.c=$(OBJ_DIR)/%.o) -LIB_DEPS := $(LIB_SRCS:%.c=$(OBJ_DIR)/%.d) -LIB_PATH := $(BUILDDIR)/lib$(LIB_NAME).a - -EX_SRCS := $(wildcard examples/*/*.c) -EX_OBJS := $(EX_SRCS:%.c=$(OBJ_DIR)/%.o) -EX_DEPS := $(EX_SRCS:%.c=$(OBJ_DIR)/%.d) -EX_EXES := $(EX_SRCS:%.c=$(BUILDDIR)/%$(DOTEXE)) - -TEST_SRCS := $(wildcard tests/*_test.c) tests/main.c -TEST_OBJS := $(TEST_SRCS:%.c=$(OBJ_DIR)/%.o) -TEST_DEPS := $(TEST_SRCS:%.c=$(OBJ_DIR)/%.d) -TEST_EXE := $(BUILDDIR)/tests/test_all$(DOTEXE) - -PROGRAMS := $(EX_EXES) $(TEST_EXE) - -fast: - @$(MAKE) -j --no-print-directory all - -all: $(PROGRAMS) - @echo - @$(TEST_EXE) - -$(PROGRAMS): $(LIB_PATH) - -clean: - @$(RM_F) $(LIB_OBJS) $(EX_OBJS) $(TEST_OBJS) $(LIB_DEPS) $(EX_DEPS) $(TEST_DEPS) $(LIB_PATH) $(EX_EXES) $(TEST_EXE) - @echo "Cleaned" - -distclean: - @$(RM_F) -r build - @echo "All Cleaned" - -lib: $(LIB_PATH) - @echo - -$(LIB_PATH): $(LIB_OBJS) - @printf "\r\e[2K%s" "$(AR_RCS) $@" - @$(AR_RCS) $@ $(LIB_OBJS) - -$(OBJ_DIR)/%.o: %.c Makefile - @$(MKDIR_P) $(@D) - @printf "\r\e[2K%s" "$(CC) $( -Version 6 NEWS -Apologies for the multiple API changes particularly on the coroutine, cspan and cregex modules -after V5.1. From upcoming V6.0 release, API is planned to be stable and changes will be -made backward compatible. - -V6.0: -- New powerful V2 coroutines with waitgroups, cancellation and async finalization. -- Fixed #149: improved cregex API and fixed bug on word-boundary match. -- Fixed #143: major container initialization flaw. -- Fixed #146: regression on cstr initialization. -- Fixed #142: regression regarding i_no_clone. -- Fixed #138: general hash function bug. -- Fixed queue/deque shrink_to_fit() and reserve() bugs. -- Fixed i_aux and custom allocations bugs. -- Fixed #136: missing exports in hmap, #137: declare_hash_set() -- Fixed #133: bug in vec/stack _begin() and _rbegin(). -- Fixed #129 & #150: Makefile bugs and improvements. -- Fixed #128: bug in cstr_istarts_with(). -- Issue #123: Added GNU print format attribute to cstr_from_fmt(), cstr_printf(). -- Improved documentation. - -V5.1: -- Specifying containers with non-trivial element types can now be done with a single `#define` -prior to including the container (using `c_keyclass`, `c_keypro`, and `c_cmpclass` option *traits*). -- Users may now define `T` as a shorthand for `i_type`. -- Replaced **arc** with a new implementation which take up only one pointer. Previous arc is now available as a traits option (c_arc2). The new **arc** may not be constructed from an object pointer, for that use **arc2**. -- Updated and fixed bugs in **cregex** to handle invalid utf8 strings. -- Some breaking changes in cspan API. -- Several other smaller improvements and bug fixes. - -V5.0.2: -- Changed `c_foreach (...)` => `for (c_each(...))`, and `c_forrange(...)` => `for (c_range(...))`, etc. - -V5.0: -- Added build system/CI with Meson. Makefile provided as well. -- Added support for extending templated containers by `#define i_aux `. -- Changed ranged for-loop macros to use more natural C-syntax (v5.0.2) -- Added **sum type** (tagged union), included via `algorithm.h` -- Added single/multi-dimensional generic **span** type, with numpy-like slicing. -- Updated coroutines support with *structured concurrency* and *symmetric coroutines*. -- Updated coroutines support with proper *error handling* and *error recovery*. -- Template parameter `T` lets you define container type plus `i_key` and `i_val` (or `i_opt`) all in one line. -- Template parameters `i_keyclass` and `i_valclass` to specify types with `_drop()` and `_clone()` functions defined. -- Template parameters `i_keypro` and `i_valpro` to specify `cstr`, `box` and `arc` types (users may also define pro-types). -- **hmap** now uses *Robin Hood hashing* (very fast on clang compiler). -- Several new algorithms added, e.g. `c_filter` (ranges-like), `c_shuffle`, `c_reverse`. -See also [version history](#version-history) for breaking changes in V5.0. - -
-Why use STC? - -#### A. Supplementing features missing in the C standard library -* A wide set of high performance, generic/templated typesafe container types, including smart pointers and bitsets. -* String type with utf8 support and short string optimization (sso), plus two string-view types. -* Typesafe and ergonomic **sum type** implementation, aka. tagged union or variant. -* A **coroutine** implementation with good ergonomics, error handling/recovery and cleanup support. -* Fast, modern **regular expressions** with full utf8 and a subset of unicode character classes support. -* Ranges algorithms like *iota* and filter views like *take, skip, take-while, skip-while, map*. -* Generic algorithms, iterators and loop abstactions. Blazing fast *sort, binary search* and *lower bound*. -* Single/multi-dimensional generic **span view** with arbitrary array dimensions and numpy array-like slicing. - -#### B. Improved safety and increased productivity -* Abstractions for raw loops, ranged iteration over containers, and generic ranges algorithms. All this -reduces the chance of creating bugs, as user code with raw loops and ad-hoc implementation of -common algorithms and containers is minimized/eliminated. -* STC is inherently **type safe**. Essentially, there are no opaque pointers or casting away of type information. -Only where neccesary, generic code will use some macros to do compile-time type-checking before types are casted. -Examples are `c_static_assert`, `c_const_cast`, `c_safe_cast` and macros for safe integer type casting. -* Containers and algorithms all use **signed integers** for indices and sizes, and it encourange to use -signed integers for quantities in general (unsigned integers have valid usages as bitsets and in bit operations). -This could remove a wide range of bugs related to mixed unsigned-signed calculations and comparisons, which -intuitively gives the wrong answer in many cases. -* Tagged unions in C are common, but normally unsafely implemented. Traditionally, it leaves the inactive payload -data readily accesible to user code, and there is no general way to ensure that the payload is assigned along with -the tag, or that they match. STC **sum type** is a typesafe version of tagged unions which eliminates all those -safety concerns. -
- -Containers ----------- -- [***arc*** - (atomic) reference counted; shared pointer](docs/arc_api.md) -- [***box*** - heap allocated unique pointer`](docs/box_api.md) -- [***cbits*** - dynamic bitset](docs/cbits_api.md) -- [***cstr*** - string type (short string optimized)](docs/cstr_api.md) -- [***list*** - forward linked list](docs/list_api.md) -- [***stack*** - stack type](docs/stack_api.md) -- [***vec*** - vector type](docs/vec_api.md) -- [***deque*** - double-ended queue](docs/deque_api.md) -- [***queue*** - queue type](docs/queue_api.md) -- [***pqueue*** - priority queue](docs/pqueue_api.md) -- [***hashmap*** - unordered map](docs/hmap_api.md) -- [***hashset*** - unordered set](docs/hset_api.md) -- [***sortedmap*** - binary tree map](docs/smap_api.md) -- [***sortedset*** - binary tree set](docs/sset_api.md) - -Views ------ -- [***cspan*** - dynamic multi-dimensional (sub)span array view](docs/cspan_api.md) -- [***csview*** - string view (non-zero terminated)](docs/csview_api.md) -- [***zsview*** - zero-terminated string view](docs/zsview_api.md) - -Algorithms ----------- -- [***Coroutines*** - ergonomic, portable coroutines](docs/coroutine_api.md) -- [***Regular expressions*** - Rob Pike's Plan 9 regexp modernized!](docs/cregex_api.md) -- [***Tagged unions*** - a.k.a. sum types, variants, discriminating unions](docs/algorithm_api.md#tagged-unions) -- [***for-loop abstractions*** - ranged and on containers](docs/algorithm_api.md#ranged-for-loop-control-blocks) -- [***Misc generic algorithms*** - incl. fast qsort/binsort/lowerbound](docs/algorithm_api.md#generic-algorithms) -- [***Random numbers*** - a very fast *PRNG* based on *SFC64*](docs/random_api.md) -- [***Command line argument parser*** - similar to *getopt()*](docs/coption_api.md) - -## Contents - -
-Highlights - -## Highlights - -- **Minimal boilerplate code** - Specify only the required template parameters, and leave the rest as defaults. -- **Fully type safe** - Because of templating, it avoids error-prone casting of container types and elements back and forth from the containers. -- **High performance** - Unordered maps and sets, queues and deques are significantly faster than the C++ STL containers, the remaining are similar or close to STL in speed (See graph below). -- **Fully memory managed** - Containers destructs keys/values via default or user supplied drop function. They may be cloned if element types are clonable. Smart pointers (shared and unique) works seamlessly when stored in containers. See [***arc***](docs/arc_api.md) and [***box***](docs/box_api.md). -- **Uniform, easy-to-learn API** - For the generic containers and algorithms, simply include the headers. The API and functionality resembles c++ STL or Rust and is fully listed in the docs. Uniform usage across the various containers. -- **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed for comparison and calculation is asking for trouble. STC only uses signed numbers in the API for this reason. -- **Small footprint** - Small source code and generated executables. -- **Dual mode compilation** - By default it is a header-only library with inline and static methods, but you can easily switch to create a shared library without changing existing source files. Non-generic types, like (utf8) strings are compiled with external linking. one See the [installation section](#installation). -- **No callback functions** - All passed template argument functions/macros are directly called from the implementation, no slow callbacks which requires storage. -- **Compiles with C++ and C99** - C code can be compiled with C++ (container element types must be POD). -- **Pre-declaration** - Templated containers may be [pre-declared](#pre-declarations) without including the full API/implementation. -- **Extendable containers** - STC provides a mechanism to wrap containers inside a struct with [custom data per instance](#per-container-instance-customization). - -
-
-Installation - -## Installation - -STC uses meson build system. Make sure to have meson and ninja installed, e.g. as a python pip package from a bash shell: -```bash -pip install meson ninja -export LIBRARY_PATH=$LIBRARY_PATH:~/.local/lib -export CPATH=$CPATH:~/.local/include -export CC=gcc -``` -To create a build folder and to set the install folder to e.g. ~/.local: -```bash -meson setup --buildtype debug build --prefix ~/.local -cd build -ninja -ninja install -``` -STC is mixed *"headers-only"* / traditional library, i.e the templated container headers (and the *sort*/*lower_bound* -algorithms) can simply be included - they have no library dependencies. By default, all templated functions are -static (many inlined). This is often optimal for both performance and compiled binary size. However, for frequently -used container type instances (more than 2-3 TUs), consider creating a separate header file for them, e.g.: -```c++ -// intvec.h -#ifndef INTVEC_H_ -#define INTVEC_H_ -#define i_header // header definitions only -#define T intvec, int -#include -#endif -``` -So anyone may use the shared vec-type. Implement the shared functions in one C file (if several containers are shared, -you may define STC_IMPLEMENT on top of the file once instead): -```c++ -// shared.c -#define i_implement // implement the shared intvec. -#include "intvec.h" -``` -The non-templated types **cstr**, **csview**, **cregex**, **cspan** and **random**, are built as a library (libstc), -and is using the ***meson*** build system. However, the most common functions in **csview** and **random** are inlined. -The bitset **cbits**, the zero-terminated string view **zsview** and **algorthm** are all fully inlined and need no -linking with the stc-library. -
-
-Usage - -## Usage -STC containers have similar functionality to the C++ STL standard containers. All containers except for a few, -like **cstr** and **cbits** are generic/templated. No type casting is used, so containers are type-safe like -templated types in C++. To specify template parameters with STC, you define them as macros prior to -including the container, e.g. -```c++ -#define T Floats, float // Container type (name, element type) -#include // "instantiate" the desired container type -#include - -int main(void) -{ - Floats nums = {0}; - Floats_push(&nums, 30.f); - Floats_push(&nums, 10.f); - Floats_push(&nums, 20.f); - - for (int i = 0; i < Floats_size(&nums); ++i) - printf(" %g", nums.data[i]); - - for (c_each(i, Floats, nums)) // Alternative and recommended way to iterate. - printf(" %g", *i.ref); // i.ref is a pointer to the current element. - - Floats_drop(&nums); // cleanup memory -} -``` -Switching to a different container type, e.g. a sorted set (sset): - -[ [Run this code](https://godbolt.org/z/1PKqWo4z6) ] -```c++ -#define T Floats, float -#include // Use a sorted set instead -#include - -int main(void) -{ - Floats nums = {0}; - Floats_push(&nums, 30.f); - Floats_push(&nums, 10.f); - Floats_push(&nums, 20.f); - - // print the numbers (sorted) - for (c_each(i, Floats, nums)) - printf(" %g", *i.ref); - - Floats_drop(&nums); -} -``` -For associative containers and priority queues (hmap, hset, smap, sset, pqueue), comparison/lookup functions -are assumed to be defined. I.e. if they are not specified with template parameters, it assumes default -comparison operators works. To enable search/sort for the remaining containers (stack, vec, queue, deque), -define `i_cmp` or `i_eq` and/or `i_less` for the element type. If the element type is an integral type, -just define `i_use_cmp` (will use `==` and `<` operators for comparisons). - -If an element destructor `i_keydrop` is defined, `i_keyclone` function is required. -*Alternatively `#define i_opt c_no_clone` to disable container cloning.* - -Let's make a vector of vectors, which can be cloned. All of its element vectors will be destroyed when destroying the Vec2D. - -[ [Run this code](https://godbolt.org/z/PncareMEn) ] -```c++ -#include -#include - -#define T Vec, float -#define i_use_cmp // enable default ==, < and hash operations -#include - -#define T Vec2D -#define i_keyclass Vec // Use i_keyclass when key type has "members" _clone() and _drop(). -#define i_use_eq // vec does not have _cmp(), but it has _eq() -#include - -// The above may be written as a one-liners (note the c_-prefix instead of i_): -// #define T Vec, float, (c_use_cmp) -// #include -// #define T Vec2D, Vec, (c_keyclass | c_use_eq) -// #include - -int main(void) -{ - Vec* v; - Vec2D vec_a = {0}; // All containers in STC can be initialized with {0}. - v = Vec2D_push(&vec_a, Vec_init()); // push() returns a pointer to the new element in vec. - Vec_push(v, 10.f); - Vec_push(v, 20.f); - - v = Vec2D_push(&vec_a, Vec_init()); - Vec_push(v, 30.f); - Vec_push(v, 40.f); - - Vec2D vec_b = c_make(Vec2D, { - c_make(Vec, {10.f, 20.f}), - c_make(Vec, {30.f, 40.f}), - }); - printf("vec_a == vec_b is %s.\n", Vec2D_eq(&vec_a, &vec_b) ? "true":"false"); - - Vec2D clone = Vec2D_clone(vec_a); // Make a deep-copy of vec - - for (c_each(i, Vec2D, clone)) // Loop through the cloned vector - for (c_each(j, Vec, *i.ref)) - printf(" %g", *j.ref); - - c_drop(Vec2D, &vec_a, &vec_b, &clone); // Free all 9 vectors. -} -``` -This example uses four different container types: - -[ [Run this code](https://godbolt.org/z/fdavvGoE8) ] - -```c++ -#include - -#define T hset_int, int -#include // unordered/hash set (assume i_key is basic type, uses `==` operator) - -struct Point { float x, y; }; -// Define cvec_pnt and enable linear search by defining i_eq -#define T vec_pnt, struct Point -#define i_eq(a, b) (a->x == b->x && a->y == b->y) -#include // vector of struct Point - -// enable sort/search. Use native `<` and `==` operators -#define T list_int, int, (c_use_cmp) -#include // singly linked list - -#define T smap_int, int, int -#include // sorted map int => int - -int main(void) -{ - // Define four empty containers - hset_int set = {0}; - vec_pnt vec = {0}; - list_int lst = {0}; - smap_int map = {0}; - c_defer( // Drop the containers at scope exit - hset_int_drop(&set), - vec_pnt_drop(&vec), - list_int_drop(&lst), - smap_int_drop(&map) - ){ - enum{N = 5}; - int nums[N] = {10, 20, 30, 40, 50}; - struct Point pts[N] = {{10, 1}, {20, 2}, {30, 3}, {40, 4}, {50, 5}}; - int pairs[N][2] = {{20, 2}, {10, 1}, {30, 3}, {40, 4}, {50, 5}}; - - // Add some elements to each container - for (int i = 0; i < N; ++i) { - hset_int_insert(&set, nums[i]); - vec_pnt_push(&vec, pts[i]); - list_int_push_back(&lst, nums[i]); - smap_int_insert(&map, pairs[i][0], pairs[i][1]); - } - - // Find an element in each container - hset_int_iter i1 = hset_int_find(&set, 20); - vec_pnt_iter i2 = vec_pnt_find(&vec, (struct Point){20, 2}); - list_int_iter i3 = list_int_find(&lst, 20); - smap_int_iter i4 = smap_int_find(&map, 20); - - printf("\nFound: %d, (%g, %g), %d, [%d: %d]\n", - *i1.ref, i2.ref->x, i2.ref->y, *i3.ref, - i4.ref->first, i4.ref->second); - - // Erase all the elements found - hset_int_erase_at(&set, i1); - vec_pnt_erase_at(&vec, i2); - list_int_erase_at(&lst, i3); - smap_int_erase_at(&map, i4); - - printf("After erasing the elements found:"); - printf("\n set:"); - for (c_each(i, hset_int, set)) - printf(" %d", *i.ref); - - printf("\n vec:"); - for (c_each(i, vec_pnt, vec)) - printf(" (%g, %g)", i.ref->x, i.ref->y); - - printf("\n lst:"); - for (c_each(i, list_int, lst)) - printf(" %d", *i.ref); - - printf("\n map:"); - for (c_each(i, smap_int, map)) - printf(" [%d: %d]", i.ref->first, i.ref->second); - } -} -``` - -
-
-Performance - -## Performance - -STC is a fast and memory efficient library, and code compiles fast: - -![Benchmark](docs/pics/Figure_1.png) - -Benchmark notes: -- The barchart shows average test times over three compilers: **Mingw64 13.1.0, Win-Clang 16.0.5, VC-19-36**. CPU: **Ryzen 7 5700X**. -- Containers uses value types `uint64_t` and pairs of `uint64_t` for the maps. -- Black bars indicates performance variation between various platforms/compilers. -- Iterations and access are repeated 4 times over n elements. -- access: no entryfor *forward_list*, *deque*, and *vector* because these c++ containers does not have native *find()*. -- **deque**: *insert*: n/3 push_front(), n/3 push_back()+pop_front(), n/3 push_back(). -- **map and unordered map**: *insert*: n/2 random numbers, n/2 sequential numbers. *erase*: n/2 keys in the map, n/2 random keys. -
-
-Some unique features of STC - -## Some unique features of STC - -1. ***Centralized analysis of template parameters***. The analyser assigns values to all -non-specified template parameters using meta-programming. You may specify a set of "standard" -template parameters for each container, but as a minimum *only one is required*: `T` or -`i_key` (+ `i_val` for maps). In this case, STC assumes that the elements are of basic types. -For non-trivial types, additional template parameters must be given. -2. ***Alternative lookup and insert type***. Specify an alternative type to use for -lookup in containers. E.g., containers with STC string elements (**cstr**) uses `const char*` -as lookup type. Therefore it is not needed to construct (or destroy) a `cstr` in order -to lookup a **cstr** object. Also, one may pass a c-string literal to one of the -***emplace***-functions to implicitly insert a cstr object, i.e. `vec_cstr_emplace(&vec, "Hello")` -as an alternative to `vec_cstr_push(&vec, cstr_from("Hello"))`. -3. ***Standardized container iterators***. All containers can be iterated in the same manner, and all use the -same element access syntax. The following works for single-element type containers, e.g a linked list: -```c++ -#define T MyInts, int -#include -... -MyInts ints = c_make(MyInts, {3, 5, 9, 7, 2}); -for (c_each(it, MyInts, ints)) *it.ref += 42; -``` -
-
-Naming rules - -## Naming rules - -- Naming conventions - - Non-templated container names are prefixed by `c`, e.g. `cstr`, `cbits`, `cregex`. - - Public STC macros and "keywords" are prefixed by `c_`, e.g. `c_each`, `c_make`. - - Template parameter macros are prefixed by `i_`, e.g. `i_key`, `T`. - - All owning containers can be initialized with `{0}` (also `cstr`), i.e. no heap allocation initially. - -- Common types defined for any container type Cnt: - - Cnt - - Cnt_value - - Cnt_raw - - Cnt_iter - -- Functions defined for most container types: - - Cnt_init() -> Cnt - - Cnt_with_capacity(isize capacity) -> Cnt - - Cnt_from_n(Cnt_value[], isize n) -> Cnt - - Cnt_reserve(Cnt*, isize capacity) - - Cnt_move(Cnt*) -> Cnt - - Cnt_take(Cnt*, Cnt unowned) - - Cnt_copy(Cnt*, const Cnt* other) - - Cnt_clone(Cnt other) -> Cnt - - Cnt_drop(Cnt*) - - Cnt_value_drop(Cnt_value*) - - Cnt_value_toraw(Cnt_value*) -> Cnt_raw - - Cnt_capacity(Cnt*) -> isize - - Cnt_size(Cnt*) -> isize - - Cnt_is_empty(Cnt*) -> bool - - Cnt_put_n(Cnt*, Cnt_value[], isize n) - - Cnt_push(Cnt*, Cnt_value) - - Cnt_emplace(Cnt*, Cnt_raw) - - Cnt_erase_at(Cnt*, Cnt_iter) - - Cnt_at(Cnt*, isize index OR Cnt_raw) -> Cnt_value* - - Cnt_find(Cnt*, Cnt_raw) -> Cnt_iter - - Cnt_front(Cnt*) -> Cnt_value* - - Cnt_back(Cnt*) -> Cnt_value* - - Cnt_begin(Cnt*) -> Cnt_iter - - Cnt_end(Cnt*) -> Cnt_iter - - Cnt_next(Cnt_iter*) - - Cnt_advance(Cnt_iter, isize n) -> Cnt_iter -
-
-Defining template parameters - -## Defining template parameters - -The container template parameters are specified with a `#define i_xxxx` statement. Each templated -type instantiation requires an `#include` statement, even if the same container base type was -included earlier. Normally it is sufficient to only define `T` before including a container: - -```c -#define T ContainerType, KeyType[, ValType][, (Options)] -``` - -Examples of container definitions: - -A sortedmap of **int** => **float**: -```c++ -#define T IntfMap, int, float -#include -``` - -A hashmap of **int** => string -```c++ -#define T StrMap, int, cstr, (c_valpro) // cstr is a "pro" type -#include -``` - -A vector of searchable string vectors: -```c++ -#define T StrVec, cstr, (c_keypro | c_use_eq) // enable vector linear search (find). -#include -#define T StrVecVec, StrVec, (c_keyclass) // container as element has "class" properties -#include -``` -The **c_keypro** and **c_keyclass** are *options*, and is specified as the last comma-separated argument -of the `T` template parameter. They associate the (key) element type name with a set of standard -named "member" functions and assigns them to template parameters. These are then used during the -implementation of the container. NB! Note that the associated/bound "member" functions are only -required to be implemented if the container actually use them. Option flags are boolean properties, -and may be combined with the `|` operator. Below is a complete list of *options* that may be -specified for a container: - - - **c_cmpclass** - `i_key` binds _cmp(), _eq() and _hash() member names. - - **c_keyclass** - `i_key` binds _clone(), _drop(), _cmp(), _eq(), and _hash() member names. - - **c_valclass** - `i_val` binds _clone() and _drop() member names for sortedmaps / hashmaps. - - **c_keypro** - `i_key` is a "keyclass" with an associated "cmpclass"-type named KeyType_raw (see below). - - **c_valpro** - `i_val` is a "valclass" with an associated "raw"-type named ValType_raw. - - **c_use_cmp** - enable `<` comparison on integral types, or the _cmp() member on "pro/class" elements. - - **c_use_eq** - enable `==` on integral types, or the _eq() member on "pro/class" elements. - - **c_no_clone** - disable clone functionality in container - - **c_no_atomic** - used with **arc** type, do simple reference counting instead of atomic. - - **c_no_hash** - don't enable hash function when "cmpclass" is specified. - - **c_declared** - container type was predeclared - -Bound element "member" functions when **c_keyclass** / **c_valclass** / **c_cmpclass** are specified: -```c++ -int KeyType_cmp(const KeyType* x, const KeyType* y); -bool KeyType_less(const KeyType* x, const KeyType* y); -bool KeyType_eq(const KeyType* x, const KeyType* y); -size_t KeyType_hash(const KeyType* kp); -KeyType KeyType_clone(KeyType k); -void KeyType_drop(KeyType* kp); - -ValType ValType_clone(ValType v); -void ValType_drop(ValType* vp); -``` - -**Notes**: -- **c_use_cmp** is only needed for **vec**, **stack**, **deque**, **list**, as sorting -and linear seach are not enabled by default for them. Maps/sets/priority queues enables -these by default. -- Comparison uses `<` and `==` operators by default whereas when **class/pro** are specified, it -uses the _cmp() member function by default. However, the _cmp() member is also used for -equality comparison, so **c_use_eq** has to be specified in order to use the _eq() member! -- For plain structs (PODs), define `i_cmp` / `i_eq` / `i_hash` macros when needed, or make it -into a "class" by defining required "member" functions, and use the class-options described. - -#### The **c_keypro** and **c_valpro** options (properties) -The **c_cmpclass**'s type is equal to the `i_key` type. However, it is posible to -- `i_cmpclass` *RawType* - -#### Key type template parameters (advanced usage) -The assosicated element "member" functions defined from using meta-template parameters may also be -specified/overridden by defining specific template parameters before including the container. -Only `i_key` is strictly required to be defined for simple non-maps: - -- `i_key` *KeyType* - Element type. -- `i_keyclass` *KeyType* - Meta template parameter -- `i_cmpclass` *KeyRaw* - Meta template parameter (defaults to *KeyType*) - - `i_keyfrom` *Func* - Conversion from *KeyRaw* to *KeyType*. - - `i_keytoraw` *Func* - Conversion from *KeyType* to *KeyRaw*. -- `i_cmp` *Func* - Three-way comparison of two *KeyRaw* elements, given as pointers. -- `i_less` *Func* - Comparison of two *KeyRaw* elements. Alternative to specifying *i_cmp*. -- `i_eq` *Func* - Equality comparison of two *KeyRaw*. Defaults to *!i_cmp(x,y)*. -- `i_hash` *Func* - Hash function taking a *KeyRaw* pointer. Companion with *i_eq*. - **[required]** for **hmap** and **hset** unless *KeyRaw* is an integral type (or a struct with no padding space). -- `i_keyclone` *Func* - **[required if]** *i_keydrop* is defined (exception for **arc**, as it shares). -- `i_keydrop` *Func* - Destroy key - defaults to empty destructor. - -Bound key-element member functions when `i_keyclass` and/or `i_cmpclass` parameters are specified: -```c++ -int KeyType_cmp(const KeyRaw* rx, const KeyRaw* ry); -bool KeyType_less(const KeyRaw* rx, const KeyRaw* ry); -bool KeyType_eq(const KeyRaw* rx, const KeyRaw* ry); -size_t KeyType_hash(const KeyRaw* rp); -KeyType KeyType_from(KeyRaw r); -KeyRaw KeyType_toraw(const KeyType* kp); -KeyType KeyType_clone(KeyType k); -void KeyType_drop(KeyType* kp); -``` - -#### Val type template parameters (mapped value type for maps) -- `i_val` *ValType* - **[required]** for **hmap** and **smap** containers. -- `i_valraw` *ValRaw* - Alternative input type (converted to/from *ValType*). Defaults to *ValType* - - `i_valfrom` *Func* - Conversion from *ValRaw* to *ValType*. - - `i_valtoraw` *Func* - Conversion from *ValType* to *ValRaw*. -- `i_valclone` *Func* - **[required if]** *i_valdrop* is defined (exception for **arc**, as it shares). -- `i_valdrop` *Func* - Destroy mapped val - defaults to empty destructor. - -Bound mapped-element member functions when `i_valraw` / `i_val` is specified: -```c++ -ValType ValType_from(ValRaw r); -ValRaw ValType_toraw(const ValType* vp); -ValType ValType_clone(ValType v); -void ValType_drop(ValType* vp); -``` - ---- - -### Meta template parameters (advanced / internal) -Normally it is simplest to specify the meta-template parameters via the *option* argument to `T`, -however, they can be specified as separate template parameters as well. Specifically, `i_cmpclass` -can be specified as a different type than `i_key` (**c_cmpclass** always makes it equal to `i_key`). -This enables a container to be associated with an additional alternative "raw" input key/val-type, -and one may specify convertion functions between them. Specifically the string, **cstr** and smart -pointers, **box** and **arc** uses this to enhance ergonmics, but every containers may gain efficiency -and usage enhancements from this general built-in mechanism. - -- `i_cmpclass` *RawType* - Defines ***i_keyraw*** and binds ***i_cmp***, ***i_eq***, and ***i_hash*** to -*RawType_cmp()*, *RawType_eq()*, and *RawType_hash()* comparison functions/macro names. In addition -***i_keyfrom***, ***i_keytoraw*** are bound to conversion functions *KeyType_from(RawType\*)* and *KeyType_toraw()*. - - If neither ***i_key*** nor ***i_keyclass*** are defined, ***i_key*** will be defined as *RawType*. In this case, - ***i_keyfrom***, ***i_keytoraw*** are bound to default pass-through conversion macros. - - Useful alone for containers of views (like csview) - may use **c_cmpclass** option in that case. -- `i_keyclass` *KeyType* - - Defines ***i_key*** and binds ***i_keyclone***, ***i_keydrop*** to *KeyType_clone()* and *KeyType_drop()* - function/macro names. - - Unless `i_cmpclass` or `i_keyraw` are also specified, comparison functions associated with ***i_cmpclass*** are - also bound. - - Use with container of containers, or in general when the element type has *_clone()* and *_drop()* - "member" functions. -- `i_keypro` *KeyType* - Use with "pro"-element types, i.e. library types like **cstr**, **box** and **arc**. -It combines the ***i_keyclass*** and ***i_cmpclass*** properties. Defining ***i_keypro*** is equal to defining - - ***i_cmpclass*** *KeyType_raw*. - - ***i_keyclass*** *KeyType* - - I.e. `i_key`, `i_keyclone`, `i_keydrop`, `i_keyraw`, `i_keyfrom`, `i_keytoraw`, `i_cmp`, `i_eq`, `i_hash` - will all be textually bound to function names. See the vikings.c example on how to create and instantiate - a self-made pro-type. - -#### Val meta parameters -- `i_valclass` *MappedType* - Analogous to the ***i_keyclass***, except for comparison and hash funcs. -- `i_valpro` *MappedType* - Comparison/lookup functions are not relevant for the mapped type, so this defines - - ***i_valraw*** *MappedType_raw* (used by *emplace* and *c_make* functions only) - - ***i_valclass*** *MappedType* - - I.e. `i_val`, `i_valclone`, `i_valdrop`, `i_valraw`, `i_valfrom`, `i_valtoraw` will all be defined/bound. - -#### Conversion between an alternative key/val type -- `i_keyraw` *RawType* - Lookup/emplace-function argument "raw" type. Defaults to *i_key*. -- `i_keyfrom` *Func(r)* - Conversion func from a *i_keyraw* to return a *i_key* type. -- `i_keytoraw` *Func(p)* - Conversion func from a *i_key* pointer to a *i_keyraw* type. **[required]** if *i_keyraw* was defined. By default, it returns the dereferenced *i_key* value. -- `i_valraw` *RawType* - Emplace-function argument "raw" type. Defaults to *i_val*. -- `i_valfrom` *Func(r)* - Conversion func from a *i_valraw* to return a *i_val* type. -- `i_valtoraw` *Func(p)* - Conversion func from a *i_val* pointer to a *i_valraw* type. - -
-
-Specifying comparison parameters - -## Specifying comparison parameters - -The table below shows the template parameters which *must* be defined to support element search/lookup and sort for various container type instantiations. - -For the containers marked ***optional***, the features are disabled if the template parameter(s) are not defined. Note that the ***(integral type)*** columns also applies to "special" key-types, specified with `i_keyclass` (so not only for true integral types like `int` or `float`). - -| Container | search (integral type) | sort (integral type) |\|| search (struct elem) | sort (struct elem) | optional | -|:------------------|:---------------------|:---------------------|:-|:-----------------|:-------------------|:---------| -| vec, deque, list | `i_use_cmp` | `i_use_cmp` || `i_eq` | `i_cmp` / `i_less` | yes | -| stack | n/a | `i_use_cmp` || n/a | `i_cmp` / `i_less` | yes | -| box, arc | `i_use_cmp` | `i_use_cmp` || `i_eq` + `i_hash` | `i_cmp` / `i_less` | yes | -| hmap, hset | | n/a || `i_eq` + `i_hash` | n/a | no | -| smap, sset | | || `i_cmp` / `i_less` | `i_cmp` / `i_less` | no | -| pqueue | n/a | || n/a | `i_cmp` / `i_less` | no | -| queue | n/a | n/a || n/a | n/a | n/a | - -
-
-The emplace methods - -## The *emplace* methods - -STC, like c++ STL, has two sets of methods for adding elements to containers. One set begins -with **emplace**, e.g. *vec_X_emplace_back()*. This is an ergonimic alternative to -*vec_X_push_back()* when dealing non-trivial container elements, e.g. strings, shared pointers or -other elements using dynamic memory or shared resources. - -The **emplace** methods ***construct*** / ***clone*** the given raw-type element when it is added -to the container (specified normally using i_keypro/i_valpro or i_cmpclass or the c_-option variants). -In contrast, the *non-emplace* methods ***moves*** the element into the container. - -**Note**: For containers with integral/trivial element types, or when neither `i_keyraw/i_valraw` is defined, -the **emplace** functions are ***not*** available (or needed), as it can easier lead to mistakes. - -| non-emplace: Move | emplace: Embedded copy | Container | -|:---------------------------|:-------------------------------|:----------------------------| -| insert(), push() | emplace() | hmap, smap, hset, sset | -| insert_or_assign() | emplace_or_assign() | hmap, smap | -| push() | emplace() | queue, pqueue, stack | -| push_back(), push() | emplace_back() | deque, list, vec | -| push_front() | emplace_front() | deque, list | - -Strings are the most commonly used non-trivial data type. STC containers have proper pre-defined -definitions for cstr container elements, so they are fail-safe to use both with the **emplace** -and non-emplace methods: -```c++ -#include - -#define i_keypro cstr // use i_keypro for "pro" types like cstr, arc, box -#include // vector of string (cstr) -... -vec_cstr vec = {0}; -cstr s = cstr_lit("a string literal"); -const char* hello = "Hello"; - -vec_cstr_push(&vec, cstr_from(hello); // make a cstr from const char* and move it onto vec -vec_cstr_push(&vec, cstr_clone(s)); // make a cstr clone and move it onto vec - -vec_cstr_emplace(&vec, "Yay, literal"); // internally make a cstr from const char* -vec_cstr_emplace(&vec, cstr_clone(s)); // <-- COMPILE ERROR: expects const char* -vec_cstr_emplace(&vec, cstr_str(&s)); // Ok: const char* input type. - -cstr_drop(&s) -vec_cstr_drop(&vec); -``` -This is made possible because the type configuration may be given an optional -conversion/"rawvalue"-type as template parameter, along with a back and forth conversion -methods to the container value type. - -Rawvalues are primarily beneficial for **lookup** and **map insertions**, however the -**emplace** methods constructs `cstr`-objects from the rawvalues, but only when required: -```c++ -hmap_cstr_emplace(&map, "Hello", "world"); -// Two cstr-objects were constructed by emplace - -hmap_cstr_emplace(&map, "Hello", "again"); -// No cstr was constructed because "Hello" was already in the map. - -hmap_cstr_emplace_or_assign(&map, "Hello", "there"); -// Only cstr_lit("there") constructed. "world" was destructed and replaced. - -hmap_cstr_insert(&map, cstr_lit("Hello"), cstr_lit("you")); -// Two cstr's constructed outside call, but both destructed by insert -// because "Hello" existed. No mem-leak but less efficient. - -it = hmap_cstr_find(&map, "Hello"); -// No cstr constructed for lookup, although keys are cstr-type. -``` -Apart from strings, maps and sets are normally used with trivial value types. However, the -last example on the **hmap** page demonstrates how to specify a map with non-trivial keys. -
-
-The erase methods - -## The *erase* methods - -| Name | Description | Container | -|:--------------------------|:-----------------------------|:-----------------------------------------| -| erase() | key based | smap, sset, hmap, hset, cstr | -| erase_at() | iterator based | smap, sset, hmap, hset, vec, deque, list | -| erase_range() | iterator based | smap, sset, vec, deque, list | -| erase_n() | index based | vec, deque, cstr | -| remove() | remove all matching values | list | -
-
-User-defined container type name - -## User-defined container type name - -Define `T` and/or `i_key`: -```c++ -// #define T MyVec, int // shorthand -#define T MyVec -#define i_key int -#include - -MyVec vec = {0}; -MyVec_push(&vec, 42); -... -``` -
-
-Pre-declarations - -## Pre-declarations -Pre-declare templated container in header file. The container can then e.g. be a member of a -struct defined in a header file. -- If the container will use an auxiliary member the with `i_aux AuxType` parameter, the declaration -must also add it as the last argument: `declare_vec_aux(VecType, Element, AuxType)`. -- Up to, but not including C23, a `(c_declared)` option must be specified when defining the container. -See example below. - -```c++ -// Dataset.h -#ifndef Dataset_H_ -#define Dataset_H_ -#include // include various container data structure templates - -// declare PointVec as a vec. Also struct Point may be incomplete/undeclared. -declare_vec(PointVec, struct Point); - -typedef struct Dataset { - PointVec vertices; - PointVec colors; -} Dataset; - -void Dataset_drop(Dataset* self); -... -#endif -``` - -Define and use the "private" container in the c-file: -```c++ -// Dataset.c -#include "Dataset.h" -#include "Point.h" // struct Point must be defined here. - -#define T PointVec, struct Point, (c_declared) // Was pre-declared. -#include // Implements PointVec with static linking by default -... -``` -
-
-Per container-instance customization - -## Per container-instance customization -Sometimes it is useful to extend a container type to store extra data, e.g. a comparison -or allocator function pointer or a context which the function pointers can use. Most -libraries solve this by adding an opaque pointer (void*) or function pointer(s) into -the data structure for the user to manage. Because most containers are templated, -an auxiliary template parameter, `i_aux` may be defined to extend the container with -typesafe custom attributes. - -The example below shows how to customize containers to work with PostgreSQL memory management. -It adds a MemoryContext to each container by defining the `i_aux` template parameter. -`i_aux` may define a struct on the fly, or refer to an already defined type. -Note that `pgs_realloc` and `pgs_free` is also passed the -allocated size of the given pointer, unlike standard `realloc` and `free`. - -`self->aux` is accessible from the following template parameters / container combinations: -- `i_allocator`: **all containers** -- `i_eq` : **all containers** -- `i_cmp`, `i_less`: **all containers except hmap and hset** -- `i_hash`: **hmap and hset** - -```c++ -// pgs_alloc.h -#define pgs_malloc(sz) MemoryContextAlloc(self->aux.memctx, sz) -#define pgs_calloc(n, sz) MemoryContextAllocZero(self->aux.memctx, (n)*(sz)) -#define pgs_realloc(p, old_sz, sz) (p ? repalloc(p, sz) : pgs_malloc(sz)) -#define pgs_free(p, sz) (p ? pfree(p) : (void)0) // pfree/repalloc does not accept NULL. - -#define i_aux struct { MemoryContext memctx; } -#define i_allocator pgs -#define i_no_clone -``` -Usage is straight forward: -```c++ -#define T IMap, int, int -#include "pgs_alloc.h" -#include - -void maptest() -{ - IMap map = {.aux={ - AllocSetContextCreate(CurrentMemoryContext, "MapContext", ALLOCSET_DEFAULT_SIZES) - }}; - for (c_range(i, 1, 16)) - IMap_insert(&map, i*i, i); // uses pgs_realloc() - - for (c_each(i, IMap, map)) - printf("%d:%d ", i.ref->first, i.ref->second); - - IMap_drop(&map); // uses psg_free() - MemoryContextDelete(map.aux.memctx); -} -``` -Another example is to sort struct elements by the *active field* and *reverse* flag: - -[ [Run this code](https://godbolt.org/z/eqrGGzbKh) ] -```c++ -#include -#include -#include -#include - -typedef struct { - cstr fileName; - cstr directory; - isize size; - time_t lastWriteTime; -} FileMetaData; - -enum FMDActive {FMD_fileName, FMD_directory, FMD_size, FMD_lastWriteTime, FMD_LAST}; -typedef struct { enum FMDActive activeField; bool reverse; } FMDVectorSorting; - -int FileMetaData_cmp(const FMDVectorSorting*, const FileMetaData*, const FileMetaData*); -void FileMetaData_drop(FileMetaData*); - -#define T FMDVector, FileMetaData, (c_keyclass | c_no_clone) -#define i_aux FMDVectorSorting -#define i_cmp(x, y) FileMetaData_cmp(&self->aux, x, y) -#include -// -------------- - -int FileMetaData_cmp(const FMDVectorSorting* aux, const FileMetaData* a, const FileMetaData* b) { - int dir = aux->reverse ? -1 : 1; - switch (aux->activeField) { - case FMD_fileName: return dir*cstr_cmp(&a->fileName, &b->fileName); - case FMD_directory: return dir*cstr_cmp(&a->directory, &b->directory); - case FMD_size: return dir*c_default_cmp(&a->size, &b->size); - case FMD_lastWriteTime: return dir*c_default_cmp(&a->lastWriteTime, &b->lastWriteTime); - default:; - } - return 0; -} - -void FileMetaData_drop(FileMetaData* fmd) { - cstr_drop(&fmd->fileName); - cstr_drop(&fmd->directory); -} - -int main(void) { - FMDVector vec = c_make(FMDVector, { - {cstr_from("WScript.cpp"), cstr_from("code/unix"), 3624, 123567}, - {cstr_from("CanvasBackground.cpp"), cstr_from("code/unix/canvas"), 38273, 12398}, - {cstr_from("Brush_test.cpp"), cstr_from("code/tests"), 67236, 7823}, - }); - - vec.aux.reverse = true; - for (c_range_t(enum FMDActive, field, FMD_LAST)) { - vec.aux.activeField = field; - FMDVector_sort(&vec); - - for (c_each(i, FMDVector, vec)) { - fmt_println("{:30}{:30}{:10}{:10}", - cstr_str(&i.ref->fileName), cstr_str(&i.ref->directory), - i.ref->size, i.ref->lastWriteTime); - } - puts(""); - } - FMDVector_drop(&vec); -} -``` -
-
-Extended templated containers (advanced) - -## Extended templated containers - -It is possible to extend the functionality of templated container by adding functions to them, -while having all the input and derived/defaulted template parameters available. Below we add -an alias function `_len()` for `_size()` in a new file "extvec.h", which can be used like stc/vec.h: -```c++ -// extvec.h -#define i_extend -#include - -STC_INLINE isize _c_MEMB(_len)(Self* self) { - return _c_MEMB(_size)(self); -} - -#include -``` -
-
-Memory efficiency - -## Memory efficiency - -STC is generally very memory efficient. Memory usage for the different containers: -- **cstr**, **vec**, **stack**, **pqueue**: 1 pointer, 2 isize + memory for elements. -- **csview**, 1 pointer, 1 isize. Does not own data! -- **cspan**, 1 pointer and 2 \* dimension \* int32_t. Does not own data! -- **list**: Type size: 1 pointer. Each node allocates a struct to store its value and a next pointer. -- **deque**, **queue**: Type size: 2 pointers, 2 isize. Otherwise like *vec*. -- **hmap/hset**: Type size: 2 pointers, 2 int32_t (default). *hmap* uses one table of keys+value, and one table of precomputed hash-value/used bucket, which occupies only one byte per bucket. The closed hashing has a default max load factor of 85%, and hash table scales by 1.5x when reaching that. -- **smap/sset**: Type size: 1 pointer. *smap* manages its own ***array of tree-nodes*** for allocation efficiency. Each node uses two 32-bit ints for child nodes, and one byte for `level`, but has ***no parent node***. -- **arc**: Type size: 1 pointer, 1 long for the shared reference counter + memory for the shared element. -- **arc2**: Type size: 2 pointers, 1 long for the shared reference counter + memory for the shared element. -- **box**: Type size: 1 pointer + memory for the pointed-to element. -
- -
-Version history - -## Version history - -## Version 5.0 changes -- This is a major new version, with serveral breaking changes compared to 4.3 - - Some API changes in `cregex`. - - Some API changes in `cstr` and `csview`. - - Renamed czsview type to `zsview`, some API changes. - - Renamed all member Container_empty() functions to `Container_is_empty()`. - - Changed API in `random` numbers. - - c_init renamed to `c_make` - - c_forlist renamed to `c_foritems` - - c_forpair *replaced by* `c_each_kv` (changed API). - - Renamed all functions stc_\() to `c_()` in common.h. - - c_SVFMT(sv) renamed tp `c_svfmt(sv)` - - c_SVARG(sv) renamed tp `c_svarg(sv)` - - Renamed coroutine cco_yield() to "keyword" `cco_yield`. - - Swapped 2nd and 3rd argument in `c_fortoken()` to make it consistent with all other `c_for*()`, i.e, input object is third last. - - New header `vec.h` renamed from cvec.h - - New header `deque.h` renamed from cdeq.h - - New header `list.h` renamed from clist.h - - New header `stack.h` renamed from cstack.h - - New header `queue.h` renamed from cqueue.h - - New header `pqueue.h` renamed from cpque.h - - New header `hmap.h` renamed from cmap.h - - New header `hset.h` renamed from cset.h - - New header `smap.h` renamed from csmap.h - - New header `sset.h` renamed from csset.h - - New header `zsview.h` renamed from czview.h - - New header `random.h` renamed from crand.h - - New header `types.h` renamed from forward.h - -## Version 4.3 -- Breaking changes: - - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. - - Renamed "stc/calgo.h" => `"stc/algorithm.h"` - - Moved "stc/algo/coroutine.h" => `"stc/coroutine.h"` - - Much improved with some new API and added features. - - Removed deprecated "stc/crandom.h". Use `"stc/random.h"` with the new API. - - Reverted names _unif and _norm back to `_uniform` and `_normal`. - - Removed default comparison for **list**, **vec** and **deque**: - - Define `i_use_cmp` to enable comparison for built-in i_key types (<, ==). - - Use of `i_keyclass` still expects comparison functions to be defined. - - Renamed input enum flags for ***cregex***-functions. -- **cspan**: Added **column-major** order (fortran) multidimensional spans and transposed views (changed representation of strides). -- All new faster and smaller **queue** and **deque** implementations, using a circular buffer. -- Renamed i_extern => `i_import` (i_extern deprecated). - - Define `i_import` before `#include ` will also define full utf8 case conversions. - - Define `i_import` before `#include ` will also define cstr + utf8 tables. -- Renamed c_make() => ***c_make()*** macro for initializing containers with element lists. c_make deprecated. -- Removed deprecated uppercase flow-control macro names. -- Other smaller additions, bug fixes and improved documentation. - -## Version 4.2 -- New home! And online single headers for https://godbolt.org - - Library: https://github.com/stclib/STC - - Headers, e.g. https://raw.githubusercontent.com/stclib/stcsingle/main/stc/vec.h -- Much improved documentation -- Added Coroutines + documentation -- Added new random.h API & header. Old crandom.h is deprecated. -- Added `c_const_cast()` typesafe macro. -- Removed RAII macros usage from examples -- Renamed c_flt_count(i) => `c_flt_counter(i)` -- Renamed c_flt_last(i) => `c_flt_getcount(i)` -- Renamed c_ARRAYLEN() => c_countof() -- Removed deprecated c_ARGSV(). Use c_svarg() -- Removed c_PAIR - -## Version 4.1.1 -Major changes: -- A new exciting [**cspan**](docs/cspan_api.md) single/multi-dimensional array view (with numpy-like slicing). -- Signed sizes and indices for all containers. See C++ Core Guidelines by Stroustrup/Sutter: [ES.100](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es100-dont-mix-signed-and-unsigned-arithmetic), [ES.102](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es102-use-signed-types-for-arithmetic), [ES.106](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es106-dont-try-to-avoid-negative-values-by-using-unsigned), and [ES.107](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es107-dont-use-unsigned-for-subscripts-prefer-gslindex). -- Customizable allocator [per templated container type](https://github.com/tylov/STC/discussions/44#discussioncomment-4891925). -- Updates on **cregex** with several [new unicode character classes](docs/cregex_api.md#regex-cheatsheet). -- Algorithms: - - [crange](docs/algorithm_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - - [c_forfilter](docs/algorithm_api.md#c_forfilter) - ranges-like view filtering. - - [quicksort](include/stc/sort.h) - fast quicksort with custom inline comparison. -- Renamed `c_ARGSV()` => `c_svarg()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. -- Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in common.h. -- Some API changes in **cregex** and **cstr**. -- Create single header container versions with python script. - - -## API changes summary V4.0 -- Added **cregex** with documentation - powerful regular expressions. -- Added: `c_forfilter`: container iteration with "piped" filtering using && operator. 4 built-in filters. -- Added: **crange**: number generator type, which can be iterated (e.g. with *c_forfilter*). -- Added back **coption** - command line argument parsing. -- New + renamed loop iteration/scope macros: - - `c_foritems`: macro replacing *c_forarray* and *c_apply*. Iterate a compound literal list. -- Updated **cstr**, now always takes self as pointer, like all containers except csview. -- Updated **vec**, **deque**, changed `*_range*` function names. - -
- ---- diff --git a/src/finchlite/codegen/stc/docs/algorithm_api.md b/src/finchlite/codegen/stc/docs/algorithm_api.md deleted file mode 100644 index 4a455510..00000000 --- a/src/finchlite/codegen/stc/docs/algorithm_api.md +++ /dev/null @@ -1,782 +0,0 @@ -# STC Algorithms - -STC contains many generic algorithms and loop abstactions. Raw loops are one of the most prominent -sources for errors in C and C++ code. By using the loop abstractions below, your code becomes more -descriptive and reduces chances of making mistakes. It is generally easier to read and write too. - -## Ranged for-loop abstractions -*"No raw loops"* - Sean Parent -
-c_each - Ranged sequence iteration - -### c_each, c_each_reverse, c_each_n, c_each_kv -```c++ -#include -``` - -| Usage | Description | -|:---------------------------------------------------|:------------------------------------------| -| for (`c_each`(it, **CntType**, container)) | Iteratate all elements | -| for (`c_each`(it, **CntType**, it1, it2)) | Iterate the range [it1, it2) | -| for (`c_each_reverse`(it, **CntType**, container)) | Iteratate elements in reverse: *vec, deque, queue, stack* | -| for (`c_each_reverse`(it, **CntType**, it1, it2))` | Iteratate range [it1, it2) elements in reverse. | -| for (`c_each_n`(it, **CntType**, container, n)) | Iteratate `n` first elements. Index variable is `{it}_index`. | -| for (`c_each_kv`(key, val, **CntType**, container))| Iterate maps with "structured binding" | - -[ [Run this code](https://godbolt.org/z/xK8s5cKc9) ] -```c++ -#define T IMap, int, int -#include -// ... -IMap map = c_make(IMap, {{23,1}, {3,2}, {7,3}, {5,4}, {12,5}}); - -for (c_each(i, IMap, map)) - printf(" %d", i.ref->first); -// 3 5 7 12 23 - -// same, with raw for loop: -for (IMap_iter i = IMap_begin(&map); i.ref; IMap_next(&i)) - printf(" %d", i.ref->first); - -// iterate from iter to end -IMap_iter iter = IMap_find(&map, 7); -for (c_each(i, IMap, iter, IMap_end(&map))) - printf(" %d", i.ref->first); -// 7 12 23 - -// iterate first 3 with an index count enumeration -for (c_each_n(i, IMap, map, 3)) - printf(" %zd:(%d %d)", i.index, i.ref->first, i.ref->second); -// 0:(3 2) 1:(5 4) 2:(7 3) - -// iterate a map using "structured binding" of the key and val pair: -for (c_each_kv(id, count, IMap, map)) - printf(" (%d %d)", *id, *count); -``` - -
-
-c_items - Literal list element iteration - -### c_items -Iterate compound literal array elements. In addition to `i.ref`, you can access `i.index` and `i.size`. - -```c++ -// apply multiple push_backs -for (c_items(i, int, {4, 5, 6, 7})) - list_i_push_back(&lst, *i.ref); - -// insert in existing map -for (c_items(i, hmap_ii_value, {{4, 5}, {6, 7}})) - hmap_ii_insert(&map, i.ref->first, i.ref->second); - -// string literals pushed to a stack of cstr elements: -for (c_items(i, const char*, {"Hello", "crazy", "world"})) - stack_cstr_emplace(&stk, *i.ref); -``` - -
-
-c_range - Integer range iteration - -### c_range, c_range32, c_range_t -- `c_range`: abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop. Uses `isize` (*ptrdiff_t*) as control variable. -- `c_range32` is like *c_range*, but uses `int32_t` as control variable. -- `c_range_t` is like *c_range*, but takes an additional ***type*** for the control variable as first argument. - -| Usage | Python equivalent | -|:--------------------------------------|:-------------------------------------| -| for (`c_range`(stop)) | for _ in `range`(stop): | -| for (`c_range`(i, stop)) | for i in `range`(stop): | -| for (`c_range`(i, start, stop)) | for i in `range`(start, stop): | -| for (`c_range`(i, start, stop, step)) | for i in `range`(start, stop, step): | - -| Usage | -|:-----------------------------------------------------| -| for (`c_range_t`(**IntType**, i, stop)) | -| for (`c_range_t`(**IntType**, i, start, stop)) | -| for (`c_range_t`(**IntType**, i, start, stop, step)) | - -```c++ -for (c_range(5)) printf("x"); -// xxxxx -for (c_range(i, 5)) printf(" %lld", i); -// 0 1 2 3 4 -for (c_range(i, -3, 3)) printf(" %lld", i); -// -3 -2 -1 0 1 2 -for (c_range(i, 30, 0, -5)) printf(" %lld", i); -// 30 25 20 15 10 5 -``` -
-
-c_ffilter - Filtered range iteration - -### c_ffilter -For-loop variant of `c_filter`in generic algorithms. -```c++ -#include -#include -#define T IVec, int -#include - -int main(void) { - IVec vec = c_make(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80, - 10, 11, 12, 13, 14, 15, 80, 16, 17}); - #define ff_skipValue(i, x) (*i.ref != (x)) - #define ff_isEven(i) ((*i.ref & 1) == 0) - #define ff_square(i) (*i.ref * *i.ref) - - int sum = 0; - for (c_ffilter(i, IVec, vec, true - && c_fflt_skipwhile(i, *i.ref != 80) - && c_fflt_skip(i, 1) - && ff_isEven(i) - && ff_skipValue(i, 80) - && c_fflt_map(i, ff_square(i)) - && c_fflt_take(i, 5) - )){ - sum += *i.ref; - } - printf("sum: %d\n", sum); - IVec_drop(&vec); -} -``` -
- -## Tagged unions - -This is a tiny, robust and fully typesafe implementation of tagged unions. They work -similarly as in Zig, Odin and Rust, and is just as easy and safe to use. -Each tuple/parentesized field is an enum (tag) with an associated data type (payload), -called a *variant* of the sum type. The type itself is a **union** type, aka. a sum type. - -
-c_union - tagged union - -Synopsis: -```c++ -// Define a sum type -c_union (SumType, - (EnumTagA, UnionTypeA), - (EnumTagB, UnionTypeB), - (EnumTagC, EnumTagB_type), // use same payload type as EnumTagB - ... - (EnumTagN, UnionTypeN), // (final comma is optional) -); - -SumType c_variant(EnumTag tag, UnionType value); // Construct a tagged union variant. -bool c_is_variant(SumType* obj, EnumTag tag); // Does obj hold tag? -EnumTag_type* c_get_if(SumType* obj, EnumTag tag); // NULL if obj does does not hold the tag. -int c_variant_id(SumType* obj); // (mainly for debugging) - -// Use a sum type -c_when (SumType* obj) { - c_is(EnumTagA, EnumTagA_type* x) - ActionA(x); - c_is_same(EnumTagB, EnumTagC, EnumTagD) // same payload types (checked) - ActionBCD(obj->EnumTagB.var); - c_is(EnumTagX) c_or_is(EnumTagY) // different payload types - ActionXY(); - c_otherwise // optional, silence exhaustiveness-check - ActionElse(obj); -} - -// Use a single sum type (*) -if (c_is(SumType* obj, EnumTagX, EnumTagX_type* x)) - ActionX(x); -``` -The **c_when** statement is exhaustive. The compiler will give a warning if not all variants are -covered by **c_is** (requires `-Wall` or `-Wswitch` gcc/clang compiler flag). The first enum tag -is deliberately set to `__LINE__*1000` in order to easier detect zero/un-initialized variants -and distinguish between types (can be inspected with c_variant_id()). - -* Note: The `x` variables in the synopsis are "auto" type declared/defined - see examples. -* Caveat 1: `c_when()` and `if (c_is())` behaves like a one-iteration loop; i.e, the use of `continue` - and `break` will just break out of its block (meaning not out of any outer loop/switch). -* Caveat 2: Sum types will generally not work in coroutines because the `x` variable is local and therefore -will not be preserved across `cco_suspend` / `cco_yield..` / `cco_await..`. -* Caveat 3: The second usage (*), `c_is(obj, TAG, x)` may only be used isolated in an if-statement, like -shown or in the _drop() function of Example 2 below. - -### Example 1 - -[ [Run this code](https://godbolt.org/z/Y9hYM8We1) ] -```c++ -#include -#include - -c_union (Tree, - (Empty, bool), - (Leaf, int), - (Node, struct {int value; Tree *left, *right;}) -); - -int tree_sum(Tree* t) { - c_when (t) { - c_is(Empty) return 0; - c_is(Leaf, v) return *v; - c_is(Node, n) return n->value + tree_sum(n->left) + tree_sum(n->right); - } - return -1; -} - -int main(void) { - Tree* tree = - &c_variant(Node, {1, - &c_variant(Node, {2, - &c_variant(Leaf, 3), - &c_variant(Leaf, 4) - }), - &c_variant(Leaf, 5) - }); - - printf("sum = %d\n", tree_sum(tree)); -} -``` - -### Example 2 -This example has two sum types. The `MessageChangeColor` variant uses the `Color` sum type as -its data type (payload). Because C does not have namespaces, it is recommended to prefix the variant names with the sum type name, as with regular enums. - -[ [Run this code](https://godbolt.org/z/bM9q9h397) ] -```c++ -// https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html#destructuring-enums -#include -#include -#include - -c_union (Color, - (ColorRgb, struct {int32_t r, g, b;}), - (ColorHsv, struct {int32_t h, s, v;}) -); - -c_union (Message, - (MessageQuit, bool), - (MessageMove, struct {int32_t x, y;}), - (MessageWrite, cstr), - (MessageChangeColor, Color) -); - -void Message_drop(Message* m) { - if (c_is(m, MessageWrite, s)) - cstr_drop(s); -} - -int main(void) { - Message msg[] = { - c_variant(MessageMove, {42, 314}), - c_variant(MessageWrite, cstr_from("Attack!")), - c_variant(MessageChangeColor, c_variant(ColorHsv, {0, 160, 255})), - }; - - for (c_range(i, c_countof(msg))) - c_when (&msg[i]) { - c_is(MessageQuit) { - printf("The Quit variant has no data to destructure.\n"); - } - c_is(MessageMove, p) { - printf("Move %d in the x direction and %d in the y direction\n", p->x, p->y); - } - c_is(MessageWrite, text) { - printf("Text message: %s\n", cstr_str(text)); - } - c_is(MessageChangeColor, cc) c_when (cc) { - c_is(ColorRgb, c) - printf("Change color to red %d, green %d, and blue %d\n", c->r, c->g, c->b); - c_is(ColorHsv, c) - printf("Change color to hue %d, saturation %d, value %d\n", c->h, c->s, c->v); - } - Message_drop(&msg[i]); - } -} -``` -
- -## Generic algorithms - -
-c_make, c_put_items, c_drop - Generic container operations - -These work on any container. *c_make()* may also be used for **cspan** views. - -### c_make, c_put_items, c_drop - -- **c_make** - construct any container from an initializer list -- **c_put_items** - push (raw) values onto any container from an initializer list -- **c_drop** - drop (destroy) multiple containers of the same type - -[ [Run this code](https://godbolt.org/z/TadM4zeeb) ] - -```c++ -#include -#define T Vec, int -#include - -#define T Map, int, int -#include - -struct VecPair { Vec keys, values; } -split_map(Map map) -{ - struct VecPair out = {0}; - for (c_each_kv(k, v, Map, map)) { - Vec_push(&out.keys, *k); - Vec_push(&out.values, *v); - } - return out; -} - -int main(void) { - Vec vec = c_make(Vec, {1, 2, 3, 4, 5, 6}); - Map map = c_make(Map, {{1, 2}, {3, 4}, {5, 6}}); - - c_put_items(Vec, &vec, {7, 8, 9, 10, 11, 12}); - c_put_items(Map, &map, {{7, 8}, {9, 10}, {11, 12}}); - - for (c_each(i, Vec, vec)) - printf("%d ", *i.ref); - puts(""); - - for (c_each_kv(k, v, Map, map)) - printf("[%d %d] ", *k, *v); - puts(""); - - struct VecPair res = split_map(map); - - for (c_each(i, Vec, res.values)) - printf("%d ", *i.ref); - puts(""); - - c_drop(Vec, &vec, &res.keys, &res.values); - c_drop(Map, &map); -} -``` - -
-
-c_find, c_reverse, c_copy_to, c_erase - Container/array operations - -### c_find_if, c_find_reverse_if -Find linearily in containers using a predicate. `value` is a pointer to each element in predicate. -***outiter_ptr*** must be defined prior to call. -- void `c_find_if`(**CntType**, cnt, outiter_ptr, pred). -- void `c_find_if`(**CntType**, startiter, enditer, outiter_ptr, pred) -- void `c_find_reverse_if`(**CntType**, cnt, outiter_ptr, pred) -- void `c_find_reverse_if`(**CntType**, startiter, enditer, outiter_ptr, pred) - -### c_reverse, c_reverse_array - -- void `c_reverse`(**CntType**, cnt); // reverse a cspan, vec, stack, queue or deque type. -- void `c_reverse_array`(array, len); // reverse an array of elements. - -### c_copy_to, c_copy_if -Adds elements of any container onto a container of possible a different container type, optionally -using a predicate to filter out elements. Requires only that the element types are equal for the -two containers. `value` is the pointer to each element in predicate. See example below for usage. -- void `c_copy_to`(**CntType**, outcnt_ptr, cnt) -- void `c_copy_to`(**OutCnt**, outcnt_ptr, **CntType**, cnt) -- void `c_copy_if`(**CntType**, outcnt_ptr, cnt, pred) -- void `c_copy_if`(**OutCnt**, outcnt_ptr, **CntType**, cnt, pred) - -### c_erase_if, c_eraseremove_if -Erase linearily in containers using a predicate. `value` is a pointer to each element in predicate. -- void `c_erase_if`(**CntType**, cnt_ptr, pred). Use with ***list**, ***hmap***, ***hset***, ***smap***, and ***sset***. -- void `c_eraseremove_if`(**CntType**, cnt_ptr, pred). Use with ***stack***, ***vec***, ***deque***, and ***queue*** only. - -[ [Run this code](https://godbolt.org/z/rYoPM34Y9) ] - -```c++ -#include -#include -#include - -#define T Vec, int, (c_use_eq) -#include - -#define T List, int, (c_use_eq) -#include - -#define T Map, cstr, int, (c_keypro) -#include - -int main(void) -{ - Vec vec = c_make(Vec, {2, 30, 21, 5, 9, 11}); - Vec outvec = {0}; - - // Copy all *value > 10 to outvec. Note: `value` is a pointer to current element - c_copy_if(Vec, &outvec, vec, *value > 10); - for (c_each(i, Vec, outvec)) printf(" %d", *i.ref); - puts(""); - - // Search vec for first value > 20. - Vec_iter result; - c_find_if(Vec, vec, &result, *value > 20); - if (result.ref) printf("found %d\n", *result.ref); - - // Erase values between 20 and 25 in vec: - c_eraseremove_if(Vec, &vec, 20 < *value && *value < 25); - for (c_each(i, Vec, vec)) printf(" %d", *i.ref); - puts(""); - - // Erase all values > 20 in a linked list: - List list = c_make(List, {2, 30, 21, 5, 9, 11}); - - c_erase_if(List, &list, *value > 20); - for (c_each(i, List, list)) printf(" %d", *i.ref); - puts(""); - - // Search a sorted map from it1, for the first string containing "hello" and erase it: - Map map = c_make(Map, {{"yes",1}, {"no",2}, {"say hello from me",3}, {"goodbye",4}}); - Map_iter res, it1 = Map_begin(&map); - - c_find_if(Map, it1, Map_end(&map), &res, cstr_contains(&value->first, "hello")); - if (res.ref) Map_erase_at(&map, res); - - // Erase all strings containing "good" in the sorted map: - c_erase_if(Map, &map, cstr_contains(&value->first, "good")); - for (c_each(i, Map, map)) printf("%s, ", cstr_str(&i.ref->first)); - - c_drop(Vec, &vec, &outvec); - List_drop(&list); - Map_drop(&map); -} -``` - -
-
-c_filter, c_filter_zip, c_filter_pairwise - Ranged filtering - -### c_filter, c_filter_zip, c_filter_pairwise -Functional programming with chained `&&` filtering. `value` is the pointer to current value. -It enables a subset of functional programming like in other popular languages. - -- **Note 1**: The **_reverse** variants only works with ***vec***, ***deque***, ***stack***, ***queue*** containers. -- **Note 2**: There is also a `c_ffilter` loop variant of `c_filter`. It uses the filter namings -`c_fflt_skip(it, numItems)`, etc. - -| Usage | Description | -|:-------------------------------------|:----------------------------------| -| void `c_filter`(**CntType**, container, filters) | Filter items in chain with the && operator | -| void `c_filter_from`(**CntType**, start, filters) | Filter from start iterator | -| void `c_filter_reverse`(**CntType**, cnt, filters) | Filter items in reverse order | -| void `c_filter_reverse_from`(**CntType**, rstart, filters) | Filter reverse from rstart iterator | -| *c_filter_zip*, *c_filter_pairwise*: || -| void `c_filter_zip`(**CntType**, cnt1, cnt2, filters)` | Filter (cnt1, cnt2) items | -| void `c_filter_zip`(**CntType1**, cnt1, **CntType2**, cnt2, filters)` | May use different types for cnt1, cnt2 | -| void `c_filter_reverse_zip`(**CntType**, cnt1, cnt2, filters)` | Filter (cnt1, cnt2) items in reverse order | -| void `c_filter_reverse_zip`(**CntType1**, cnt1, **CntType2**, cnt2, filters)` | May use different types for cnt1, cnt2 | -| void `c_filter_pairwise`(**CntType**, cnt, filters)` | Filter items pairwise as value1, value2 | - -| Built-in filter | Description | -|:----------------------------------|:-------------------------------------------| -| void `c_flt_skip`(numItems) | Skip numItems (increments count) | -| void `c_flt_take`(numItems) | Take numItems only (increments count) | -| void `c_flt_skipwhile`(predicate) | Skip items until predicate is false | -| void `c_flt_takewhile`(predicate) | Take items until predicate is false | -| int `c_flt_counter`() | Increment count and return it | -| int `c_flt_getcount`() | Number of items passed skip/take/counter | -| **Type** `c_flt_map`(expr) | Map expr to current value. Input unchanged | -| **Type** `c_flt_src` | Pointer variable to current unmapped source value | -| **Type** `value` | Pointer variable to (possible mapped) value | -| For *c_filter_zip*, *c_filter_pairwise*: || -| **Type** `c_flt_map1`(expr) | Map expr to value1. Input unchanged | -| **Type** `c_flt_map2`(expr) | Map expr to value2. Input unchanged | -| **Type** `c_flt_src1`, `c_flt_src2`| Pointer variables to current unmapped source values | -| **Type** `value1`, `value2` | Pointer variables to (possible mapped) values | - -[ [Run this example](https://godbolt.org/z/rWax63bdK) ] -```c++ -#include -#define T Vec, int -#include -#include - -int main(void) -{ - Vec vec = c_make(Vec, {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10, 11, 12, 5}); - - c_filter(Vec, vec, true - && c_flt_skipwhile(*value < 3) // skip leading values < 3 - && (*value & 1) == 1 // then use odd values only - && c_flt_map(*value * 2) // multiply by 2 - && c_flt_takewhile(*value < 20) // stop if mapped *value >= 20 - && printf(" %d", *value) // print value - ); - // 6 10 14 2 6 18 - puts(""); - Vec_drop(&vec); -} -``` -
-
-c_all_of, c_any_of, c_none_of - Boolean container operations - -### c_all_of, c_any_of, c_none_of -Test a container/range using a predicate. ***result*** is output and must be declared prior to call. -- void `c_all_of`(**CntType**, cnt, bool* result, pred) -- void `c_any_of`(**CntType**, cnt, bool* result, pred) -- void `c_none_of`(**CntType**, cnt, bool* result, pred) -```c++ -#define DivisibleBy(n) (*value % (n) == 0) // `value` refers to the current element - -bool result; -c_any_of(vec_int, vec, &result, DivisibleBy(7)); -if (result) - puts("At least one number is divisible by 7"); -``` -
-
-sort, lower_bound, binary_search - Faster quicksort and binary search - -### sort, lower_bound, binary_search - -- `X` refers to the template name specified by `T` or `i_key`. -- All containers with random access may be sorted, including regular C-arrays, i.e. **stack**, **vec** -and **deque** when either `i_use_cmp`, `i_cmp` or `i_less` is defined. -- Linked **list** may also be sorted, i.e. only *X_sort()* is available. -```c++ - // Sort c-arrays by defining T and include "stc/sort.h": -void X_sort(const X array[], isize len); -isize X_lower_bound(const X array[], i_key key, isize len); -isize X_binary_search(const X array[], i_key key, isize len); - - // or random access containers when `i_less`, `i_cmp` is defined: -void X_sort(X* self); -isize X_lower_bound(const X* self, i_key key); -isize X_binary_search(const X* self, i_key key); - - // functions for sub ranges: -void X_sort_lowhigh(X* self, isize low, isize high); -isize X_lower_bound_range(const X* self, i_key key, isize start, isize end); -isize X_binary_search_range(const X* self, i_key key, isize start, isize end); -``` -`T` may be customized in the normal way, along with comparison function `i_cmp` or `i_less`. - -##### Performance -The *X_sort()*, *X_sort_lowhigh()* functions are about twice as fast as *qsort()* and comparable in -speed with *std::sort()**. Both *X_binary_seach()* and *X_lower_bound()* are about 30% faster than -c++ *std::lower_bound()*. -##### Usage examples - -[ [Run this code](https://godbolt.org/z/YE613YbT4) ] -```c++ -#define i_key int // sort a regular c-array of ints -#include -#include - -int main(void) { - int arr[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}; - ints_sort(arr, c_countof(arr)); // `ints` derived from the `i_key` name - - for (c_range(i, c_countof(arr))) - printf(" %d", arr[i]); -} -``` -```c++ -#define T MyDeq, int, (c_use_cmp) // int elements, enable sorting -#include -#include - -int main(void) { - MyDeq deq = c_make(MyDeq, {5, 3, 5, 9, 7, 4, 7}); - - MyDeq_sort(&deq); - - for (c_each(i, MyDeq, deq)) - printf(" %d", *i.ref); - puts(""); - - MyDeq_drop(&deq); -} -``` -
-
-c_defer, c_with - RAII macros - -### c_defer, c_with - -| Usage | Description | -|:--------------------------------------|:-------------------------------------------------------| -| `c_defer (deinit, ...) {}` | Defers execution of `deinit`s to end of scope | -| `c_with (init, deinit) {}` | Declare and/or initialize a variable. Defers execution of `deinit` to end of scope | -| `c_with (init, condition, deinit) {}` | Adds a predicate in order to exit early if init fails | -| `continue` | Break out of a `c_with` scope without resource leakage | -*Note*: Regular `return`, `break` and `continue` must not be used -anywhere inside a defer scope. - -```c++ -// declare and init a new scoped variable and specify the deinitialize call: -c_with (cstr str = cstr_lit("Hello"), cstr_drop(&str)) -{ - cstr_append(&str, " world"); - printf("%s\n", cstr_str(&str)); -} - -pthread_mutex_t lock; -... -// use c_with without variable declaration: -c_with (pthread_mutex_lock(&lock), pthread_mutex_unlock(&lock)) -{ - // syncronized code -} -``` - -**Example 2**: Load each line of a text file into a vector of strings: -```c++ -#include -#include - -#define i_keypro cstr -#include - -// receiver should check errno variable -vec_cstr readFile(const char* name) -{ - vec_cstr vec = {0}; // returned - c_with (FILE* fp = fopen(name, "r"), fp != NULL, fclose(fp)) - c_with (cstr line = {0}, cstr_drop(&line)) - while (cstr_getline(&line, fp)) - vec_cstr_emplace(&vec, cstr_str(&line)); - return vec; -} - -int main(void) -{ - c_with (vec_cstr vec = readFile(__FILE__), vec_cstr_drop(&vec)) - for (c_each(i, vec_cstr, vec)) - printf("| %s\n", cstr_str(i.ref)); -} -``` -
- -## Miscellaneous - -
-crange, c_iota - Integer range objects - -### crange, crange32, c_iota -An integer sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). - -- `crange` uses `isize` (ptrdiff_t) as control variable -- `crange32` is like *crange*, but uses `int32_t` as control variable, which may be faster. - -```c++ -crange crange_make(stop); // 0, 1, ... stop-1 -crange crange_make(start, stop); // start, start+1, ... stop-1 -crange crange_make(start, stop, step); // start, start+step, ... upto-not-including stop, - // step may be negative. -crange_iter crange_begin(crange* self); -void crange_next(crange_iter* it); - - -crange& c_iota(start); // l-value; NB! otherwise like crange_make(start, INTPTR_MAX) -crange& c_iota(start, stop); // l-value; otherwise like crange_make(start, stop) -crange& c_iota(start, stop, step); // l-value; otherwise like crange_make(start, stop, step) -``` - The **crange_value** type is *isize*. Variables *start*, *stop*, and *step* are of type *crange_value*. - -[ [Run this code](https://godbolt.org/z/6aaq6qTro) ] -```c++ -// 1. All primes less than 32: See below for c_filter() and is_prime() -crange r1 = crange_make(3, 32, 2); -printf("2"); // first prime -c_filter(crange, r1, true - && is_prime(*value) - && printf(" %zi", *value) -); -// 2 3 5 7 11 13 17 19 23 29 31 - -// 2. The first 11 primes: -// c_iota() can be used as argument to c_filter. -printf("2"); // first prime -c_filter(crange, c_iota(3), true - && is_prime(*value) - && (c_flt_take(10), printf(" %zi", *value)) -); -// 2 3 5 7 11 13 17 19 23 29 31 -``` -
-
-c_malloc, c_calloc, c_realloc, c_free, c_new, c_delete_n - Allocator helpers - -### c_malloc, c_calloc, c_realloc, c_free -Memory allocator wrappers which uses signed sizes. Note that the signatures for -*c_realloc()* and *c_free()* have an extra size parameter. These will be used as -default in containers unless `i_malloc`, `i_calloc`, `i_realloc`, and `i_free` are user defined. See -[Per container-instance customization](../README.md#per-container-instance-customization) -- void* `c_malloc`(isize sz) -- void* `c_calloc`(isize n, isize sz) -- void* `c_realloc`(void* old_p, isize old_sz, isize new_sz) -- void `c_free`(void* p, isize sz) - -### c_new, c_new_n, c_new_items, c_realloc_n, c_free_n, c_delete_n - -- Type\* `c_new`(**Type**, value) - Allocate *and initialize* a new object on the heap with *value*. -- Type\* `c_new_n`(**Type**, n) - Allocate an array of ***n*** new objects on the heap, *uninitialized*. -- Type\* `c_new_items`(**Type**, {v1, v2, ...}) - Allocate an array of new initialized objects on the heap. -- void\* `c_realloc_n`(arr, old_n, n) - Calls *c_realloc(arr, (old_n)\*c_sizeof \*(arr), (n)\*c_sizeof \*(arr))*. -- void `c_free_n`(arr, n) - Calls *c_free(arr, (n)\*c_sizeof \*(arr))*. -- void `c_delete_n`(**Type**, arr, n) - Calls *Type_drop(&arr[i])* and *c_free_n(arr, n)*. -```c++ -#include - -cstr* stringptr = c_new (cstr, cstr_from("Hello")); -printf("%s\n", cstr_str(stringp)); -c_delete_n(cstr, stringptr, 1); -``` -
-
-c_swap, c_countof, c_const_cast, c_safe_case - -### c_swap, c_countof, c_const_cast, c_safe_case -Side effect- and typesafe macro for swapping internals of two objects of same type: -```c++ -double x = 1.0, y = 2.0; -c_swap(&x, &y); -``` - -Return number of elements in an array. array must not be a pointer! -```c++ -int array[] = {1, 2, 3, 4}; -isize n = c_countof(array); -``` - -Type-safe casting a from const (pointer): -```c++ -const char cs[] = "Hello"; -char* s = c_const_cast(char*, cs); // OK -int* ip = c_const_cast(int*, cs); // issues a warning! - -// Type safe casting: -#define tofloat(d) c_safe_cast(float, double, d) -``` -
- - - ---- diff --git a/src/finchlite/codegen/stc/docs/arc_api.md b/src/finchlite/codegen/stc/docs/arc_api.md deleted file mode 100644 index a13f0c54..00000000 --- a/src/finchlite/codegen/stc/docs/arc_api.md +++ /dev/null @@ -1,155 +0,0 @@ -# STC [arc](../include/stc/arc.h): Atomic Reference Counted Smart Pointer - -**arc** is a smart pointer that retains shared ownership of an object through a pointer. -Several **arc** objects may own the same object. The object is destroyed and its memory -deallocated when the last remaining **arc** owning the object is destroyed with *arc_X_drop()*; - -The object is destroyed using *arc_X_drop()*. A **arc** may also own no objects, in which -case it is called empty. The *arc_X_cmp()*, *arc_X_drop()* methods are defined based on -the `i_cmp` and `i_keydrop` macros specified. Use *arc_X_clone(p)* when sharing ownership of -the pointed-to object. Note that an arc set to NULL is consider uninitialized, and -cannot be e.g. cloned or dropped. - -All **arc** functions can be called by multiple threads on different instances of **arc** without -additional synchronization even if these instances are copies and share ownership of the same object. -**arc** uses thread-safe atomic reference counting, through the *arc_X_clone()* and *arc_X_drop()* methods. - -- ***arc type 1*** is the default arc type. It occupies the size of only one pointer, and it can convert -a raw pointer gotten from an arc back to an arc with the *X_toarc()* function. Conceptually, the arc which -passed the raw pointer should be ***moved*** (or not dropped), e.g.: -```c++ -Arc a1 = Arc_make(value); -Value* vp = Arc_move(&a1).get; // a1 will now be NULL -Arc a2 = Arc_toarc(vp); -c_drop(Arc, &a1, &a2); -``` -- ***arc type 2*** occupies the size of two pointers, however it may also be constructed from a existing unmanaged -pointer. Enable it by `#define T Arc, key, (c_arc2)` -- When defining a container with shared pointer elements, add *c_keypro*/*valpro*: `#define T MyVec, MyArc, (c_keypro)` - -See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) for a functional reference, or Rust [std::sync::Arc](https://doc.rust-lang.org/std/sync/struct.Arc.html) / [std::rc::Rc](https://doc.rust-lang.org/std/rc/struct.Rc.html). - -## Header file and declaration - -```c++ -#define T ,[,] // shorthand -#define T // arc container type name -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -#define i_use_cmp // may be defined instead of i_cmp when i_key is an integral/native-type. -#define i_cmp // three-way element comparison. If not specified, pointer comparison is used. - // Note that containers of arcs will derive i_cmp from the i_key type - // when using arc in containers specified with i_keypro . -#define i_less // less comparison. Alternative to i_cmp -#define i_eq // equality comparison. Implicitly defined with i_cmp, but not i_less. - -#define i_keydrop // destroy element func - defaults to empty destruct -#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. - -#define i_keyraw // conversion type (lookup): defaults to {i_key} -#define i_keytoraw // conversion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. -#define i_keyfrom // from-raw func. - -#define i_no_atomic // Non-atomic reference counting, like Rust Rc. -#define i_opt c_no_atomic // Same as above, but can combine other options on one line with |. -#include -``` -When defining a container with **arc** elements, specify `#define i_keypro ` instead of `i_key`. - -In the following, `X` is the value of `i_key` unless `T` is defined. - -## Methods -```c++ -arc_X arc_X_init(); // empty shared pointer -arc_X arc_X_from(i_keyraw raw); // create an arc from raw type (available if i_keyraw defined by user). -arc_X arc2_X_from_ptr(i_key* ptr); // NB! arc2 only: create an arc from raw pointer. Takes ownership of p. -arc_X arc_X_make(i_key key); // create an arc from constructed key object. Faster than from_ptr(). - -arc_X arc_X_clone(arc_X other); // return other with increased use count -void arc_X_assign(arc_X* self, const arc_X* other); // shared assign (increases use count) -void arc_X_take(arc_X* self, arc_X unowned); // take ownership of unowned. -arc_X arc_X_move(arc_X* self); // transfer ownership to receiver; self becomes NULL -arc_X arc1_X_toarc(i_key* ptr); // NB! arc1 only: convert raw pointer previously created by arc back to arc. -void arc_X_drop(const arc_X* self); // destruct (decrease use count, free at 0) - -long arc_X_use_count(arc_X arc); -void arc2_X_reset_to(arc_X* self, i_key* ptr); // NB! arc2 only: assign new arc from ptr. Takes ownership of p. - -size_t arc_X_hash(const arc_X* self); // hash value -int arc_X_cmp(const arc_X* x, const arc_X* y); // compares pointer addresses if no `i_cmp` is specified - // is defined. Otherwise uses 'i_cmp' or default cmp. -bool arc_X_eq(const arc_X* x, const arc_X* y); // arc_X_cmp() == 0 - -// functions on pointed to objects. - -size_t arc_X_value_hash(const i_key* self); -int arc_X_value_cmp(const i_key* x, const i_key* y); -bool arc_X_value_eq(const i_key* x, const i_key* y); -``` - -## Types and constants - -| Type name | Type definition | Used to represent... | -|:-----------------|:--------------------------------------------------|:-----------------------| -| `arc_null` | `{0}` | Init nullptr const | -| `arc_X` | `union { arc_X_value* get; }` | The arc type | -| `arc_X_value` | `i_key` | The arc element type | -| `arc_X_raw` | `i_keyraw` | Convertion type | - -## Example - -[ [Run this code](https://godbolt.org/z/TvcoxG1fz) ] - -```c++ -// Create two stacks with arcs to maps. -// Demonstrate sharing and cloning of maps. -// Show elements dropped. -#include - -#define T Map, cstr, int, (c_keypro) // cstr is a "pro" type -#define i_keydrop(p) (printf(" drop name: %s\n", cstr_str(p)), cstr_drop(p)) -#include - -// keyclass binds _clone & _drop: -#define T Arc, Map, (c_keyclass) // (Atomic) Ref. Counted pointer -#include // try to switch to box.h! - -#define T Stack, Arc, (c_keypro) // arc is "pro" -#include - -int main(void) -{ - Stack s1 = {0}, s2 = {0}; - Map *map; - - // POPULATE s1 with shared pointers to Map: - map = Stack_emplace(&s1, Map_init())->get; // emplace empty map on s1. - c_put_items(Map, map, {{"Joey", 1990}, {"Mary", 1995}, - {"Mary", 1996}, {"Joanna", 1992}}); - - map = Stack_emplace(&s1, Map_init())->get; // emplace will make the Arc - c_put_items(Map, map, {{"Rosanna", 2001}, {"Brad", 1999}, {"Jack", 1980}}); - - // POPULATE s2: - map = Stack_emplace(&s2, Map_init())->get; - c_put_items(Map, map, {{"Steve", 1979}, {"Rick", 1974}, {"Tracy", 2003}}); - - - // Share Arc 1 from s1 with s2 by cloning(=sharing): - Stack_push(&s2, Arc_clone(s1.data[1])); - - puts("S2 is now"); - for (c_each(i, Stack, s2)) { - Map m = Stack_value_toraw(i.ref); - for (c_each_kv(name, year, Map, m)) - printf(" %s:%d\n", cstr_str(name), *year); - puts(""); - } - - c_drop(Stack, &s1, &s2); -} -``` - diff --git a/src/finchlite/codegen/stc/docs/box_api.md b/src/finchlite/codegen/stc/docs/box_api.md deleted file mode 100644 index bc22d68c..00000000 --- a/src/finchlite/codegen/stc/docs/box_api.md +++ /dev/null @@ -1,134 +0,0 @@ -# STC [box](../include/stc/box.h): Smart Pointer (boxed object) - -**box** is a smart pointer to a heap allocated value of type X. A **box** can -be empty. The *box_X_cmp()*, *box_X_drop()* methods are defined based on the `i_cmp` -and `i_keydrop` macros specified. Use *box_X_clone(p)* to make a deep copy, which uses the -`i_keyclone` macro if defined. Note that a box set to NULL is consider uninitialized, and -cannot be e.g. cloned or dropped. - -When declaring a container of **box** elements, define `i_keypro` with the -box type instead of defining `i_key`. This will auto-define `i_keydrop`, `i_keyclone`, and `i_cmp` using -functions defined by the specified **box**. - -See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr) for a functional reference, or Rust [std::boxed::Box](https://doc.rust-lang.org/std/boxed/struct.Box.html) - -## Header file and declaration - -```c++ -#define T ,[,] // shorthand for defining T, i_key, i_opt -#define T // box container type name (default: box_{i_key}) -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -#define i_use_cmp // may be defined instead of i_cmp when i_key is an integral/native-type. -#define i_cmp // three-way element comparison. If not specified, pointer comparison is used. - // Note that containers of arcs will derive i_cmp from the i_key type - // when using arc in containers specified with i_keypro . -#define i_less // less comparison. Alternative to i_cmp -#define i_eq // equality comparison. Implicitly defined with i_cmp, but not i_less. - -#define i_keydrop // destroy element func - defaults to empty destruct -#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. - -#define i_keyraw // conversion type (lookup): defaults to {i_key} -#define i_keytoraw // conversion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. -#define i_keyfrom // from-raw func. -#include -``` -In the following, `X` is the value of `i_key` unless `T` is defined. -Unless `c_use_cmp` is defined, comparison between i_key's is not needed/available. Will then -compare the pointer addresses when used. Additionally, `c_no_clone` or `i_is_fwd` may be defined. - -## Methods -```c++ -box_X box_X_init(); // return an empty box -box_X box_X_from(i_keyraw raw); // create a box from raw type. Avail if i_keyraw user defined. -box_X box_X_from_ptr(i_key* ptr); // create a box from a pointer. Takes ownership of ptr. -box_X box_X_make(i_key val); // create a box from unowned val object. - -box_X box_X_clone(box_X other); // return deep copied clone -void box_X_assign(box_X* self, box_X* other); // transfer ownership from other to self; other set to NULL. -void box_X_take(box_X* self, box_X unowned); // take ownership of unowned box object. -box_X box_X_move(box_X* self); // transfer ownership to receiving box. self set to NULL. -i_key* box_X_release(box_X* self); // release owned pointer; must be freed by receiver. self set NULL. -void box_X_drop(const box_X* self); // destruct the contained object and free its heap memory. - -void box_X_reset_to(box_X* self, i_key* ptr); // assign ptr, and take ownership of ptr. - -size_t box_X_hash(const box_X* x); // hash value -int box_X_cmp(const box_X* x, const box_X* y); // compares pointer addresses if no `i_cmp` is specified - // is defined. Otherwise uses 'i_cmp' or default cmp. -bool box_X_eq(const box_X* x, const box_X* y); // box_X_cmp() == 0 - -// functions on pointed to objects. - -size_t box_X_value_hash(const i_key* x); -int box_X_value_cmp(const i_key* x, const i_key* y); -bool box_X_value_eq(const i_key* x, const i_key* y); -``` - -## Types and constants - -| Type name | Type definition | Used to represent... | -|:------------------|:--------------------------------|:-----------------------| -| `box_null` | `{0}` | Init nullptr const | -| `box_X` | `struct { box_X_value* get; }` | The box type | -| `box_X_value` | `i_key` | The box element type | - -## Example -Create a vec and a set with owned pointers to int elements, using box. - -[ [Run this code](https://godbolt.org/z/61rcjcz1x) ] -```c++ -#include - -void int_drop(int* x) { - printf("\n drop %d", *x); -} - -#define T IBox, int, (c_use_cmp) // defines _cmp(), _eq(), and _hash() box-functions -#define i_keydrop int_drop // just to display elements destroyed -#define i_keyclone(x) x // must be specified when i_keydrop is defined. -#include - -// ISet : std::set> -#define T ISet, IBox, (c_keypro) // box is a "pro"-type -#include - -// IVec : std::vector> -#define T IVec, IBox, (c_keypro) -#include - - -int main(void) -{ - IVec vec = c_make(IVec, {2021, 2012, 2022, 2015}); - ISet set = {0}; - - printf("vec:"); - for (c_each(i, IVec, vec)) - printf(" %d", *i.ref->get); - - // add odd numbers from vec to set - for (c_each(i, IVec, vec)) { - if (*i.ref->get & 1) { - ISet_insert(&set, IBox_clone(*i.ref)); - } - } - // pop the two last elements in vec - IVec_pop(&vec); - IVec_pop(&vec); - printf("\nvec:"); - for (c_each(i, IVec, vec)) - printf(" %d", *i.ref->get); - - printf("\nset:"); - for (c_each(i, ISet, set)) - printf(" %d", *i.ref->get); - - IVec_drop(&vec); - ISet_drop(&set); -} -``` diff --git a/src/finchlite/codegen/stc/docs/cbits_api.md b/src/finchlite/codegen/stc/docs/cbits_api.md deleted file mode 100644 index b66139a1..00000000 --- a/src/finchlite/codegen/stc/docs/cbits_api.md +++ /dev/null @@ -1,125 +0,0 @@ -# STC [cbits](../include/stc/cbits.h): Bitset -![Bitset](pics/bitset.jpg) - -A **cbits** represents either a dynamically sized sequence of bits, or a compile-time fixed sized bitset. It provides accesses to the value of individual bits via *cbits_test()* (or *cbits_at()*) and provides the bitwise operators that one can apply to builtin integers. - -For the dynamic The number of bits in the set is specified at runtime via a parameter to the constructor *cbits_with_size()* or by *cbits_resize()*. A **cbits** bitset can be manipulated by standard logic operators and converted to and from strings. - -See the c++ class [std::bitset](https://en.cppreference.com/w/cpp/utility/bitset) or -[boost::dynamic_bitset](https://www.boost.org/doc/libs/release/libs/dynamic_bitset/dynamic_bitset.html) -for a functional description. - -## Header file -All cbits definitions and prototypes are available by including a single header file. - -```c++ -// if T is defined, the bitset will be fixed-size of N bits on the stack, and with the given type name. -#define T MyBits, MY_MAX_BITS -#include - -// otherwise, just include the header. The type name is cbits, data will be dynamically allocated. -#include -``` -## Methods - -```c++ -cbits cbits_from(const char* str); -cbits cbits_with_size(isize size, bool value); // size must be <= N if N is defined -cbits cbits_with_pattern(isize size, size_t pattern); -cbits cbits_clone(cbits other); - -void cbits_clear(cbits* self); -void cbits_copy(cbits* self, const cbits* other); -bool cbits_resize(cbits* self, isize size, bool value); // NB! only for dynamic bitsets! -void cbits_drop(cbits* self); - -cbits* cbits_take(cbits* self, const cbits* other); // give other to self -cbits cbits_move(cbits* self); // transfer self to caller - -isize cbits_size(const cbits* self); -isize cbits_count(const cbits* self); // count number of bits set - -bool cbits_test(const cbits* self, isize i); -bool cbits_at(const cbits* self, isize i); // cbits_test() with bounds check. -bool cbits_subset_of(const cbits* self, const cbits* other); // is set a subset of other? -bool cbits_disjoint(const cbits* self, const cbits* other); // no common bits -char* cbits_to_str(const cbits* self, char* str, isize start, isize stop); - -void cbits_print(const cbits* self); -void cbits_print(const cbits* self, FILE* fp); -void cbits_print(const cbits* self, FILE* fp, isize start, isize stop); -void cbits_print(TYPE Bits, const Bits* self, FILE* fp); // for fixed size bitsets -void cbits_print(TYPE Bits, const Bits* self, FILE* fp, isize start, isize stop); - -void cbits_set(cbits* self, isize i); -void cbits_reset(cbits* self, isize i); -void cbits_set_value(cbits* self, isize i, bool value); -void cbits_set_all(cbits* self, bool value); -void cbits_set_pattern(cbits* self, size_t pattern); -void cbits_flip_all(cbits* self); -void cbits_flip(cbits* self, isize i); - -void cbits_intersect(cbits* self, const cbits* other); -void cbits_union(cbits* self, const cbits* other); -void cbits_xor(cbits* self, const cbits* other); // set of disjoint bits -``` - -## Types - -| cbits | Type definition | Used to represent... | -|:--------------------|:--------------------------|:-----------------------------| -| `cbits` | `struct { ... }` | The cbits type | -| `cbits_iter` | `struct { ... }` | The cbits iterator type | - -## Example -```c++ -#include -#include -#include -#include - -cbits sieveOfEratosthenes(isize n) -{ - cbits bits = cbits_with_size(n/2, true); - isize q = (isize)sqrt(n); - - for (isize i = 3; i <= q; i += 2) { - for (isize j = i; j < n; j += 2) { - if (cbits_test(&bits, j/2)) { - i = j; - break; - } - } - for (isize j = i*i; j < n; j += i*2) - cbits_reset(&bits, j/2); - } - return bits; -} - -int main(void) -{ - isize n = 100000000; - printf("computing prime numbers up to %" c_ZI "\n", n); - - clock_t t1 = clock(); - cbits primes = sieveOfEratosthenes(n + 1); - isize nprimes = cbits_count(&primes); - t1 = clock() - t1; - - printf("number of primes: %" c_ZI ", time: %f\n", nprimes, (float)t1/CLOCKS_PER_SEC); - - printf(" 2"); - for (isize i = 3; i < 1000; i += 2) - if (cbits_test(&primes, i/2)) printf(" %" c_ZI, i); - puts(""); - - cbits_drop(&primes); -} -``` -Output: -``` -computing prime numbers up to 100000000 -done -number of primes: 5761455 -2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997 -``` diff --git a/src/finchlite/codegen/stc/docs/coption_api.md b/src/finchlite/codegen/stc/docs/coption_api.md deleted file mode 100644 index f9828c47..00000000 --- a/src/finchlite/codegen/stc/docs/coption_api.md +++ /dev/null @@ -1,69 +0,0 @@ -# STC [coption](../include/stc/coption.h): Command line argument parsing - -This describes the API of the *coption_get()* function for command line argument parsing. - -See [getopt_long](https://www.freebsd.org/cgi/man.cgi?getopt_long(3)) for a similar posix function. - -## Types - -```c++ -typedef enum { - coption_no_argument, - coption_required_argument, - coption_optional_argument -} coption_type; - -typedef struct { - const char *name; - coption_type type; - int val; -} coption_long; - -typedef struct { - int ind; /* equivalent to posix optind */ - int opt; /* equivalent to posix optopt */ - const char *optstr; /* points to the option string, if any */ - const char *arg; /* equivalent to posix optarg */ - ... -} coption; -``` - -## Methods - -```c++ -coption coption_init(void); -int coption_get(coption *opt, int argc, char *argv[], - const char *shortopts, const coption_long *longopts); -``` - -## Example - -```c++ -#include -#include - -int main(int argc, char *argv[]) { - coption_long longopts[] = { - {"foo", coption_no_argument, 'f'}, - {"bar", coption_required_argument, 'b'}, - {"opt", coption_optional_argument, 'o'}, - {0} - }; - const char* shortopts = "xy:z::123"; - if (argc == 1) - printf("Usage: program -x -y ARG -z [ARG] -1 -2 -3 --foo --bar ARG --opt [ARG] [ARGUMENTS]\n", argv[0]); - coption opt = coption_init(); - int c; - while ((c = coption_get(&opt, argc, argv, shortopts, longopts)) != -1) { - switch (c) { - case '?': printf("error: unknown option: %s\n", opt.optstr); break; - case ':': printf("error: missing argument for %s\n", opt.optstr); break; - default: printf("option: %c [%s]\n", opt.opt, opt.arg ? opt.arg : ""); break; - } - } - printf("\nNon-option arguments:"); - for (int i = opt.ind; i < argc; ++i) - printf(" %s", argv[i]); - putchar('\n'); -} -``` diff --git a/src/finchlite/codegen/stc/docs/coroutine_api.md b/src/finchlite/codegen/stc/docs/coroutine_api.md deleted file mode 100644 index 4bb5e16f..00000000 --- a/src/finchlite/codegen/stc/docs/coroutine_api.md +++ /dev/null @@ -1,825 +0,0 @@ -# STC [Coroutines](../include/stc/coroutine.h) -![Coroutine](pics/coroutine.png) - -This is a small, portable, ergonomic implementation of coroutines in C99. - -* Stackless, fully typesafe coroutines. -* Supports spawning of concurrent tasks using ***fibers/green threads***, managed by the internal scheduler. -* Tasks may be associated with a ***waitgroup***, which must be awaited for to finish. -* Supports both ***asymmetric/structured concurrency*** and ***symmetric transfer*** of control between coroutines. -* Strong error handling and cleanup support. Users may *throw* errors and handle/recover from them up the "call stack" -(resume from the original suspension point). -* Asynchronous coroutine destruction/cleanup supported as standard. -* The coroutine frames/objects will be cleaned up at the `cco_finalize:` label inside the `cco_async` scope. -This will also happen on errors thrown and on coroutine cancellation. -* Fibers are allocated on the heap and automatically freed by the scheduler. Coroutine frames are provided -by the user, and can be either stack or heap allocated. -* Unhandled errors will exit program with an error message including the offending throw's line number. -* Tiny memory usage, about 100 bytes overhead per fiber, and 50 bytes per coroutine object/task. - -Because coroutines are stackless, a common usage is to let each coroutine frame store the coroutine -frames to be called/awaited for, typically on the stack. The coroutine frame holds the local -variables and input/output used within its coroutine scope. This has the advantage -that coroutines become truely lightweight and may therefore be used in memory constrained / embedded systems. - -The coroutine frames may alternatively be allocated on the heap, e.g. individually allocated just before -they are called/awaited for. In this case, each coroutine must free themselves between the `cco_async` -scope end, and `return 0`. - -## Methods and statements - -#### Coroutine Basics (both simple and tasks) -```c++ - cco_async (Coroutine* co) {...} // The coroutine scope. - - cco_yield; // Suspend execution => cco_yield_v(CCO_YIELD) - cco_yield_v(status); // Suspend execution with custom status returned. - cco_suspend; // Suspend execution => cco_yield_v(CCO_SUSPEND) - cco_await(bool condition); // Suspend with CCO_AWAIT status or continue if condition is true. - // Resumption takes place at the condition test, not after. - cco_finalize: // Label marks where cleanup of the task/coroutine frame happens. - // Jumps here on cco_return, cco_throw(), cco_cancel_task(self). - cco_return; // Finish coroutine. Jumps to cco_finalize: label. If already passed - // it or label is absent, exit the cco_async scope. - cco_exit(); // Cancel current coroutine immediately (skip the cco_finalize: stage). - -bool cco_is_active(Coroutine* co); // Is coroutine active/not done?. -bool cco_is_done(Coroutine* co); // Is coroutine done/not active? -void cco_reset_state(Coroutine* co); // Reset state to initial (for reuse). -void cco_stop(Coroutine* co); // Coroutine continues at label cco_finalize if present, - // otherwise it exits the cco_async scope on next resume. -``` - -#### Simple Coroutines (non-Task types) -```c++ - cco_await_coroutine(corofunc(co)); // Await for coroutine to finish, else suspend with CCO_AWAIT. - cco_await_coroutine(corofunc(co), int awaitbits); // Await until coroutine resume status is in (awaitbits | CCO_DONE). - cco_run_coroutine(corofunc(co)) {}; // Run blocking until coroutine is finished. -``` - -#### Tasks (coroutine function-objects) and Fibers (green thread-like entity within a system thread) -```c++ - cco_task_struct(name) {_base base; ...}; // Define a custom coroutine task struct; extends cco_task struct. - cco_task_struct(name, EnvT) {_base base; ...}; // Also specify value type of pointer returned from cco_env(). Default: void. - - cco_yield_to(cco_task* task); // Yield to another task (symmetric transfer of control). -int cco_resume(cco_task* task); // Resume task until next suspension, returns status. - // Normally called by cco_run_task() driver function or a scheduler. - - cco_throw(int error); // Throw an error. Will unwind call/await-task stack. - // Handling of error *is* required else abort(). - cco_throw(CCO_CANCEL); // Throw a cancellation of the current task. - // It will silently unwind the await stack. Handling *not* - // required, but it may be recovered in a cco_finalize: section. - cco_recover; // Recover from a cco_throw() or cancellation. Resume from the original - // suspend point in the current task and clear error status. - // Should be done in a cco_finalize: section. -``` -#### Task Accessors -```c++ -int cco_status(); // Get current return status from last cco_resume() call. -cco_error* cco_err(); // Get error object created from cco_throw(error) call. - // Should be handled in a cco_finalize: section. -cco_fiber* cco_fb(cco_task* task); // Get fiber associated with task. -EnvT* cco_env(cco_task* task); // Get environment pointer, stored in the associated fiber. -EnvT* cco_set_env(cco_task* task, EnvT* env); // Set environment pointer. -``` -#### Task and Waitgroup Cancellation -```c++ - cco_cancel_task(cco_task* task); // Cancel a spawned task; If task runs in the current - // fiber it equals cco_throw(CCO_CANCEL) (jumps to cco_finalize:). -void cco_cancel_fiber(cco_fiber* fiber); // Signal that fiber will be cancelled upon next suspension point. -void cco_cancel_group(cco_group* wg); // Cancel all spawned tasks in the waitgroup, *except* the current. - // Passing NULL as arg will cancel all non-group spawned tasks. -void cco_cancel_all(); // Cancel all spawned tasks, *except* the current. -``` -#### Awaiting Tasks and Waitgroups -```c++ - cco_await_task(cco_task* task); // Await/call until task's resume status is CCO_DONE (=0). - cco_await_task(cco_task* task, int awaitbits); // Await until task's resume status is in (awaitbits | CCO_DONE). - cco_await_cancel_task(cco_task* task); // Cancel and await for task to finalize async. - // Shorthand for cco_cancel_task() + cco_await_task(). - - // If tasks were spawned, all must be awaited for by using these awaiter functions: - cco_await_group(cco_group* wg); // Await for all (remaining) tasks in waitgroup to finish. - // Does not await for current task/fiber, - cco_await_any(cco_group* wg); // Await for any one spawned task in waitgroup to - // finish, and cancel the remaining. - cco_await_cancel_group(cco_group* wg); // Cancel all tasks in wg, and await for them to finalize. - // Shorthand for cco_cancel_group() + cco_await_group(). - cco_await_n(cco_group* wg, int n); // Awaits for n spawned tasks. Does *not* cancel the remaining. -``` -#### Spawning and Running Tasks -The `EnvT` type used below is by default `void`, but can be specified in *cco_task_struct()* definition. -```c++ -void cco_reset_group(cco_group* wg); // Reset waitgroup.(Normally not needed). -cco_fiber* cco_spawn(cco_task* tsk); // Lazily spawn a new concurrent task, detatched. -cco_fiber* cco_spawn(cco_task* tsk, cco_group* wg); // Lazily spawn a new concurrent task within a waitgroup. -cco_fiber* cco_spawn(cco_task* tsk, cco_group* wg, EnvT* env); // Variable env may be used as a "promise", or point to input. -cco_fiber* cco_spawn(cco_task* tsk, cco_group* wg, EnvT* env, // This may be called from main or outside `cco_async` scope. - cco_fiber* fiber); - - cco_run_task(cco_task* tsk) {} // Run task blocking until it and spawned fibers are finished. - cco_run_task(cco_task* tsk, EnvT *env) {} // Run task blocking with env data - cco_run_task(fb_iter, cco_task* tsk, EnvT *env) {} // Run task blocking. fb_iter reference the current fiber. - -cco_fiber* cco_new_fiber(cco_task* tsk); // Create an initial fiber from a task. -cco_fiber* cco_new_fiber(cco_task* tsk, EnvT* env); // Create an initial fiber from a task and env (inputs or a future). - cco_run_fiber(cco_fiber** fiber_ref) {} // Run fiber(s) blocking. Note it takes a (cco_fiber **) as arg. - cco_run_fiber(fb_iter, cco_fiber* fiber) {} // Run fiber(s) blocking. fb_iter reference the current fiber. - -bool cco_joined(); // Check if all concurrent spawned tasks are joined. -``` -#### Timers and Time Functions -```c++ -void cco_start_timer(cco_timer* tm, double sec); // Start timer with seconds duration. -void cco_restart_timer(cco_timer* tm); // Restart timer with previous duration. -bool cco_timer_expired(cco_timer* tm); // Return true if timer is expired. -double cco_timer_elapsed(cco_timer* tm); // Return elapsed seconds. -double cco_timer_remaining(cco_timer* tm); // Return remaining seconds. - cco_await_timer(cco_timer* tm, double sec); // Start timer with duration and await for it to expire. -``` -#### Semaphores -```c++ -cco_semaphore cco_make_semaphore(long value); // Create semaphore -void cco_set_semaphore(cco_semaphore* sem, long value); // Set initial semaphore value -void cco_acquire_semaphore(cco_semaphore* sem); // if (count > 0) count -= 1 -void cco_release_semaphore(cco_semaphore* sem); // "Signal" the semaphore (count += 1) - cco_await_semaphore(cco_semaphore* sem); // Await for the semaphore count > 0, then count -= 1 -``` -#### Interoperability with fb_iterators and Filters -```c++ - // Container fb_iteration within coroutines - for (cco_each(fb_iter_name, CntType, cnt)) ...; // Use an existing fb_iterator (stored in coroutine object) - for (cco_each_reverse(fb_iter_name, CntType, cnt)) ...; // Iterate in reverse order - - // c_filter() interoperability with coroutine fb_iterators -bool cco_flt_take(int num); // Use instead of *c_flt_take(num)* to ensure cleanup -bool cco_flt_takewhile(bool predicate); // Use instead of *c_flt_takewhile(pred)* to ensure cleanup -``` - -## Types -| Type name | Type definition / usage | Used to represent... | -|:------------------|:----------------------------------------------------|:---------------------| -|`cco_status` | **enum** `CCO_DONE`, `CCO_AWAIT`, `CCO_SUSPEND`, `CCO_YIELD` | Default set of return status from coroutines | -|`struct cco_error` | `struct { int32_t code, line; const char* file; }` | Error object for exceptions | -|`cco_task` | Enclosure/function object | Basic coroutine frame type | -|`cco_timer` | Struct type | Delay timer | -|`cco_semaphore` | Struct type | Synchronization primitive | -|`cco_fiber` | `struct { int status; }` | Represent a thread-like entity within a thread | - -## Rules -1. All cco-features must be called/placed in the ***cco_async*** scope. -2. Avoid declaring local variables within a ***cco_async*** scope. They are only alive until next ***cco_suspend***, -***cco_yield..***, or ***cco_await..***. Normally place them in the coroutine struct. Be particularly careful with -control variables in loops. -3. Do not call ***cco_suspend***, ***cco_yield..*** or ***cco_await..*** inside a `switch` statement. Use `if-else-if` in those cases. -4. Never use regular `return` inside ***cco_async*** scope, always use ***cco_return***. -5. Resuming a coroutine after it has returned 0 (CCO_DONE) is undefined behaviour ***if*** there is additional -code between the ***cco_async*** scope and `return 0`. -6. There may only be one ***cco_async*** scope per coroutine. - -## Implementation and examples -A plain coroutine may have any signature, however this implementation has specific support for -coroutines which returns `int`, indicating CCO_DONE, CCO_AWAIT, CCO_SUSPEND, CCO_YIELD, or a custom int value. -It also require a struct pointer as one of the parameters, which must contains a member of type ***cco_base*** named `base`. -The coroutine struct should normally store all *local* variables to be used within the coroutine -(technically those where its usage crosses over a ***cco_yield..***, ***cco_await..*** or a ***cco_suspend*** -statement), along with *input* and *output* data/parameters for the coroutine. - -Both asymmetric and symmetric coroutine control flow transfer are supported when using ***tasks*** -(closures/functors), and they may be combined. Be aware of that cleanup (if needed) is harder to ensure -for symmetric transfer of control (***cco_yield_to***), because there is no automatic transfer back to -the "caller"/*awaiter* when it is finished, like it is in the asymmetric case (***cco_await_task***). - -This implementation is not limited to support only a certain set of coroutine types, -like generators. They operate like stackful coroutines, i.e. tasks can efficiently yield -or await within deeply nested coroutines "calls". - ----- -### Generators - -Generator are among the simplest types of coroutines and is easy to write: - -[ [Run this code](https://godbolt.org/z/n5fGEcjYj) ] -```c++ -#include -#include - -struct Gen { - cco_base base; - int start, end, value; -}; - -int Gen(struct Gen* g) { - cco_async (g) { - for (g->value = g->start; g->value < g->end; ++g->value) - cco_yield; - } - return 0; -} - -int main(void) { - struct Gen gen = {.start=10, .end=20}; - - while (Gen(&gen)) { - printf("%d, ", gen.value); - } -} -``` -To be more expressive, you may use the `cco_run_coroutine()` macro: -```c++ - cco_run_coroutine(Gen(&gen)) { - printf("%d, ", gen.value); - } -``` - ----- -### Iterable generators -Although the generator above is simple to use, sometimes it could be useful to iterate through the items -the way you iterate STC containers. Then you may apply [other algorithms](algorithm_api.md) on the sequence as well. -Notice that `Gen` now becomes the "container", while `Gen_iter` is the coroutine: - -
-Iterable generator coroutine implementation - -[ [Run this code](https://godbolt.org/z/4EhPGv7cG) ] -```c++ -#include -#include - -typedef int Gen_value; -typedef struct { - Gen_value start, end, value; -} Gen; - -typedef struct { - cco_base base; - Gen* g; - Gen_value* ref; -} Gen_iter; - -int Gen_next(Gen_iter* it) { - cco_async (it) { - for (*it->ref = it->g->start; *it->ref < it->g->end; ++*it->ref) - cco_yield; - - cco_finalize: - it->ref = NULL; // stop - } - return 0; -} - -Gen_iter Gen_begin(Gen* g) { - Gen_iter it = {.g = g, .ref = &g->value}; - Gen_next(&it); // advance to first - return it; -} - -int main(void) { - Gen gen = {.start=10, .end=20}; - - for (c_each(i, Gen, gen)) { - printf("%d, ", *i.ref); - } -} -``` - -
- ----- -### Actor models of concurrency in video games and simulations -A common usage of coroutines is long-running concurrent tasks, often found in video games. An example of this is the -[Dining philosopher's problem](https://en.wikipedia.org/wiki/Dining_philosophers_problem). The following -implementation uses `cco_await` and `cco_suspend`. It avoids deadlocks by awaiting for both forks to be -available before aquiring them. It also avoids starvation by increasing both neighbor's hunger when a philosopher -starts eating (because they must be waiting). - -
-The "Dining philosophers" C implementation - -[ [Run this code](https://godbolt.org/z/vz5rbE7W4) ] -```c++ -#include -#include -#include -#include - -enum {num_philosophers = 5}; -enum PhMode {ph_THINKING, ph_HUNGRY, ph_EATING}; - -// Philosopher coroutine: use task coroutine -cco_task_struct (Philosopher) { - Philosopher_base base; // required - int id; - cco_timer tm; - enum PhMode mode; - int hunger; - struct Philosopher* left; - struct Philosopher* right; -}; - -int Philosopher(struct Philosopher* o) { - cco_async (o) { - while (1) { - double duration = 1.0 + crand64_real()*2.0; - printf("Philosopher %d is thinking for %.0f minutes...\n", o->id, duration*10); - o->hunger = 0; - o->mode = ph_THINKING; - cco_await_timer(&o->tm, duration); - - printf("Philosopher %d is hungry...\n", o->id); - o->mode = ph_HUNGRY; - cco_await(o->hunger >= o->left->hunger && - o->hunger >= o->right->hunger); - o->left->hunger += (o->left->mode == ph_HUNGRY); // don't starve the neighbours - o->right->hunger += (o->right->mode == ph_HUNGRY); - o->hunger = INT32_MAX; - o->mode = ph_EATING; - - duration = 0.5 + crand64_real(); - printf("Philosopher %d is eating for %.0f minutes...\n", o->id, duration*10); - cco_await_timer(&o->tm, duration); - } - cco_finalize: - printf("Philosopher %d done\n", o->id); - } - - return 0; -} - -// Dining coroutine -cco_task_struct (Dining) { - Dining_base base; // required - float duration; - struct Philosopher philos[num_philosophers]; - int i; - cco_timer tm; - cco_group wg; -}; - -int Dining(struct Dining* o) { - cco_async (o) { - for (int i = 0; i < num_philosophers; ++i) { - o->philos[i] = (struct Philosopher){ - .base = {Philosopher}, - .id = i + 1, - .left = &o->philos[(i - 1 + num_philosophers) % num_philosophers], - .right = &o->philos[(i + 1) % num_philosophers], - }; - cco_spawn(&o->philos[i], &o->wg); - } - cco_await_timer(&o->tm, o->duration); - - cco_finalize: - cco_await_cancel_group(&o->wg); - puts("Dining done"); - } - return 0; -} - -int main(void) -{ - struct Dining dining = {.base={Dining}, .duration=5.0f, .wg = {0}}; - - crand64_seed((uint64_t)time(NULL)); - cco_run_task(&dining); -} -``` -
- ----- -### Tasks -A task is a coroutine functor/enclosure. Users must define a custom task type, which *extends* the basic ***cco_task*** -in a typesafe manner: -```c++ -cco_task_struct (MyTask) { - MyTask_base base; - ... // other task members -}; -``` -```c++ -// a useful convention is to use same name for the coroutine function as the struct task: -int MyTask(struct MyTask* o) { - cco_async (o) { - ... - } - return 0; -} - -int main(void) { - struct MyTask task = {{MyTask}}; // create the task on the stack. - cco_run_task(&task); -} -``` - -#### Error handling with tasks -Tasks allows for scheduling coroutines and more efficient deep nesting of coroutine calls/awaits. -Also, tasks have an excellent error handling mechanism, i.e. an error can be thrown, which will unwind the "call stack", -and errors may be handled and recoveded higher up in the call tree in a simple, structured manner. - -
-Implementation of nested awaiting coroutines with error handling - -The following example shows a task `start` which awaits `TaskA`, => awaits `TaskB`, => awaits `TaskC`. `TaskC` throws -an error, which causes unwinding of the call stack. The error is finally handled in `TaskA`'s `cco_async` scope -and recovered using `cco_recover`. This call will resume control back to the original suspension point in the -current task. Because the "call-tree" is fixed, the coroutine frames to be called may be pre-allocated on the stack, -which is very fast. - -[ [Run this code](https://godbolt.org/z/ad15G1rxj) ] - -```c++ -#include -#include - -cco_task_struct (TaskA, struct Subtasks) { TaskA_base base; int a; }; -cco_task_struct (TaskB, struct Subtasks) { TaskB_base base; double d; }; -cco_task_struct (TaskC, struct Subtasks) { TaskC_base base; float x, y; }; -cco_task_struct (start, struct Subtasks) { start_base base; }; - - -int TaskC(struct TaskC* o) { - cco_async (o) { - printf("TaskC start: {%g, %g}\n", o->x, o->y); - - // assume there is an error... - cco_throw(99); - - puts("TaskC work"); - cco_yield; - puts("TaskC more work"); - - cco_finalize: - puts("TaskC done"); - } - return 0; -} - -struct Subtasks { - struct TaskA task_a; - struct TaskB task_b; - struct TaskC task_c; -}; - -int TaskB(struct TaskB* o) { - cco_async (o) { - printf("TaskB start: %g\n", o->d); - - cco_await_task(&cco_env(o)->task_c); - puts("TaskB work"); - - cco_finalize: - puts("TaskB done"); - } - return 0; -} - -int TaskA(struct TaskA* o) { - cco_async (o) { - printf("TaskA start: %d\n", o->a); - - cco_await_task(&cco_env(o)->task_b); - - puts("TaskA work"); - - cco_finalize: - if (cco_err()->code == 99) { - // if error not handled, will cause 'unhandled error'... - printf("TaskA recovered error '99' thrown on line %d\n", cco_err()->line); - cco_recover; - } - puts("TaskA done"); - } - return 0; -} - -int start(struct start* o) { - cco_async (o) { - puts("start"); - - cco_await_task(&cco_env(o)->task_a); - - cco_finalize: - puts("done"); - } - return 0; -} - - -int main(void) -{ - struct Subtasks env = { - {{TaskA}, 42}, - {{TaskB}, 3.1415}, - {{TaskC}, 1.2f, 3.4f}, - }; - struct start task = {{start}}; - - int count = 0; - cco_run_task(&task, &env) { ++count; } - printf("resumes: %d\n", count); -} -``` - -
- -#### Coroutines frames allocated on the heap - -Sometimes the call-tree is dynamic or more complex, then we can dynamically allocate the coroutine frames before -they are awaited. This is somewhat more general and simpler, but requires heap allocation. Note that the coroutine -frames are now freed at the end of the coroutine functions, i.e. after cco_async {} scope. Example is based on -the previous, but also shows how to use the env field in `cco_fiber` to return a value from the coroutine -call/await: - -
-Implementation of coroutine objects on the heap - -[ [Run this code](https://godbolt.org/z/1j31oPv3W) ] - -```c++ -#include -#include - -cco_task_struct (job1) { - job1_base base; - cco_timer tm; -}; - -cco_task_struct (job_start) { - job_start_base base; - cco_timer tm; - cco_group wg; -}; - - -int job1(struct job1* o) { - cco_async (o) { - cco_await_timer(&o->tm, 0.2); - puts("Pong"); - cco_await_timer(&o->tm, 0.2); - } - free(o); - return 0; -} - -int job_start(struct job_start* o) { - cco_async (o) { - cco_spawn(c_new(struct job1, {{job1}}), &o->wg); - cco_await_timer(&o->tm, 0.1); - puts("Ping"); - cco_await_group(&o->wg); - puts("Ping"); - cco_await_timer(&o->tm, 0.2); - } - free(o); - return 0; -} - - -int main(void) -{ - cco_fiber* fb = c_new(cco_fiber, {0}); - - struct job_start* js = c_new(struct job_start, {{job_start}}); - cco_spawn(js, NULL, NULL, fb); - cco_run_fiber(&fb); -} -``` - -
- ----- -### Producer-consumer pattern (symmetric coroutines) tasks -Tasks are executed using an *executor*, which is easy to do via the ***cco_run_task()*** macro. -Coroutines awaits (or "calls") other coroutines with ***cco_await_task()***, in which case the awaited coroutine will give -control back to the caller whenever it finishes or reaches a `cco_suspend` or another `cco_await*` suspension point in the -code. This is knows as asymmetric calls. - -However, coroutines may also transfer control directly to another coroutine using ***cco_yield_to()***. -In this case, control will not be returned back to caller after it finishes or is suspended, known as a symmetric call. -This is useful when two or more coroutines cooperate like in the simple case of the producer-consumer pattern used in -the following example: - -
-Producer-consumer coroutine implementation - -[ [Run this code](https://godbolt.org/z/rTcxfM6h3) ] -```c++ -#include -#include -#include -#define T Inventory, int -#include - -// Example shows symmetric coroutines producer/consumer style. - -cco_task_struct (produce) { - produce_base base; // must be first (compile-time checked) - struct consume* consumer; - Inventory inventory; - int limit, batch, serial, total; -}; - -cco_task_struct (consume) { - consume_base base; // must be first - struct produce* producer; -}; - - -int produce(struct produce* o) { - cco_async (o) { - while (1) { - if (o->serial > o->total) { - if (Inventory_is_empty(&o->inventory)) - cco_return; // cleanup and finish - } - else if (Inventory_size(&o->inventory) < o->limit) { - for (c_range(o->batch)) - Inventory_push(&o->inventory, ++o->serial); - - printf("produced %d items, Inventory has now %d items:\n", - o->batch, (int)Inventory_size(&o->inventory)); - - for (c_each(i, Inventory, o->inventory)) - printf(" %2d", *i.ref); - puts(""); - } - - cco_yield_to(o->consumer); // symmetric transfer - } - - cco_finalize: - cco_await_cancel_task(o->consumer); - Inventory_drop(&o->inventory); - puts("done producer"); - } - return 0; -} - -int consume(struct consume* o) { - cco_async (o) { - int n, sz; - while (1) { - n = rand() % 10; - sz = (int)Inventory_size(&o->producer->inventory); - if (n > sz) n = sz; - - for (c_range(n)) - Inventory_pop(&o->producer->inventory); - printf("consumed %d items\n", n); - - cco_yield_to(o->producer); // symmetric transfer - } - - cco_finalize: - puts("drop consumer"); - cco_yield; // demo async destruction. - puts("done consumer"); - } - - return 0; -} - -int main(void) -{ - srand((unsigned)time(0)); - struct produce producer = { - .base = {produce}, - .inventory = {0}, - .limit = 12, - .batch = 8, - .total = 50, - }; - struct consume consumer = { - .base = {consume}, - .producer = &producer, - }; - producer.consumer = &consumer; - - cco_run_task(&producer); -} -``` - -
- ----- -### Scheduled coroutines -The task-objects have the added benefit that coroutines can be managed by a scheduler, -which is useful when dealing with large numbers of coroutines (like in simulations). -Below is a simple coroutine scheduler using a queue. It sends the suspended coroutines -to the end of the queue, and resumes the coroutine in the front. -Note that the scheduler awaits the next CCO_YIELD to be returned, not *only* the default CCO_DONE -(in the code below, `| CCO_DONE` is redundant and only to show how to await for multiple/custom bit-values). - -The example heap allocates the coroutine frames on a queue, so that the scheduler can pick the next coroutine to -execute from a pool of coroutines. This also allows it to run on a different thread/scope that may outlive -the scope in that it was created. - -
-Scheduled coroutines implementation - -[ [Run this code](https://godbolt.org/z/hj78Ms4Gf) ] -```c++ -// Based on https://www.youtube.com/watch?v=8sEe-4tig_A -#include -#include - -#define T Tasks, cco_task*, (c_no_clone) -#define i_keydrop(p) c_free_n(*p, 1) // { puts("free task"); c_free_n(*p, 1); } -#include - -// Specify Tasks as the environment pointer type: -cco_task_struct (Scheduler, Tasks) { - Scheduler_base base; - cco_task* _pulled; - Tasks tasks; -}; - -cco_task_struct (TaskA, Tasks) { - TaskA_base base; -}; - -cco_task_struct (TaskX) { - TaskX_base base; - char id; -}; - -int scheduler(struct Scheduler* o) { - cco_async (o) { - cco_set_env(o, &o->tasks); - - while (!Tasks_is_empty(&o->tasks)) { - o->_pulled = Tasks_pull(&o->tasks); - - cco_await_task(o->_pulled, CCO_YIELD | CCO_DONE); - - if (cco_status() == CCO_YIELD) { - Tasks_push(&o->tasks, o->_pulled); - } else { // CCO_DONE - Tasks_value_drop(&o->tasks, &o->_pulled); - } - } - - cco_finalize: - Tasks_drop(&o->tasks); - puts("Task queue dropped"); - } - return 0; -} - -static int taskX(struct TaskX* o) { - cco_async (o) { - printf("Hello from task %c\n", o->id); - cco_yield; - printf("%c is back doing work\n", o->id); - cco_yield; - printf("%c is back doing more work\n", o->id); - cco_yield; - - cco_finalize: - printf("%c is done\n", o->id); - } - - return 0; -} - -static int TaskA(struct TaskA* o) { - cco_async (o) { - puts("Hello from task A"); - cco_yield; - - puts("A is back doing work"); - cco_yield; - - puts("A adds task C"); - Tasks_push(cco_env(o), cco_cast_task(c_new(struct TaskX, {.base={taskX}, .id='C'}))); - cco_yield; - - puts("A is back doing more work"); - cco_yield; - - cco_finalize: - puts("A is done"); - } - return 0; -} - -int main(void) { - // Allocate everything on the heap, so it could be ran in another thread. - struct Scheduler* schedule = c_new(struct Scheduler, { - .base={scheduler}, - .tasks = c_make(Tasks, { - cco_cast_task(c_new(struct TaskA, {.base={TaskA}})), - cco_cast_task(c_new(struct TaskX, {.base={taskX}, .id='B'})), - }) - }); - - cco_run_task(schedule); - - // schedule is now cleaned up/destructed, free heap mem. - c_free_n(schedule, 1); -} -``` - -
diff --git a/src/finchlite/codegen/stc/docs/cregex_api.md b/src/finchlite/codegen/stc/docs/cregex_api.md deleted file mode 100644 index abfc8109..00000000 --- a/src/finchlite/codegen/stc/docs/cregex_api.md +++ /dev/null @@ -1,254 +0,0 @@ -# STC [cregex](../include/stc/cregex.h): Regular Expressions - - -## Description - -**cregex** is a small and fast unicode UTF8 regular expression parser. It is based on Rob Pike's non-backtracking NFA-based regular expression implementation for the Plan 9 project. See Russ Cox's articles [Implementing Regular Expressions](https://swtch.com/~rsc/regexp/) on why NFA-based regular expression engines often are superiour to the common backtracking implementations (hint: NFAs have no "bad/slow" RE patterns). - -The API is simple and includes powerful string pattern matches and replace functions. See example below and in the example folder. - -## Constants -- compile-flags - - CREG_DOTALL - dot matches newline too: can be set/overridden by (?s) and (?-s) in the RE - - CREG_ICASE - ignore case mode: can be set/overridden by (?i) and (?-i) in the RE -- match-flags - - CREG_FULLMATCH - like start-, end-of-line anchors were in pattern: "^ ... $" - - CREG_NEXT - use end of previous match[0] as start of input -- replace-flags - - CREG_STRIP - only keep the replaced matches, strip the rest - -## Methods -```c++ - // Compile and return a cregex from a RE pattern. Struct member error holds status. -cregex cregex_from(const char* pattern); -cregex cregex_make(const char* pattern, int cflags); - - // Compile and initialize a regex, Returns CREG_OK, or negative error code on failure -int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_DEFAULT); - - // Destroy -void cregex_drop(cregex* self); - - // Num. of capture groups in regex, excluding the 0th group which is the full match -int cregex_captures(const cregex* self); - - // Match RE. Return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR -int cregex_match(const cregex* re, const char* str, - csview match[] = NULL, int flags = CREG_DEFAULT); -int cregex_match_sv(const cregex* re, csview sv, - csview match[] = NULL, int flags = CREG_DEFAULT); - - // Check if there are matches in input -bool cregex_is_match(const cregex* re, const char* str); - - // All-in-one single match (compile + match + drop) -int cregex_match_aio(const char* pattern, const char* str, - csview match[] = NULL, int flags = CREG_DEFAULT); -int cregex_match_aio_sv(const char* pattern, csview sv, - csview match[] = NULL, int flags = CREG_DEFAULT); - - // Replace count matched instances, optionally transform the replacement. -cstr cregex_replace(const cregex* re, const char* str, const char* replace, - int count = 0 /* all */, - bool(*xform)(int group, csview match, cstr* result) = NULL, - int flags = CREG_DEFAULT); /* match|replace flags */ -cstr cregex_replace_sv(const cregex* re, csview sv, const char* replace, - int count = 0 /* all */, - bool(*xform)(int group, csview match, cstr* result) = NULL, - int flags = CREG_DEFAULT); - - // All-in-one replacement (compile + match/replace + drop) -cstr cregex_replace_aio(const char* pattern, const char* str, const char* replace, - int count = 0 /* all */, - bool(*xform)(int group, csview match, cstr* result) = NULL, - int flags = CREG_DEFAULT); /* compile|match|replace flags */ -cstr cregex_replace_aio_sv(const char* pattern, csview sv, const char* replace, - int count = 0 /* all */, - bool(*xform)(int group, csview match, cstr* result) = NULL, - int flags = CREG_DEFAULT); -``` - -### Error codes -- CREG_OK = 0 -- CREG_NOMATCH = -1 -- CREG_MATCHERROR = -2 -- CREG_OUTOFMEMORY = -3 -- CREG_UNMATCHEDLEFTPARENTHESIS = -4 -- CREG_UNMATCHEDRIGHTPARENTHESIS = -5 -- CREG_TOOMANYSUBEXPRESSIONS = -6 -- CREG_TOOMANYCHARACTERCLASSES = -7 -- CREG_MALFORMEDCHARACTERCLASS = -8 -- CREG_MISSINGOPERAND = -9 -- CREG_UNKNOWNOPERATOR = -10 -- CREG_OPERANDSTACKOVERFLOW = -11 -- CREG_OPERATORSTACKOVERFLOW = -12 -- CREG_OPERATORSTACKUNDERFLOW = -13 - -### Limits -- CREG_MAX_CLASSES -- CREG_MAX_CAPTURES - -## Usage - -### Compiling a regular expression -```c++ -cregex re1 = {0}; -int result = cregex_compile(&re1, "[0-9]+"); -if (result < 0) return result; - -const char* url = "(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?"; -cregex re2 = cregex_from(url); -if (re2.error != CREG_OK) - return re2.error; -... -cregex_drop(&re2); -cregex_drop(&re1); -``` -If an error occurs ```cregex_compile``` returns a negative error code stored in re2.error. - -### Getting the first match and making text replacements - -[ [Run this code](https://godbolt.org/z/cz6qfPG1E) ] -```c++ -#include - -int main(void) { - const char* input = "start date is 2023-03-01, end date 2025-12-31."; - const char* pattern = "\\b(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)\\b"; - - cregex re = cregex_from(pattern); - - // Lets find the first date in the string: - csview match[4]; // full-match, year, month, date. - if (cregex_match(&re, input, match) == CREG_OK) - printf("Found date: " c_svfmt "\n", c_svarg(match[0])); - else - printf("Could not match any date\n"); - - // Lets change all dates into US date format MM/DD/YYYY, and strip unmatched text. - cstr us_dates = cregex_replace(&re, input, "$2/$3/$1;", .flags=CREG_STRIP); - printf("%s\n", cstr_str(&us_dates)); - - // Free allocated data - cstr_drop(&us_dates); - cregex_drop(&re); -} -``` -For a single match you may use the all-in-one function: -```c++ -if (cregex_match_aio(pattern, input, match)) - printf("Found date: " c_svfmt "\n", c_svarg(match[0])); -``` - -### Iterate through regex matches, for (*c_match()*) - -To iterate multiple matches in an input string, you may use -```c++ -csview match[5] = {0}; -while (cregex_match_next(&re, input, match) == CREG_OK) - for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: " c_svfmt "\n", k, c_svarg(match[k])); -``` -There is also a `c_match` macro which simplifies this: -```c++ -for (c_match(it, &re, input)) - for (c_range(k, 1, cregex_captures(&re) + 1)) - printf("submatch %d: " c_svfmt "\n", k, c_svarg(it.match[k])); -``` - -## Regex Cheatsheet - -| Metacharacter | Description | STC addition | -|:--:|:--:|:--:| -| ***c*** | Most characters (like c) match themselve literally | | -| \\***c*** | Some characters are used as metacharacters. To use them literally escape them | | -| . | Match any character, except newline unless in (?s) mode | | -| ? | Match the preceding token zero or one time | | -| * | Match the preceding token as often as possible | | -| + | Match the preceding token at least once and as often as possible | | -| \| | Match either the expression before the \| or the expression after it | | -| (***expr***) | Match the expression inside the parentheses. ***This adds a capture group*** | | -| [***chars***] | Match any character inside the brackets. Ranges like a-z may also be used | | -| \[^***chars***\] | Match any character not inside the bracket. | | -| \x{***hex***} | Match UTF8 character/codepoint given as a hex number | * | -| ^ | Start of line anchor | | -| $ | End of line anchor | | -| \A | Start of input anchor | * | -| \Z | End of input anchor | * | -| \z | End of input including optional newline | * | -| \b | UTF8 word boundary anchor | * | -| \B | Not UTF8 word boundary | * | -| \Q | Start literal input mode | * | -| \E | End literal input mode | * | -| (?i) (?-i) | Ignore case on/off (override CREG_ICASE) | * | -| (?s) (?-s) | Dot matches newline on/off (override CREG_DOTALL) | * | -| \n \t \r | Newline, tab, carriage return | | -| \d \s \w | Digit, whitespace, alphanumeric character | | -| \D \S \W | Do not match the groups described above | | -| \p{Cc} or \p{Cntrl} | UTF8 control character | * | -| \p{L} or \p{Alpha} | UTF8 letter | * | -| \p{Ll} or \p{Lower} | UTF8 lowercase letter | * | -| \p{Lu} or \p{Upper} | UTF8 uppercase letter | * | -| \p{Lt} | Titlecase letter | * | -| \p{L&} | Cased letter (Ll Lu Lt) | * | -| \p{Lm} | Modifier letter | * | -| \p{Nd} or \p{Digit} | Decimal number | * | -| \p{Nl} | Numeric letter | * | -| \p{No} | Other number | * | -| \p{P} | Punctuation | * | -| \p{Pc} | Connector punctuation | * | -| \p{Pd} | Dash punctuation | * | -| \p{Pi} | Initial punctuation | * | -| \p{Pf} | Final punctuation | * | -| \p{Ps} | Start/open punctuation | * | -| \p{Pe} | End/close punctuation | * | -| \p{Sc} | Currency symbol | * | -| \p{Sm} | Math symbol | * | -| \p{Sk} | Modifier symbol | * | -| \p{Zl} | Line separator | * | -| \p{Zp} | Paragraph separator | * | -| \p{Zs} | Space separator | * | -| \p{Alpha} | Alphabetic letter (L) | * | -| \p{Lower} | Lowercase letter (Ll) | * | -| \p{Upper} | Uppercase letter (Lu) | * | -| \p{Alnum} | Alpha-numeric letter (L Nl Nd) | * | -| \p{Blank} | Blank (Zs \t) | * | -| \p{Space} | Whitespace: (Zs \t\r\n\v\f) | * | -| \p{Word} | Word character: (Alnum Pc) | * | -| \p{XDigit} | Hex number | * | -| \p{Arabic} | Unicode script | * | -| \p{Bengali} | Unicode script | * | -| \p{Cyrillic} | Unicode script | * | -| \p{Devanagari} | Unicode script | * | -| \p{Georgian} | Unicode script | * | -| \p{Greek} | Unicode script | * | -| \p{Han} | Unicode script | * | -| \p{Hiragana} | Unicode script | * | -| \p{Katakana} | Unicode script | * | -| \p{Latin} | Unicode script | * | -| \p{Thai} | Unicode script | * | -| \P{***Class***} | Do not match the classes described above | * | -| [:alnum:] [:alpha:] [:ascii:] | ASCII character class. NB: only to be used inside [] brackets | * | -| [:blank:] [:cntrl:] [:digit:] | " | * | -| [:graph:] [:lower:] [:print:] | " | * | -| [:punct:] [:space:] [:upper:] | " | * | -| [:xdigit:] [:word:] | " | * | -| [:^***class***:] | Match character not in the ASCII class | * | -| $***n*** | *n*-th replace backreference to capture group. ***n*** in 0-9. $0 is the entire match. | * | -| $***nn;*** | As above, but can handle ***nn*** < CREG_MAX_CAPTURES. | * | - -## Limitations - -The main goal of **cregex** is to be small and fast with limited but useful unicode support. In order to -reach these goals, **cregex** currently does not support the following features (non-exhaustive list): -- In order to limit table sizes, several general UTF8 character classes are missing, like \p{L}, \p{S}, -and specific scripts like \p{Tibetan}. Some/all of these may be added in the future as an -alternative source file with unicode tables to link with. Currently, only code points from from the -Basic Multilingual Plane (BMP) are supported, which contains all the most commonly used unicode characters, -symbols and scripts. -- {n, m} syntax for repeating previous token min-max times. -- Non-capturing groups -- Lookaround and backreferences (cannot be implemented efficiently). - -If you need a more feature complete, but bigger library, use [RE2 with C-wrapper](https://github.com/google/re2) -which uses the same type of regex engine as **cregex**, or use [PCRE2](https://www.pcre.org/). diff --git a/src/finchlite/codegen/stc/docs/cspan_api.md b/src/finchlite/codegen/stc/docs/cspan_api.md deleted file mode 100644 index 0152206c..00000000 --- a/src/finchlite/codegen/stc/docs/cspan_api.md +++ /dev/null @@ -1,308 +0,0 @@ -# STC [cspan](../include/stc/cspan.h): Multi-dimensional Array View -![Array](pics/array.jpg) - -The **cspan** types are templated non-owning *single* and *multi-dimensional* views of an array. -It supports both row-major and column-major layout efficiently, in a addition to slicing -capabilities similar to [python's numpy arrays](https://numpy.org/doc/stable/user/basics.indexing.html). -Note that **cspan** stores indices as int32_t. Multi-dimensional spans can have up to INT32_MAX elements -in the RANK-1 inner dimensions in total, and INT32_MAX in the outer dimension. Currently limited to 8 -dimensions due to ergonomics and optimization of one-dimensional spans. More dimensions can be added with -the *use_cspan_tuple(N)* macro. - -See also C++ -[std::span](https://en.cppreference.com/w/cpp/container/span) / -[std::mdspan](https://en.cppreference.com/w/cpp/container/mdspan) for similar functionality. - -## Header file and declaration -**cspan** types are defined by the *use_cspan()* macro after the header is included. -This is different from other containers where template parameters are defined prior to -including each container. This works well mainly because cspan is a non-owning type. -```c++ -#include -use_cspan(SpanType, ValueType); // Define a 1-d span with ValueType elements. -use_cspan(SpanTypeN, ValueType, RANK); // Define multi-dimensional span with RANK. - // RANK is the number (constant) of dimensions - // Has no equality test support. -use_cspan_with_eq(SpanType, ValueType, eq); // Define a 1-d span with equality function support -use_cspan_with_eq(SpanTypeN, ValueType, eq, RANK); // Define span with equality function support - -// Shorthands: -use_cspan2(S, ValueType); // Define span types S, S2 with ranks 1, 2. -use_cspan3(S, ValueType); // Define span types S, S2, S3 with ranks 1, 2, 3. - -use_cspan2_with_eq(S, ValueType, eq); // As above, but with equality function support -use_cspan3_with_eq(S, ValueType, eq); // Use c_default_eq for primary type elements. -``` -## Methods - -All index arguments are side-effect safe, e.g. `*cspan_at(&ms3, i++, j++, k++)` is safe, however `*cspan_at(&spans[n++], i, j)` -is an error, i.e. the *span* argument itself is not side-effect safe. If the number of arguments does not match the span rank, -a compile error is issued. Runtime bounds checks are enabled by default (define `STC_NDEBUG` or `NDEBUG` to disable). -```c++ - // Create local cspan using stack memory -SpanType c_make(, {v1, v2, ...}); // create a local 1-d cspan from values (stack memory) -SpanType cspan_make(, {v1, v2, ...}); // create a local 1-d cspan (on stack or global memory) -SpanType cspan_zeros(, N); // create a local 1-d cspan. N must be a comp-time constant -SpanType cspan_by_copy(const ValueType* ptr, N); // create a local 1-d cspan. N must be a comp-time constant - - // Make cspan view into existing data -SpanType cspan_from_n(ValueType* ptr, int32_t n); // make a 1-d cspan view into a pointer + length -SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan view into a C array -SpanType cspan_from_vec(VecType* cnt); // make a 1-d cspan view into a vec or stack - - // ISpan2 m = {data, cspan_shape(3, 4), cspan_strides(4, 1)}; // => ISpan2 m = cspan_md(data, 3, 4); -int32_t[N] cspan_shape(xd, ...) // specify dimensions for SpanTypeN constructor -cspan_tupleN cspan_strides(xs, ...) // specify strides for SpanTypeN constructor - -int cspan_rank(const SpanTypeN* self); // num dimensions; compile-time constant -isize cspan_size(const SpanTypeN* self); // return number of elements -isize cspan_index(const SpanTypeN* self, int32_t i, j..); // offset index at i, j,...; range checked - -ValueType* cspan_at(const SpanTypeN* self, int32_t i, j..); // get element; index range checked -ValueType* cspan_front(const SpanTypeN* self); // first element pointer -ValueType* cspan_back(const SpanTypeN* self); // last element pointer - - // Construct a multi-dim span -SpanTypeN cspan_md(ValueType* data, int32_t dim1, dim2...); // c_ROWMAJOR layout -SpanTypeN cspan_md_layout(cspan_layout layout, ValueType* data, int32_t dim1, dim2...); - - // Transpose an md span in-place. Inverses layout and axes only. -void cspan_transpose(SpanTypeN* self); -void cspan_swap_axes(SpanTypeN* self, int ax1, int ax2); - - // Set all span elements to value. -void cspan_set_all(, self, value); - -cspan_layout cspan_get_layout(const SpanTypeN* self); -bool cspan_is_rowmajor(const SpanTypeN* self); -bool cspan_is_colmajor(const SpanTypeN* self); - - // Construct a 1d subspan. Faster, but equal to: - // Span msub = cspan_slice(&ms, Span, {offset, offset+count}); -SpanType1 cspan_subspan(const SpanType1* self, isize offset, int32_t count); - - // Construct a 1d subspan from a 2d span. -OutSpan1 cspan_submd2(const SpanType2* self, int32_t i); - - // Construct a lower rank submd. E.g. Span2 md2 = cspan_submd3(&md3, i); - // is equal to: Span2 md2 = cspan_slice(&md3, Span2, {i}, {c_ALL}, {c_ALL}); -OutSpan2 cspan_submd3(const SpanType3* self, int32_t i); -OutSpan1 cspan_submd3(const SpanType3* self, int32_t i, int32_t j); - - // Construct a 3d, 2d or 1d subspan from a 4d span. -OutSpan3 cspan_submd4(const SpanType4* self, int32_t i); -OutSpan2 cspan_submd4(const SpanType4* self, int32_t i, int32_t j); -OutSpan1 cspan_submd4(const SpanType4* self, int32_t i, int32_t j, int32_t k); - - // Multi-dim span slicing function. - // {i}: select i'th column. reduces output rank by one. - // {i,j}: from i to j-1. - //{i,j,step}: step size (default step=1) - // {i,c_END}: from i to last. - // {c_ALL}: full extent, like {0,c_END}. -OutSpanM cspan_slice(const SpanTypeN* self, , {x0,x1,xs}, {y0,y1,ys}.., {N0,N1,Ns}); - - // Print numpy style output. - // fmt : printf format specifier. - // fp : optional output file pointer, default stdout. - // brackets : optional brackets and comma. Example "{},". Default "[]". - // field : optional args macro function, must match fmt args. - // e.g.: #define complexfield(x) creal(x), cimag(x) - // Examples: cspan_print(Span2, "%.3f", Span2_transposed(sp2))); - // cspan_print(Span2, "%.3f", (Span2)cspan_submd3(&sp3, 1)); -void cspan_print(, const char* fmt, SpanTypeN span, FILE* fp = stdout, - const char* brackets = "[]", field(x) = x); - // Print matrix with complex numbers. num_decimals applies both to real and imag parts. -void cspan_print_complex(, int num_decimals, SpanTypeN span, FILE* fp); - -// Member functions - -SpanTypeN SpanTypeN_transposed(SpanTypeN sp); // see also in-place cspan_transpose(&sp); -bool SpanTypeN_equals(SpanTypeN spx, SpanTypeN spy); -bool SpanTypeN_eq(const SpanTypeN* self, const SpanTypeN* other); - -SpanTypeN_iter SpanTypeN_begin(const SpanTypeN* self); -SpanTypeN_iter SpanTypeN_end(const SpanTypeN* self); -void SpanTypeN_next(SpanTypeN_iter* it); -``` - -## Types -| Type name | Type definition / usage | Used to represent... | -|:------------------|:----------------------------------------------------|:---------------------| -| `cspan_istride` | `int32_t` | Stride / Index type | -| SpanTypeN_value | `ValueType` | Element value type | -| SpanTypeN | `struct { ValueType *data; cspan_istride shape[N]; .. }`| SpanType with rank N | -| cspan_tupleN | `struct { cspan_istride d[N]; }` | Strides for each rank | -| `cspan_layout` | `enum { c_ROWMAJOR, c_COLMAJOR, c_STRIDED }` | Multi-dim layout | -| `c_ALL` | `cspan_slice(&md, Mat, {1,3}, {c_ALL})` | Full extent | -| `c_END` | `cspan_slice(&md, Mat, {1,c_END}, {2,c_END})` | End of extent | - -## Example 1 - -[ [Run this code](https://godbolt.org/z/x1PYoarxE) ] -```c++ -#include -#define i_key int -#include - -#define i_key int -#include -#include -use_cspan(intspan, int); - -void printMe(intspan container) { - printf("%d:", (int)cspan_size(&container)); - for (c_each(e, intspan, container)) - printf(" %d", *e.ref); - puts(""); -} - -int main(void) -{ - printMe( c_make(intspan, {1, 2, 3, 4}) ); - - int arr[] = {1, 2, 3, 4, 5}; - printMe( (intspan)cspan_from_array(arr) ); - - vec_int vec = c_make(vec_int, {1, 2, 3, 4, 5, 6}); - printMe( (intspan)cspan_from_vec(&vec) ); - - stack_int stk = c_make(stack_int, {1, 2, 3, 4, 5, 6, 7}); - printMe( (intspan)cspan_from_vec(&stk) ); - - intspan spn = c_make(intspan, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); - printMe( (intspan)cspan_subspan(&spn, 2, 8) ); - - // cleanup - vec_int_drop(&vec); - stack_int_drop(&stk); -} -``` - -## Example 2 - -Multi-dimension slicing (python): -```py -import numpy as np - -if __name__ == '__main__': - ms3 = np.array((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24), int) - - ms3 = np.reshape(ms3, (2, 3, 4), order='C') - ss3 = ms3[:, 0:3, 2:] - a = ss3[1] - b = np.transpose(a) - - print("ss3:") - print(ss3) - print("\nms3:") - print(ms3[1]) - print("\na:") - print(a) - print("b:") - print(b) - - print("\na flat:\n", [int(i) for i in a.flat]) - print("b flat:\n", [int(i) for i in b.flat]) -''' - ss3: -[[[ 3 4] - [ 7 8] - [11 12]] - - [[15 16] - [19 20] - [23 24]]] - -ms3: -[[13 14 15 16] - [17 18 19 20] - [21 22 23 24]] - -a: -[[15 16] - [19 20] - [23 24]] -b: -[[15 19 23] - [16 20 24]] - -a flat: - [15, 16, 19, 20, 23, 24] -b flat: - [15, 19, 23, 16, 20, 24] -''' -``` -Multi-dimension slicing (STC cspan): - -[ [Run this code](https://godbolt.org/z/cEPbsja98) ] -```c++ -#include -#include -use_cspan3(myspan, int); // define myspan, myspan2, myspan3. - -int main(void) { - int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; - - myspan3 ms3 = cspan_md(arr, 2, 3, 4); // row-major layout - myspan3 ss3 = cspan_slice(&ms3, myspan3, {c_ALL}, {0,3}, {2,c_END}); - puts("ss3:"); - myspan2 a = cspan_submd3(&ss3, 1); - myspan2 b = myspan2_transposed(a); - - cspan_print(myspan3, "%d", ss3); - puts("\nms3[1]:"); - cspan_print(myspan2, "%d", ((myspan2)cspan_submd3(&ms3, 1))); - - puts("\na:"); - cspan_print(myspan2, "%d", a); - - puts("b:"); - cspan_print(myspan2, "%d", b); - - puts("\na flat:"); - for (c_each(i, myspan2, a)) - printf(" %d,", *i.ref); - - puts("\nb flat:"); - for (c_each(i, myspan2, b)) - printf(" %d,", *i.ref); - puts(""); -} -``` - -## Example 3 -Slicing cspan without and with reducing the rank: - -[ [Run this code](https://godbolt.org/z/PTh8ojenc) ] -```c++ -#include -#include - -use_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3 - -int main(void) -{ - Span span = c_make(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}); - Span3 span3 = cspan_md(span.data, 2, 4, 3); - - // numpy style printout - puts("span3:"); - cspan_print(Span3, "%d", span3); - - puts("\nspan3[:, 3:4, :]:"); - Span3 ss3 = cspan_slice(&span3, Span3, {c_ALL}, {3,4}, {c_ALL}); - cspan_print(Span3, "%d", ss3); - - puts("\nspan3[:, 3, :]:"); - Span2 ss2 = cspan_slice(&span3, Span2, {c_ALL}, {3}, {c_ALL}); - cspan_print(Span2, "%d", ss2); - - puts("\nspan3 swap axes to: [1, 2, 0]"); - Span3 swapped = span3; - cspan_swap_axes(&swapped, 0, 1); - cspan_swap_axes(&swapped, 1, 2); - cspan_print(Span3, "%d", swapped); -} -``` diff --git a/src/finchlite/codegen/stc/docs/cstr_api.md b/src/finchlite/codegen/stc/docs/cstr_api.md deleted file mode 100644 index b01cb00f..00000000 --- a/src/finchlite/codegen/stc/docs/cstr_api.md +++ /dev/null @@ -1,211 +0,0 @@ -# STC [cstr](../include/stc/cstr.h): String -![String](pics/string.jpg) - -A **cstr** object represent sequences of characters. It supports an interface similar -to that of a standard container of bytes, but adding features specifically designed to -operate with strings of single-byte characters, terminated by the null character. - -**cstr** has support for *UTF8* encoded strings, and has a set of small and -efficient functions for handling case-conversion, iteration and indexing into UTF8 -codepoints (runes). - -**cstr** uses short strings optimization (sso), which eliminates heap memory allocation -for string capacity up to 22 bytes. - -## Header file - -All cstr definitions and prototypes are available by including a single header file. - -```c++ -#include -``` - -## Methods -```c++ -cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call. -cstr cstr_init(void); // make an empty string -cstr cstr_from(const char* str); // construct from a zero-terminated c-string. -cstr cstr_from_s(cstr s, isize pos, isize len); // construct a substring -cstr cstr_from_sv(csview sv); // construct from a string view -cstr cstr_from_zv(zsview zv); // construct from a zero-terminated zsview -cstr cstr_from_fmt(const char* fmt, ...); // construct from printf() formatting -cstr cstr_from_replace(csview sv, csview search, csview repl, int32_t count); -cstr cstr_from_n(const char* str, isize n); // construct from first n bytes of str -cstr cstr_with_capacity(isize cap); // make empty string with pre-allocated capacity. -cstr cstr_with_size(isize len, char fill); // make string with fill characters - -cstr cstr_clone(cstr s); -cstr* cstr_take(cstr* self, cstr s); // take ownership of s, i.e. don't drop s. -cstr cstr_move(cstr* self); // move string to caller, leave self empty -void cstr_drop(cstr* self); // destructor - -isize cstr_size(const cstr* self); -isize cstr_capacity(const cstr* self); -isize cstr_to_index(const cstr* self, cstr_iter it); // to byte position at iter. -bool cstr_is_empty(const cstr* self); // test from empty string - -const char* cstr_str(const cstr* self); // get const char* -char* cstr_data(cstr* self); // get mutable char* -cstr_buf cstr_getbuf(cstr* self); // to mutable buffer struct (with capacity) -zsview cstr_zv(const cstr* self); // to zero-terminated string view -csview cstr_sv(const cstr* self); // to csview string view -zsview cstr_tail(cstr* self, isize len); // to zsview subview of the trailing len bytes -csview cstr_subview(const cstr* self, isize pos, isize len); // to csview subview from pos and length len - -void cstr_clear(cstr* self); -char* cstr_reserve(cstr* self, isize capacity); // return pointer to buffer -void cstr_resize(cstr* self, isize len, char fill); -void cstr_shrink_to_fit(cstr* self); - -char* cstr_assign(cstr* self, const char* str); -char* cstr_assign_n(cstr* self, const char* str, isize n); // assign n first bytes of str -char* cstr_assign_sv(cstr* self, csview sv); -char* cstr_copy(cstr* self, cstr s); // assign a clone of s -int cstr_printf(cstr* self, const char* fmt, ...); // source and target must not overlap. -isize cstr_vfmt(cstr* self, isize start, const char* fmt, va_list args); // mostly for internal use. - -char* cstr_append(cstr* self, const char* str); -char* cstr_append_n(cstr* self, const char* str, isize n); // append n first bytes of str -char* cstr_append_sv(cstr* self, csview str); -char* cstr_append_s(cstr* self, cstr str); -int cstr_append_fmt(cstr* self, const char* fmt, ...); // printf() formatting -char* cstr_append_uninit(cstr* self, isize len); // return ptr to start of uninited data - -void cstr_join(cstr* self, const char* sep, cstr-vec vec); // join and append vec/stack of cstrs -void cstr_join_n(cstr* self, const char* sep, const char* arr[], isize n); // join and append c-strings -void cstr_join_items(cstr* self, const char* sep, {const char* s1,...}); // join and append c-strings - -void cstr_push(cstr* self, const char* chr); // append one utf8 char -void cstr_pop(cstr* self); // pop one utf8 char - -void cstr_insert(cstr* self, isize pos, const char* ins); -void cstr_insert_sv(cstr* self, isize pos, csview ins); - -void cstr_erase(cstr* self, isize pos, isize len); // erase len bytes from pos - -void cstr_replace(cstr* self, const char* search, const char* repl); -void cstr_replace_nfirst(cstr* self, const char* search, const char* repl, int32_t count); // replace count instances -cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count); -void cstr_replace_at(cstr* self, isize pos, isize len, const char* repl); // replace at a pos -void cstr_replace_at_sv(cstr* self, isize pos, isize len, const csview repl); - -bool cstr_equals(const cstr* self, const char* str); -bool cstr_equals_sv(const cstr* self, csview sv); - -isize cstr_find(const cstr* self, const char* search); -isize cstr_find_sv(const cstr* self, csview search); -isize cstr_find_at(const cstr* self, isize pos, const char* search); // search from pos -bool cstr_contains(const cstr* self, const char* search); - -bool cstr_starts_with(const cstr* self, const char* str); -bool cstr_starts_with_sv(const cstr* self, csview sv); - -bool cstr_ends_with(const cstr* self, const char* str); -bool cstr_ends_with_sv(const cstr* self, csview sv); - -bool cstr_getline(cstr *self, FILE *stream); // cstr_getdelim(self, '\n', stream) -bool cstr_getdelim(cstr *self, int delim, FILE *stream); // does not append delim to result -``` - -#### UTF8 methods -```c++ -cstr cstr_u8_from(const char* str, isize u8pos, isize u8len);// make cstr from an utf8 substring -isize cstr_u8_size(const cstr* self); // number of utf8 runes -isize cstr_u8_to_index(const cstr* self, isize u8pos); // get byte index at rune position -cstr_iter cstr_u8_at(const cstr* self, isize u8pos); // get rune at rune position -csview cstr_u8_subview(const cstr* self, isize u8pos, isize u8len); -zsview cstr_u8_tail(cstr* self, isize u8len); // subview of the trailing len runes -void cstr_u8_insert(cstr* self, isize u8pos, const char* ins); -void cstr_u8_replace(cstr* self, isize u8pos, isize u8len, const char* repl); -void cstr_u8_erase(cstr* self, isize u8pos, isize u8len); // erase u8len runes from u8pos -bool cstr_u8_valid(const cstr* self); // verify that str is valid utf8 - -bool cstr_iequals(const cstr* self, const char* str); // utf8 case-insensitive comparison -bool cstr_istarts_with(const cstr* self, const char* str); // utf8 case-insensitive -bool cstr_iends_with(const cstr* self, const char* str); // utf8 case-insensitive - -cstr_iter cstr_begin(const cstr* self); // iterate utf8 codepoints (runes) -cstr_iter cstr_end(const cstr* self); -void cstr_next(cstr_iter* it); // next rune -cstr_iter cstr_advance(cstr_iter it, isize u8pos); // advance +/- runes - -cstr cstr_casefold_sv(csview sv); // returns new casefolded utf8 cstr -cstr cstr_tolower_sv(csview sv); // returns new lowercase utf8 cstr -cstr cstr_toupper_sv(csview sv); // returns new uppercase utf8 cstr -cstr cstr_tolower(const char* str); // returns new lowercase utf8 cstr -cstr cstr_toupper(const char* str); // returns new uppercase utf8 cstr -void cstr_lowercase(cstr* self); // transform cstr to lowercase utf8 -void cstr_uppercase(cstr* self); // transform cstr to uppercase utf8 -``` - -Note that all methods with arguments `(..., const char* str, isize n)`, `n` must be within the range of `str` length. - -#### Helper methods: -```c++ -size_t cstr_hash(const cstr* self); -int cstr_cmp(const cstr* s1, const cstr* s2); -bool cstr_eq(const cstr* s1, const cstr* s2); -int cstr_icmp(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison -bool cstr_ieq(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison - -char* c_strnstrn(const char* str, isize slen, const char* needle, isize nlen); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:----------------|:---------------------------------------------|:---------------------| -| `cstr` | `struct { ... }` | The string type | -| `cstr_value` | `char` | String element type | -| `cstr_iter` | `union { cstr_value *ref; csview chr; }` | String iterator | -| `cstr_buf` | `struct { char *data; isize size, cap; }` | String buffer type | - -## Constants and macros - -| Name | Value | -|:----------------|:------------------| -| `c_NPOS` | `INTPTR_MAX` | - -## Example -```c++ -#include - -int main(void) { - cstr s0, s1, full_path; - c_defer( - cstr_drop(&s0), cstr_drop(&s1), cstr_drop(&full_path) - ){ - s0 = cstr_lit("Initialization without using strlen()."); - printf("%s\nLength: %" c_ZI "\n\n", cstr_str(&s0), cstr_size(&s0)); - - s1 = cstr_lit("one-nine-three-seven-five."); - printf("%s\n", cstr_str(&s1)); - - cstr_insert(&s1, 3, "-two"); - printf("%s\n", cstr_str(&s1)); - - cstr_erase(&s1, 7, 5); // -nine - printf("%s\n", cstr_str(&s1)); - - cstr_replace_nfirst(&s1, "seven", "four", 1); - printf("%s\n", cstr_str(&s1)); - - // reassign: - cstr_assign(&s1, "one two three four five six seven"); - cstr_append(&s1, " eight"); - printf("append: %s\n", cstr_str(&s1)); - - full_path = cstr_from_fmt("%s/%s.%s", "directory", "filename", "ext"); - printf("%s\n", cstr_str(&full_path)); - } -} -``` -Output: -``` -one-nine-three-seven-five. -one-two-nine-three-seven-five. -one-two-three-seven-five. -one-two-three-four-five. -append: one two three four five six seven eight -directory/filename.ext -``` diff --git a/src/finchlite/codegen/stc/docs/csview_api.md b/src/finchlite/codegen/stc/docs/csview_api.md deleted file mode 100644 index 59828e35..00000000 --- a/src/finchlite/codegen/stc/docs/csview_api.md +++ /dev/null @@ -1,227 +0,0 @@ -# STC [csview](../include/stc/csview.h): Non-zero terminated String View -![String](pics/string.jpg) - -The type **csview** is a ***non-zero terminated*** and ***utf8-iterable*** string view. It refers to a -constant contiguous sequence of char-elements with the first element of the sequence at position zero. -The implementation holds two members: a pointer to constant char and a size. See [zsview](zsview_api.md) -for a ***zero-terminated*** string view/span type. - -**csview** never allocates memory, and therefore need not be destructed. Its lifetime is limited by the -source string storage. It keeps the length of the string, which redcues the need to call *strlen()* in -usage. - -- **csview** iterators works on UTF8 codepoints - like **cstr** and **zsview** (see Example 2). -- Because it is not zero-terminated, it must be printed the following way: -```c++ -csview sv = c_sv("Hello world"); -sv = csview_subview(sv, 0, 5); -printf(c_svfmt "\n", c_svarg(sv)); // "Hello" -``` - -See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) -for a functional description. - -## Header file - -All csview definitions and prototypes are available by including a single header file. - -```c++ -#include -#include // after cstr.h: include extra cstr-csview functions -``` -## Methods - -```c++ -csview c_sv(const char literal_only[]); // from string literal only -csview c_sv(const char* str, isize n); // from a const char* and length n -csview csview_from(const char* str); // from const char* str -csview csview_from_n(const char* str, isize n); // alias for c_sv(str, n) - -isize csview_size(csview sv); -bool csview_is_empty(csview sv); -void csview_clear(csview* self); - -bool csview_equals(csview sv, const char* str); -isize csview_find(csview sv, const char* str); -isize csview_find_sv(csview sv, csview find); -bool csview_contains(csview sv, const char* str); -bool csview_starts_with(csview sv, const char* str); -bool csview_ends_with(csview sv, const char* str); - -csview csview_subview(csview sv, isize pos, isize len); -csview csview_slice(csview sv, isize pos1, isize pos2); -csview csview_tail(csview sv, isize len); // span of the trailing len bytes -csview csview_trim(csview sv); // trim whitespace and ctrl-chars on both ends -csview csview_trim_start(csview sv); // trim from start of view -csview csview_trim_end(csview sv); // trim from end of view - -csview csview_subview_pro(csview sv, isize pos, isize len); // negative pos count from end -csview csview_token(csview sv, const char* sep, isize* start); // *start > sv.size after last token -``` - -#### UTF8 methods -```c++ -csview csview_u8_from(const char* str, isize u8pos, isize u8len); // construct csview with u8len runes -isize csview_u8_size(csview sv); // number of utf8 runes -csview_iter csview_u8_at(csview sv, isize u8pos); // get rune at rune position -csview csview_u8_subview(csview sv, isize u8pos, isize u8len); // utf8 span -csview csview_u8_tail(csview sv, isize u8len); // span of the trailing u8len runes. -bool csview_u8_valid(csview sv); // check utf8 validity of sv - -bool csview_iequals(csview sv, const char* str); // utf8 case-insensitive comparison -bool csview_istarts_with(csview sv, const char* str); // utf8 case-insensitive -bool csview_iends_with(csview sv, const char* str); // utf8 case-insensitive - -csview_iter csview_begin(const csview* self); // utf8 iteration -csview_iter csview_end(const csview* self); -void csview_next(csview_iter* it); // next utf8 codepoint -csview_iter csview_advance(csview_iter it, isize u8pos); // advance +/- codepoints -``` - -#### Iterate tokens with *c_token* - -Iterate tokens in an input string split by a separator string: -- `for (c_token_sv(it, const char* separator, csview input_sv)) ...;` -- `it.token` is a csview of the current token. - -```c++ -for (c_token(i, ", ", "hello, one, two, three")) - printf("'" c_svfmt "' ", c_svarg(i.token)); -// 'hello' 'one' 'two' 'three' -``` - -#### Helper methods -```c++ -size_t csview_hash(const csview* x); -int csview_cmp(const csview* x, const csview* y); -bool csview_eq(const csview* x, const csview* y); -int csview_icmp(const csview* x, const csview* y); -bool csview_ieq(const csview* x, const csview* y); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:----------------|:-------------------------------------------|:-------------------------| -| `csview` | `struct { const char *buf; isize size; }` | The string view type | -| `csview_value` | `const char` | The string element type | -| `csview_iter` | `union { csview_value *ref; csview chr; }` | UTF8 iterator | - -## Constants and macros - -| Name | Value | Usage | -|:---------------|:---------------------|:---------------------------------------------| -| `c_svarg(sv)` | printf argument | `printf("sv: " c_svfmt "\n", c_svarg(sv));` | - -## Example -```c++ -#include -#include - - -int main(void) -{ - cstr str = cstr_lit("We think in generalities, but we live in details."); - csview sv = cstr_sv(&str); - csview sv1 = csview_subview(sv, 3, 5); // "think" - isize pos = csview_find(sv, "live"); // position of "live" - csview sv2 = csview_subview(sv, pos, 4); // "live" - csview sv3 = csview_subview_pro(sv, -8, 7); // "details" - printf(c_svfmt ", " c_svfmt ", " c_svfmt "\n", - c_svarg(sv1), c_svarg(sv2), c_svarg(sv3)); - - cstr_assign(&str, "apples are green or red"); - sv = cstr_sv(&str); - cstr s2 = cstr_from_sv(csview_subview_pro(sv, -3, 3)); // "red" - cstr s3 = cstr_from_sv(csview_subview(sv, 0, 6)); // "apples" - - c_drop(cstr, &str, &s2, &s3); -} -``` -Output: -``` -think live details -red Apples -``` - -### Example 2: UTF8 handling -```c++ -#include - -int main(void) -{ - cstr s1 = cstr_lit("hell😀 w😀rld"); - - cstr_u8_replace(&s1, 7, 1, "ø"); - printf("%s\n", cstr_str(&s1)); - - for (c_each(i, cstr, s1)) - printf(c_svfmt ",", c_svarg(i.chr)); - - cstr_drop(&s1); -} -``` -Output: -``` -hell😀 wørld -h,e,l,l,😀, ,w,ø,r,l,d, -``` - -### Example 3: csview tokenizer (string split) -Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, -and does not depend on zero-terminated strings. *string_split()* function returns a vector of cstr. -```c++ -#include -#include - -void print_split(csview input, const char* sep) -{ - for (c_token_sv(i, sep, input)) - printf("[" c_svfmt "]\n", c_svarg(i.token)); - puts(""); -} -#include -#define i_keypro cstr -#include - -stack_cstr string_split(csview input, const char* sep) -{ - stack_cstr out = {0}; - - for (c_token(i, sep, input)) - stack_cstr_push(&out, cstr_from_sv(i.token)); - - return out; -} - -int main(void) -{ - print_split(c_sv("//This is a//double-slash//separated//string"), "//"); - print_split(c_sv("This has no matching separator"), "xx"); - - stack_cstr s = string_split(c_sv("Split,this,,string,now,"), ","); - - for (c_each(i, stack_cstr, s)) - printf("[%s]\n", cstr_str(i.ref)); - puts(""); - - stack_cstr_drop(&s); -} -``` -Output: -``` -[] -[This is a] -[double-slash] -[separated] -[string] - -[This has no matching separator] - -[Split] -[this] -[] -[string] -[now] -[] -``` diff --git a/src/finchlite/codegen/stc/docs/deque_api.md b/src/finchlite/codegen/stc/docs/deque_api.md deleted file mode 100644 index ddfd62f6..00000000 --- a/src/finchlite/codegen/stc/docs/deque_api.md +++ /dev/null @@ -1,157 +0,0 @@ -# STC [deque](../include/stc/deque.h): Double Ended Queue -![Deque](pics/deque.jpg) - -A **deque** is an indexed sequence container that allows fast insertion and deletion at both -its beginning and its end, but has also fast random access to elements. The container is -implemented as a circular dynamic buffer. Iterators may be invalidated after push-operations. - -See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque) for a functional description. - -## Header file and declaration - -```c++ -#define T ,[,] // shorthand for defining T, i_key, i_opt -#define T // deque container type name (default: deque_{i_key}) -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop is defined - -#define i_use_cmp // enable sorting, binary_search and lower_bound -#define i_cmp // three-way compare two i_keyraw's -#define i_less // less comparison. Alternative to i_cmp -#define i_eq // equality comparison. Implicitly defined with i_cmp, but not i_less. - -#define i_keyraw // conversion "raw" type - defaults to i_key -#define i_cmpclass // conversion "raw class". binds _cmp(), _eq(), _hash() -#define i_keyfrom // conversion func i_keyraw => i_key -#define i_keytoraw // conversion func i_key* => i_keyraw - -#include -``` -- Defining either `i_use_cmp`, `i_less` or `i_cmp` will enable sorting, binary_search and lower_bound -- **emplace**-functions are only available when `i_keyraw` is implicitly or explicitly defined. -- In the following, `X` is the value of `i_key` unless `T` is defined. - -## Methods - -```c++ -deque_X deque_X_init(void); -deque_X deque_X_with_capacity(isize cap); -deque_X deque_X_with_size(isize size, i_keyraw value); -deque_X deque_X_with_size_uninit(isize size); - -deque_X deque_X_clone(deque_X deque); -void deque_X_copy(deque_X* self, const deque_X* other); -void deque_X_take(deque_X* self, deque_X unowned); // take ownership of unowned -deque_X deque_X_move(deque_X* self); // move -void deque_X_drop(const deque_X* self); // destructor - -void deque_X_clear(deque_X* self); -bool deque_X_reserve(deque_X* self, isize cap); -void deque_X_shrink_to_fit(deque_X* self); - -bool deque_X_is_empty(const deque_X* self); -isize deque_X_size(const deque_X* self); -isize deque_X_capacity(const deque_X* self); - -deque_X_iter deque_X_find(const deque_X* self, i_keyraw raw); -deque_X_iter deque_X_find_in(deque_X_iter i1, deque_X_iter i2, i_keyraw raw); // return vec_X_end() if not found - -const i_key* deque_X_at(const deque_X* self, isize idx); -const i_key* deque_X_front(const deque_X* self); -const i_key* deque_X_back(const deque_X* self); - -i_key* deque_X_at_mut(deque_X* self, isize idx); -i_key* deque_X_front_mut(deque_X* self); -i_key* deque_X_back_mut(deque_X* self); - - // Requires either i_use_cmp, i_cmp or i_less defined: -void deque_X_sort(deque_X* self); // quicksort from sort.h -isize deque_X_lower_bound(const deque_X* self, const i_keyraw raw); // return c_NPOS if not found -isize deque_X_binary_search(const deque_X* self, const i_keyraw raw); // return c_NPOS if not found - -i_key* deque_X_push_front(deque_X* self, i_key value); -i_key* deque_X_emplace_front(deque_X* self, i_keyraw raw); -void deque_X_pop_front(deque_X* self); -i_key deque_X_pull_front(deque_X* self); // move out front element - -i_key* deque_X_push_back(deque_X* self, i_key value); -i_key* deque_X_push(deque_X* self, i_key value); // alias for push_back() -i_key* deque_X_emplace_back(deque_X* self, i_keyraw raw); -i_key* deque_X_emplace(deque_X* self, i_keyraw raw); // alias for emplace_back() -void deque_X_pop_back(deque_X* self); // remove and destroy back() -i_key deque_X_pull_back(deque_X* self); // move out last element - -deque_X_iter deque_X_insert_n(deque_X* self, isize idx, const i_key[] arr, isize n); // move values -deque_X_iter deque_X_insert_at(deque_X* self, deque_X_iter it, i_key value); // move value -deque_X_iter deque_X_insert_uninit(deque_X* self, isize idx, isize n); // uninitialized data - -deque_X_iter deque_X_emplace_n(deque_X* self, isize idx, const i_keyraw[] arr, isize n); -deque_X_iter deque_X_emplace_at(deque_X* self, deque_X_iter it, i_keyraw raw); - -void deque_X_erase_n(deque_X* self, isize idx, isize n); -deque_X_iter deque_X_erase_at(deque_X* self, deque_X_iter it); -deque_X_iter deque_X_erase_range(deque_X* self, deque_X_iter it1, deque_X_iter it2); - -deque_X_iter deque_X_begin(const deque_X* self); -deque_X_iter deque_X_end(const deque_X* self); -void deque_X_next(deque_X_iter* it); -deque_X_iter deque_X_advance(deque_X_iter it, isize n); - -bool deque_X_eq(const deque_X* c1, const deque_X* c2); // require i_eq/i_cmp/i_less. -i_key deque_X_value_clone(const deque_X* self, i_key val); -deque_X_raw deque_X_value_toraw(const i_key* pval); -void deque_X_value_drop(i_key* pval); -``` -## Types - -| Type name | Type definition | Used to represent... | -|:------------------|:-----------------------------------|:-----------------------| -| `deque_X` | `struct { deque_X_value* data; }` | The deque type | -| `deque_X_value` | `i_key` | The deque value type | -| `deque_X_raw` | `i_keyraw` | The raw value type | -| `deque_X_iter` | `struct { deque_X_value* ref; }` | The iterator type | - -## Examples - -[ [Run this code](https://godbolt.org/z/1TTT68fv5) ] -```c++ -#define T Deque, int32_t -#include -#include - -int main(void) { - Deque q = {0}; - Deque_push_front(&q, 10); - for (c_each(i, Deque, q)) - printf(" %d", *i.ref); - puts(""); - - for (c_items(i, int, {1, 4, 5, 22, 33, 2})) - Deque_push_back(&q, *i.ref); - - for (c_each(i, Deque, q)) - printf(" %d", *i.ref); - puts(""); - - Deque_push_front(&q, 9); - Deque_push_front(&q, 20); - Deque_push_back(&q, 11); - Deque_push_front(&q, 8); - - for (c_each(i, Deque, q)) - printf(" %d", *i.ref); - puts(""); - Deque_drop(&q); -} -``` -Output: -``` - 10 - 10 1 4 5 22 33 2 - 8 20 9 10 1 4 5 22 33 2 1 -``` diff --git a/src/finchlite/codegen/stc/docs/hmap_api.md b/src/finchlite/codegen/stc/docs/hmap_api.md deleted file mode 100644 index b0bc6f4c..00000000 --- a/src/finchlite/codegen/stc/docs/hmap_api.md +++ /dev/null @@ -1,355 +0,0 @@ -# STC [hmap](../include/stc/hmap.h): HashMap (unordered) -![Map](pics/map.jpg) - -A **hmap** is an associative container that contains key-value pairs with unique keys. Search, insertion, and removal of elements -have average constant-time complexity. Internally, the elements are not sorted in any particular order, but organized into -buckets. Which bucket an element is placed into depends entirely on the hash of its key. This allows fast access to individual -elements, since once the hash is computed, it refers to the exact bucket the element is placed into. It is implemented as closed -hashing (aka open addressing) with linear probing, and without leaving tombstones on erase. - -***Iterator invalidation***: References and iterators are invalidated after erase. No iterators are invalidated after insert, -unless the hash-table need to be extended. The hash table size can be reserved prior to inserts if the total max size is known. -The order of elements may not be preserved after erase. It is still possible to erase elements when iterating through -the container by setting the iterator to the value returned from *erase_at()*, which references the next element. Note that a small number of elements may be visited twice when doing this, but all elements will be visited. - -See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/container/unordered_map) for a functional description. - -## Header file and declaration - -```c++ -#define T ,,[,] // shorthand for defining T, i_key, i_val, i_opt -#define T // container type name (default: hmap_{i_key}) -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -// One of the following: -#define i_val // mapped value type -#define i_valclass // mapped type, and bind _clone() and _drop() function names -#define i_valpro // mapped "pro" type, use for cstr, arc, box types - -#define i_hash // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type -#define i_eq // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a - // non-integral type. Three-way i_cmp may be specified instead. -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // conversion "raw" type - defaults to i_key -#define i_cmpclass // conversion "raw class". binds _cmp(), _eq(), _hash() -#define i_keyfrom // conversion func i_keyraw => i_key -#define i_keytoraw // conversion func i_key* => i_keyraw - -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined -#define i_valraw // conversion "raw" type - defaults to i_val -#define i_valfrom // conversion func i_valraw => i_val -#define i_valtoraw // conversion func i_val* => i_valraw - -#include -``` -- In the following, `X` is the value of `i_key` unless `T` is defined. -- **emplace**-functions are only available when `i_keyraw`/`i_valraw` are implicitly or explicitly defined. -## Methods - -```c++ -hmap_X hmap_X_init(void); -hmap_X hmap_X_with_capacity(isize cap); - -hmap_X hmap_X_clone(hmap_x map); -void hmap_X_copy(hmap_X* self, const hmap_X* other); -void hmap_X_take(hmap_X* self, hmap_X unowned); // take ownership of unowned -hmap_X hmap_X_move(hmap_X* self); // move -void hmap_X_drop(const hmap_X* self); // destructor - -void hmap_X_clear(hmap_X* self); -float hmap_X_max_load_factor(const hmap_X* self); // default: 0.85f -bool hmap_X_reserve(hmap_X* self, isize size); -void hmap_X_shrink_to_fit(hmap_X* self); - -bool hmap_X_is_empty(const hmap_X* self ); -isize hmap_X_size(const hmap_X* self); -isize hmap_X_capacity(const hmap_X* self); // buckets * max_load_factor -isize hmap_X_bucket_count(const hmap_X* self); // num. of allocated buckets - -const i_val* hmap_X_at(const hmap_X* self, i_keyraw rkey); // rkey must be in map -i_val* hmap_X_at_mut(hmap_X* self, i_keyraw rkey); // mutable at -const X_value* hmap_X_get(const hmap_X* self, i_keyraw rkey); // const get -X_value* hmap_X_get_mut(hmap_X* self, i_keyraw rkey); // mutable get -bool hmap_X_contains(const hmap_X* self, i_keyraw rkey); -hmap_X_iter hmap_X_find(const hmap_X* self, i_keyraw rkey); // find element - -hmap_X_result hmap_X_insert(hmap_X* self, i_key key, i_val mapped); // no change if key in map -hmap_X_result hmap_X_insert_or_assign(hmap_X* self, i_key key, i_val mapped); // always update mapped -hmap_X_result hmap_X_push(hmap_X* self, hmap_X_value entry); // similar to insert -hmap_X_result hmap_X_put(hmap_X* self, i_keyraw rkey, i_valraw rmapped); // like emplace_or_assign() - -hmap_X_result hmap_X_emplace(hmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map -hmap_X_result hmap_X_emplace_or_assign(hmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update mapped - -int hmap_X_erase(hmap_X* self, i_keyraw rkey); // return 0 or 1 -hmap_X_iter hmap_X_erase_at(hmap_X* self, hmap_X_iter it); // return iter after it -void hmap_X_erase_entry(hmap_X* self, hmap_X_value* entry); - -hmap_X_iter hmap_X_begin(const hmap_X* self); -hmap_X_iter hmap_X_end(const hmap_X* self); -void hmap_X_next(hmap_X_iter* it); -hmap_X_iter hmap_X_advance(hmap_X_iter it, hmap_X_ssize n); - -hmap_X_value hmap_X_value_clone(const hmap_X* self, hmap_X_value val); -hmap_X_raw hmap_X_value_toraw(hmap_X_value* pval); -``` -Free helper functions: -```c++ -size_t c_hash_n(const void *data, isize n); // generic hash function of n bytes -size_t c_hash_str(const char *str); // string hash function, uses strlen() -size_t c_hash_mix(size_t h1, size_t h2, ...); // mix/combine computed hashes -isize c_next_pow2(isize k); // get next power of 2 >= k - -// hash/equal template default functions: -size_t c_default_hash(const T *obj); // alias for c_hash_n(obj, sizeof *obj) -bool c_default_eq(const i_keyraw* a, const i_keyraw* b); // *a == *b -bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // !memcmp(a, b, sizeof *a) -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:-------------------|:------------------------------------------------|:------------------------------| -| `hmap_X` | `struct { ... }` | The hmap type | -| `hmap_X_key` | `i_key` | The key type | -| `hmap_X_mapped` | `i_val` | The mapped type | -| `hmap_X_value` | `struct { const i_key first; i_val second; }` | The value: key is immutable | -| `hmap_X_keyraw` | `i_keyraw` | The raw key type | -| `hmap_X_rmapped` | `i_valraw` | The raw mapped type | -| `hmap_X_raw` | `struct { i_keyraw first; i_valraw second; }` | i_keyraw + i_valraw type | -| `hmap_X_result` | `struct { hmap_X_value *ref; bool inserted; }` | Result of insert/emplace | -| `hmap_X_iter` | `struct { hmap_X_value *ref; ... }` | Iterator type | - -## Examples - -[ [Run this code](https://godbolt.org/z/5441E5dEx) ] -```c++ -#include - -#define T hmap_cstr, cstr, cstr, (c_keypro | c_valpro) -#include - -int main(void) -{ - // Create an unordered_map of three strings (that map to strings) - hmap_cstr umap = c_make(hmap_cstr, { - {"RED", "#FF0000"}, - {"GREEN", "#00FF00"}, - {"BLUE", "#0000FF"} - }); - - // Iterate and print keys and values of unordered map - for (c_each(n, hmap_cstr, umap)) { - hmap_cstr_raw v = hmap_cstr_value_toraw(n.ref); - printf("Key:[%s] Value:[%s]\n", v.first, v.second); - } - - // Add two new entries to the unordered map - hmap_cstr_emplace(&umap, "BLACK", "#000000"); - hmap_cstr_emplace(&umap, "WHITE", "#FFFFFF"); - - // Output values by key - printf("The HEX of color RED is:[%s]\n", cstr_str(hmap_cstr_at(&umap, "RED"))); - printf("The HEX of color BLACK is:[%s]\n", cstr_str(hmap_cstr_at(&umap, "BLACK"))); - - hmap_cstr_drop(&umap); -} -``` - -### Example 2 -Demonstrate hmap with mapped POD type Vec3i: hmap: - -[ [Run this code](https://godbolt.org/z/q46YnvWee) ] -```c++ -#include -typedef struct { int x, y, z; } Vec3i; - -#define T hmap_iv, int, Vec3i -#include - -int main(void) -{ - hmap_iv vecs = {0}; - - hmap_iv_insert(&vecs, 1, (Vec3i){100, 0, 0}); - hmap_iv_insert(&vecs, 2, (Vec3i){ 0, 100, 0}); - hmap_iv_insert(&vecs, 3, (Vec3i){ 0, 0, 100}); - hmap_iv_insert(&vecs, 4, (Vec3i){100, 100, 100}); - - for (c_each_kv(num, v3, hmap_iv, vecs)) - printf("%d: { %3d, %3d, %3d }\n", *num, v3->x, v3->y, v3->z); - - hmap_iv_drop(&vecs); -} -``` - -### Example 3 -Inverse: Demonstrate hmap with plain-old-data key type Vec3i and int as mapped type: hmap. - -[ [Run this code](https://godbolt.org/z/sjcqG35x6) ] -```c++ -#include -typedef struct { int x, y, z; } Vec3i; - -#define T hmap_vi, Vec3i, int -#define i_eq c_memcmp_eq // bitwise equal -#include - -int main(void) -{ - // Define map with defered destruct - hmap_vi vecs = {0}; - - hmap_vi_insert(&vecs, (Vec3i){100, 0, 0}, 1); - hmap_vi_insert(&vecs, (Vec3i){ 0, 100, 0}, 2); - hmap_vi_insert(&vecs, (Vec3i){ 0, 0, 100}, 3); - hmap_vi_insert(&vecs, (Vec3i){100, 100, 100}, 4); - - for (c_each_kv(v3, num, hmap_vi, vecs)) - printf("{ %3d, %3d, %3d }: %d\n", v3->x, v3->y, v3->z, *num); - - hmap_vi_drop(&vecs); -} -``` - -### Example 4: Advanced -Key type is struct. Based on https://doc.rust-lang.org/std/collections/struct.HashMap.html - -[ [Run this code](https://godbolt.org/z/3WGx8sWET) ] -```c++ -#include - -typedef struct { - cstr name; - cstr country; -} Viking; - -Viking Viking_make(cstr_raw name, cstr_raw country) { - return (Viking){.name = cstr_from(name), .country = cstr_from(country)}; -} - -bool Viking_eq(const Viking* a, const Viking* b) { - return cstr_eq(&a->name, &b->name) && cstr_eq(&a->country, &b->country); -} - -size_t Viking_hash(const Viking* a) { - return cstr_hash(&a->name) ^ cstr_hash(&a->country); -} - -Viking Viking_clone(Viking v) { - v.name = cstr_clone(v.name); - v.country = cstr_clone(v.country); - return v; -} - -void Viking_drop(Viking* vp) { - cstr_drop(&vp->name); - cstr_drop(&vp->country); -} - -// binds the four Viking_xxxx() functions above -#define T Vikings, Viking, int, (c_keyclass) -#include - -int main(void) -{ - // Use a HashMap to store the vikings' health points. - Vikings vikings = c_make(Vikings, { - {Viking_make("Einar", "Norway"), 25}, - {Viking_make("Olaf", "Denmark"), 24}, - {Viking_make("Harald", "Iceland"), 12}, - }); - - Viking lookup = Viking_make("Olaf", "Denmark"); - printf("Lookup: Olaf of Denmark has %d hp\n\n", *Vikings_at(&vikings, lookup)); - Viking_drop(&lookup); - - // Print the status of the vikings. - for (c_each_kv(viking, health, Vikings, vikings)) { - printf("%s of %s has %d hp\n", cstr_str(&viking->name), - cstr_str(&viking->country), *health); - } - Vikings_drop(&vikings); -} -``` - -### Example 5: More advanced -In example 4 we needed to construct a lookup key which may allocate strings, and then had to free it after. -In this example we use keyraw feature to make it simpler to use and avoids the creation of a Viking object -entirely when doing lookup. - -[ [Run this code](https://godbolt.org/z/Y5sTefr4q) ] - -```c++ -#include - -typedef struct Viking { - cstr name; - cstr country; -} Viking; - -Viking Viking_make(cstr_raw name, cstr_raw country) { - return (Viking){.name = cstr_from(name), .country = cstr_from(country)}; -} - -void Viking_drop(Viking* vk) { - cstr_drop(&vk->name); - cstr_drop(&vk->country); -} - -Viking Viking_clone(Viking v) { - v.name = cstr_clone(v.name); - v.country = cstr_clone(v.country); - return v; -} - -// Define Viking_raw, a Viking lookup struct with eq, hash and conversion functions between them: -typedef struct { - const char* name; - const char* country; -} Viking_raw; - -bool Viking_raw_eq(const Viking_raw* rx, const Viking_raw* ry) { - return strcmp(rx->name, ry->name)==0 && strcmp(rx->country, ry->country)==0; -} - -size_t Viking_raw_hash(const Viking_raw* rv) { - return c_hash_mix(c_hash_str(rv->name), c_hash_str(rv->country)); -} - -Viking Viking_from(Viking_raw raw) { // note: parameter is by value - Viking v = {cstr_from(raw.name), cstr_from(raw.country)}; return v; -} - -Viking_raw Viking_toraw(const Viking* vp) { - Viking_raw rv = {cstr_str(&vp->name), cstr_str(&vp->country)}; return rv; -} - -// Define the map. Viking is now a "pro"-type: -#define T Vikings, Viking, int, (c_keypro) -#include - -int main(void) -{ - Vikings vikings = c_make(Vikings, { - {{"Einar", "Norway"}, 25}, - {{"Olaf", "Denmark"}, 24}, - {{"Harald", "Iceland"}, 12}, - }); - - // Now lookup is using Viking_raw, not Viking: - printf("Lookup: Olaf of Denmark has %d hp\n\n", *Vikings_at(&vikings, (Viking_raw){"Olaf", "Denmark"})); - - for (c_each(v, Vikings, vikings)) { - Vikings_raw r = Vikings_value_toraw(v.ref); - printf("%s of %s has %d hp\n", r.first.name, r.first.country, r.second); - } - Vikings_drop(&vikings); -} -``` - diff --git a/src/finchlite/codegen/stc/docs/hset_api.md b/src/finchlite/codegen/stc/docs/hset_api.md deleted file mode 100644 index f1f0456c..00000000 --- a/src/finchlite/codegen/stc/docs/hset_api.md +++ /dev/null @@ -1,118 +0,0 @@ -# STC [hset](../include/stc/hset.h): HashSet (unordered) -![Set](pics/set.jpg) - -A **hset** is an associative container that contains a set of unique objects of type i_key. Search, insertion, and removal have average constant-time complexity. See the c++ class -[std::unordered_set](https://en.cppreference.com/w/cpp/container/unordered_set) for a functional description. - -## Header file and declaration - -```c++ -#define T ,[,] // shorthand for defining T, i_key, i_opt -#define T // container type name (default: hset_{i_key}) -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -#define i_hash // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type -#define i_eq // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a - // non-integral type. Three-way i_cmp may be specified instead. -#define i_keydrop // destroy key func: defaults to empty destruct -#define i_keyclone // clone func: REQUIRED IF i_keydrop defined - -#define i_keyraw // conversion "raw" type - defaults to i_key -#define i_keyfrom // conversion func i_keyraw => i_key - defaults to plain copy -#define i_keytoraw // conversion func i_key* => i_keyraw - defaults to plain copy - -#include -``` -- In the following, `X` is the value of `i_key` unless `T` is defined. -- **emplace**-functions are only available when `i_keyraw` is implicitly or explicitly defined. - -## Methods - -```c++ -hset_X hset_X_init(void); -hset_X hset_X_with_capacity(isize cap); - -hset_X hset_X_clone(hset_x set); -void hset_X_copy(hset_X* self, const hset_X* other); -void hset_X_take(hset_X* self, hset_X unowned); // take ownership of unowned -hset_X hset_X_move(hset_X* self); // move -void hset_X_drop(const hset_X* self); // destructor - -void hset_X_clear(hset_X* self); -float hset_X_max_load_factor(const hset_X* self); // default: 0.85 -bool hset_X_reserve(hset_X* self, isize size); -void hset_X_shrink_to_fit(hset_X* self); - -bool hset_X_is_empty(const hset_X* self); -isize hset_X_size(const hset_X* self); // num. of allocated buckets -isize hset_X_capacity(const hset_X* self); // buckets * max_load_factor -isize hset_X_bucket_count(const hset_X* self); - -bool hset_X_contains(const hset_X* self, i_keyraw rkey); -const X_value* hset_X_get(const hset_X* self, i_keyraw rkey); // return NULL if not found -X_value* hset_X_get_mut(hset_X* self, i_keyraw rkey); // mutable get -hset_X_iter hset_X_find(const hset_X* self, i_keyraw rkey); - -hset_X_result hset_X_insert(hset_X* self, i_key key); -hset_X_result hset_X_push(hset_X* self, i_key key); // alias for insert. -hset_X_result hset_X_emplace(hset_X* self, i_keyraw rkey); - -int hset_X_erase(hset_X* self, i_keyraw rkey); // return 0 or 1 -hset_X_iter hset_X_erase_at(hset_X* self, hset_X_iter it); // return iter after it -void hset_X_erase_entry(hset_X* self, hset_X_value* entry); - -hset_X_iter hset_X_begin(const hset_X* self); -hset_X_iter hset_X_end(const hset_X* self); -void hset_X_next(hset_X_iter* it); - -hset_X_value hset_X_value_clone(const hset_X* self, hset_X_value val); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:-------------------|:-------------------------------------------------|:----------------------------| -| `hset_X` | `struct { ... }` | The hset type | -| `hset_X_key` | `i_key` | The key type | -| `hset_X_value` | `i_key` | The key type (alias) | -| `hset_X_keyraw` | `i_keyraw` | The raw key type | -| `hset_X_raw` | `i_keyraw` | The raw key type (alias) | -| `hset_X_result` | `struct { hset_X_value* ref; bool inserted; }` | Result of insert/emplace | -| `hset_X_iter` | `struct { hset_X_value *ref; ... }` | Iterator type | - -## Example -[ [Run this code](https://godbolt.org/z/orjMvjznz) ] -```c++ -#include - -#define T Strings, cstr, (c_keypro) -#include - -int main(void) -{ - Strings first = c_make(Strings, {"red", "green", "blue"}); - Strings second={0}, third={0}, fourth={0}, fifth={0}; - - for (c_items(i, const char*, {"orange", "pink", "yellow"})) - Strings_emplace(&third, *i.ref); - - for (c_each(i, Strings, third)) - Strings_insert(&fifth, cstr_clone(*i.ref)); - - Strings_emplace(&fourth, "potatoes"); - Strings_emplace(&fourth, "milk"); - Strings_emplace(&fourth, "flour"); - - for (c_each(i, Strings, fourth)) - Strings_emplace(&fifth, cstr_str(i.ref)); - - printf("fifth contains:\n\n"); - for (c_each(i, Strings, fifth)) - printf("%s\n", cstr_str(i.ref)); - - c_drop(Strings, &first, &second, &third, &fourth, &fifth); -} -``` diff --git a/src/finchlite/codegen/stc/docs/list_api.md b/src/finchlite/codegen/stc/docs/list_api.md deleted file mode 100644 index 68ea064c..00000000 --- a/src/finchlite/codegen/stc/docs/list_api.md +++ /dev/null @@ -1,225 +0,0 @@ -# STC [list](../include/stc/list.h): Forward List -![List](pics/list.jpg) - -The **list** container supports fast insertion and removal of elements from anywhere in the container. -Fast random access is not supported. - -Unlike the c++ class *std::forward_list*, **list** has API similar to ***std::list***, and also supports -*push_back()* (**O**(1) time). It is still implemented as a singly-linked list. A **list** object -occupies only one pointer in memory, and like *std::forward_list* the length of the list is not stored. -All functions have **O**(1) complexity, apart from *list_X_count()* and *list_X_find()* which are **O**(*n*), -and *list_X_sort()* which is **O**(*n* log(*n*)). - -***Iterator invalidation***: Adding, removing and moving the elements within the list, or across several lists -will invalidate other iterators currently refering to these elements and their immediate succesive elements. -However, an iterator to a succesive element can both be dereferenced and advanced. After advancing, it is -in a fully valid state. This implies that if `list_X_insert(&L, list_X_advance(it,1), x)` and -`list_X_erase_at(&L, list_X_advance(it,1))` are used consistently, only iterators to erased elements are invalidated. - -See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list) for similar API and -[std::forward_list](https://en.cppreference.com/w/cpp/container/forward_list) for a functional description. - -## Header file and declaration - -```c++ -#define T ,[,] // shorthand for defining T, i_key, i_opt -#define T // list container type name (default: list_{i_key}) -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_use_cmp // may be defined instead of i_cmp when i_key is an integral/native-type. -#define i_cmp // three-way compare two i_keyraw* -#define i_less // less comparison. Alternative to i_cmp -#define i_eq // equality comparison. Implicitly defined with i_cmp, but not i_less. - -#define i_keyraw // conversion "raw" type (default: {i_key}) -#define i_cmpclass // conversion "raw class". binds _cmp(), _eq(), _hash() -#define i_keytoraw // conversion func i_key* => i_keyraw -#define i_keyfrom // conversion func i_keyraw => i_key -#include -``` -- Defining either `i_use_cmp`, `i_less` or `i_cmp` will enable sorting -- **emplace**-functions are only available when `i_keyraw` is implicitly or explicitly defined. -- In the following, `X` is the value of `i_key` unless `T` is defined. - -## Methods - -```c++ -list_X list_X_init(void); - -list_X list_X_clone(list_X list); -void list_X_copy(list_X* self, const list_X* other); -void list_X_take(list_X* self, list_X unowned); // take ownership of unowned -list_X list_X_move(list_X* self); // move -void list_X_drop(const list_X* self); // destructor - -void list_X_clear(list_X* self); - -bool list_X_is_empty(const list_X* list); -isize list_X_count(const list_X* list); // size() in O(n) time - -list_X_iter list_X_find(const list_X* self, i_keyraw raw); -list_X_iter list_X_find_in(list_X_iter it1, list_X_iter it2, i_keyraw raw); - -const i_key* list_X_back(const list_X* self); -const i_key* list_X_front(const list_X* self); - -i_key* list_X_back_mut(list_X* self); -i_key* list_X_front_mut(list_X* self); - -void list_X_push_back(list_X* self, i_key value); // note: no pop_back() -void list_X_push_front(list_X* self, i_key value); -void list_X_push(list_X* self, i_key value); // alias for push_back() - -void list_X_emplace_back(list_X* self, i_keyraw raw); -void list_X_emplace_front(list_X* self, i_keyraw raw); -void list_X_emplace(list_X* self, i_keyraw raw); // alias for emplace_back() - -list_X_iter list_X_insert_at(list_X* self, list_X_iter it, i_key value); // return iter to new elem -list_X_iter list_X_emplace_at(list_X* self, list_X_iter it, i_keyraw raw); - -void list_X_pop_front(list_X* self); -list_X_iter list_X_erase_at(list_X* self, list_X_iter it); // return iter after it -list_X_iter list_X_erase_range(list_X* self, list_X_iter it1, list_X_iter it2); -isize list_X_remove(list_X* self, i_keyraw raw); // removes all matches - -list_X list_X_split_off(list_X* self, list_X_iter i1, list_X_iter i2); // split off [i1, i2) -list_X_iter list_X_splice(list_X* self, list_X_iter it, list_X* other); // return updated valid it -list_X_iter list_X_splice_range(list_X* self, list_X_iter it, // return updated valid it - list_X* other, list_X_iter it1, li - st_X_iter it2); - -void list_X_reverse(list_X* self); -void list_X_sort(list_X* self); -void list_X_sort_with(list_X* self, int(*cmp)(const i_key*, const i_key*)); - -// Node API -list_X_node* list_X_get_node(i_key* val); // get the enclosing node -i_key* list_X_push_back_node(list_X* self, list_X_node* node); -i_key* list_X_insert_after_node(list_X* self, list_X_node* ref, list_X_node* node); -list_X_node* list_X_unlink_after_node(list_X* self, list_X_node* ref); // return unlinked node -list_X_node* list_X_unlink_front_node(list_X* self); // return unlinked node -void list_X_erase_after_node(list_X* self, list_X_node* node); - -list_X_iter list_X_begin(const list_X* self); -list_X_iter list_X_end(const list_X* self); -void list_X_next(list_X_iter* it); -list_X_iter list_X_advance(list_X_iter it, size_t n); // return n elements ahead. - -bool list_X_eq(const list_X* c1, const list_X* c2); // equality test -i_key list_X_value_clone(const list_X* self, i_key val); -list_X_raw list_X_value_toraw(const i_key* pval); -void list_X_value_drop(i_key* pval); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:-------------------|:----------------------------------------------------|:------------------------| -| `list_X` | `struct { list_X_node* last; }` | The list type | -| `list_X_node` | `struct { list_X_node* next; list_X_value value; }` | The list node type | -| `list_X_value` | `i_key` | The list element type | -| `list_X_raw` | `i_keyraw` | list raw value type | -| `list_X_iter` | `struct { list_value *ref; ... }` | list iterator | - -## Example - -Interleave *push_front()* / *push_back()* then *sort()*: - -[ [Run this code](https://godbolt.org/z/1aofesMGv) ] -```c++ -#define T DList, double, (c_use_cmp) -#include - -#include - -int main(void) { - DList list = c_make(DList, {10., 20., 30., 40., 50., 60., 70., 80., 90.}); - - for (c_range(i, 1, 10)) { - if (i & 1) DList_push_front(&list, (double) i); - else DList_push_back(&list, (double) i); - } - - printf("initial: "); - for (c_each(i, DList, list)) - printf(" %g", *i.ref); - - DList_sort(&list); // uses quicksort - - printf("\nsorted: "); - for (c_each(i, DList, list)) - printf(" %g", *i.ref); - - DList_drop(&list); -} -``` - -### Example 2 -Use of *erase_at()* and *erase_range()*: - -[ [Run this code](https://godbolt.org/z/era85saWv) ] -```c++ -#include -#define T IList, int -#include - -int main(void) -{ - IList L = c_make(IList, {10, 20, 30, 40, 50}); - // 10 20 30 40 50 - IList_iter it = IList_begin(&L); // ^ - IList_next(&it); - it = IList_erase_at(&L, it); // 10 30 40 50 - // ^ - IList_iter end = IList_end(&L); // - IList_next(&it); - it = IList_erase_range(&L, it, end); // 10 30 - // ^ - printf("mylist contains:"); - for (c_each(x, IList, L)) - printf(" %d", *x.ref); - puts(""); - - IList_drop(&L); -} -``` - -### Example 3 -Splice {**30**, **40**} from *L2* into *L1* before **3**: - -[ [Run this code](https://godbolt.org/z/854zGeKq6) ] -```c++ -#include -#define T IList, int -#include - -int main(void) { - IList L1 = c_make(IList, {1, 2, 3, 4, 5}); - IList L2 = c_make(IList, {10, 20, 30, 40, 50}); - - for (c_items(k, IList, {L1, L2})) { - for (c_each(i, IList, *k.ref)) - printf(" %d", *i.ref); - puts(""); - } - puts(""); - IList_iter i = IList_advance(IList_begin(&L1), 2); - IList_iter j1 = IList_advance(IList_begin(&L2), 2), j2 = IList_advance(j1, 2); - - IList_splice_range(&L1, i, &L2, j1, j2); - - for (c_items(k, IList, {L1, L2})) { - for (c_each(i, IList, *k.ref)) - printf(" %d", *i.ref); - puts(""); - } - - c_drop(IList, &L1, &L2); -} -``` diff --git a/src/finchlite/codegen/stc/docs/pics/Figure_1.png b/src/finchlite/codegen/stc/docs/pics/Figure_1.png deleted file mode 100644 index 46a1478f..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/Figure_1.png and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/array.jpg b/src/finchlite/codegen/stc/docs/pics/array.jpg deleted file mode 100644 index 4aede261..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/array.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/bitset.jpg b/src/finchlite/codegen/stc/docs/pics/bitset.jpg deleted file mode 100644 index 7445a6c2..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/bitset.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/containers.jpg b/src/finchlite/codegen/stc/docs/pics/containers.jpg deleted file mode 100644 index 2eddd82b..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/containers.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/coroutine.png b/src/finchlite/codegen/stc/docs/pics/coroutine.png deleted file mode 100644 index 1b8da87f..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/coroutine.png and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/deque.jpg b/src/finchlite/codegen/stc/docs/pics/deque.jpg deleted file mode 100644 index 5cdcd8ca..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/deque.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/list.jpg b/src/finchlite/codegen/stc/docs/pics/list.jpg deleted file mode 100644 index 6e642696..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/list.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/map.jpg b/src/finchlite/codegen/stc/docs/pics/map.jpg deleted file mode 100644 index 6de936d9..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/map.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/queue.jpg b/src/finchlite/codegen/stc/docs/pics/queue.jpg deleted file mode 100644 index 43477c9a..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/queue.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/random.jpg b/src/finchlite/codegen/stc/docs/pics/random.jpg deleted file mode 100644 index f40457fd..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/random.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/set.jpg b/src/finchlite/codegen/stc/docs/pics/set.jpg deleted file mode 100644 index dfad52dd..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/set.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/smap.jpg b/src/finchlite/codegen/stc/docs/pics/smap.jpg deleted file mode 100644 index 33b22845..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/smap.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/sset.jpg b/src/finchlite/codegen/stc/docs/pics/sset.jpg deleted file mode 100644 index dfad52dd..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/sset.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/stack.jpg b/src/finchlite/codegen/stc/docs/pics/stack.jpg deleted file mode 100644 index 365a2b3e..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/stack.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/string.jpg b/src/finchlite/codegen/stc/docs/pics/string.jpg deleted file mode 100644 index f37416b1..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/string.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pics/vector.jpg b/src/finchlite/codegen/stc/docs/pics/vector.jpg deleted file mode 100644 index 125e8504..00000000 Binary files a/src/finchlite/codegen/stc/docs/pics/vector.jpg and /dev/null differ diff --git a/src/finchlite/codegen/stc/docs/pqueue_api.md b/src/finchlite/codegen/stc/docs/pqueue_api.md deleted file mode 100644 index fc1366bc..00000000 --- a/src/finchlite/codegen/stc/docs/pqueue_api.md +++ /dev/null @@ -1,107 +0,0 @@ -# STC [pqueue](../include/stc/pqueue.h): Priority Queue - -A priority queue is a container adaptor that provides constant time lookup of the largest (by default) element, at the expense of logarithmic insertion and extraction. -A user-provided ***i_cmp*** may be defined to set the ordering, e.g. using ***-c_default_cmp*** would cause the smallest element to appear as the top() value. - -See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/container/priority_queue) for a functional reference. - -## Header file and declaration - -```c++ -#define T ,[,] // shorthand for defining T, i_key, i_opt -#define T // pqueue container type name (default: pqueue_{i_key}) -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -#define i_use_cmp // may be defined instead of i_cmp when i_key is an integral/native-type. -#define i_less // less comparison. REQUIRED for non-integral types. -#define i_cmp // three-way compare two i_keyraw*. Alternative to i_less. - -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // conversion type -#define i_cmpclass // conversion "raw class". binds _cmp(), _eq(), _hash() -#define i_keyfrom // conversion func i_keyraw => i_key -#define i_keytoraw // conversion func i_key* => i_keyraw. - -#include -``` -In the following, `X` is the value of `i_key` unless `T` is defined. - -## Methods - -```c++ -pqueue_X pqueue_X_init(void); // create empty pri-queue. -pqueue_X pqueue_X_with_capacity(isize cap); - -pqueue_X pqueue_X_clone(pqueue_X pq); -void pqueue_X_copy(pqueue_X* self, const pqueue_X* other); -void pqueue_X_take(pqueue_X* self, pqueue_X unowned); // take ownership of unowned -pqueue_X pqueue_X_move(pqueue_X* self); // move -void pqueue_X_drop(const pqueue_X* self); // destructor - -void pqueue_X_clear(pqueue_X* self); -bool pqueue_X_reserve(pqueue_X* self, isize n); -void pqueue_X_shrink_to_fit(pqueue_X* self); - -isize pqueue_X_size(const pqueue_X* self); -bool pqueue_X_is_empty(const pqueue_X* self); -const i_key* pqueue_X_top(const pqueue_X* self); - -void pqueue_X_make_heap(pqueue_X* self); // heapify the vector. -void pqueue_X_push(pqueue_X* self, i_key value); -void pqueue_X_emplace(pqueue_X* self, i_keyraw raw); // converts from raw - -void pqueue_X_pop(pqueue_X* self); -i_key pqueue_X_pull(const pqueue_X* self); -void pqueue_X_erase_at(pqueue_X* self, isize idx); - -i_key pqueue_X_value_clone(const pqueue_X* self, i_key value); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:------------------|:-------------------------------------|:------------------------| -| `pqueue_X` | `struct {pqueue_X_value* data; ...}` | The pqueue type | -| `pqueue_X_value` | `i_key` | The pqueue element type | - -## Example - -[ [Run this code](https://godbolt.org/z/bGb3n4sE8) ] -```c++ -#include -#include - -#define T PriorityQ, int -#define i_cmp -c_default_cmp // min-heap -#include - -int main(void) -{ - isize N = 10000000; - PriorityQ numbers = {0}; - - // Push ten million random numbers to priority queue. - for (c_range(N/2)) - PriorityQ_push(&numbers, (int)(crand32_uint() >> 6)); - - // Add some negative ones. - int nums[] = {-231, -32, -873, -4, -343}; - for (c_range(i, c_countof(nums))) - PriorityQ_push(&numbers, nums[i]); - - for (c_range(N/2)) - PriorityQ_push(&numbers, (int)(crand32_uint() >> 6)); - - // Extract and display the fifty smallest. - for (c_range(50)) { - printf("%d ", *PriorityQ_top(&numbers)); - PriorityQ_pop(&numbers); - } - PriorityQ_drop(&numbers); -} -``` diff --git a/src/finchlite/codegen/stc/docs/queue_api.md b/src/finchlite/codegen/stc/docs/queue_api.md deleted file mode 100644 index 76ffeda9..00000000 --- a/src/finchlite/codegen/stc/docs/queue_api.md +++ /dev/null @@ -1,107 +0,0 @@ -# STC [queue](../include/stc/queue.h): Queue -![Queue](pics/queue.jpg) - -The **queue** is container that gives the programmer the functionality of a queue - specifically, a FIFO (first-in, first-out) data structure. The queue pushes the elements on the back of the underlying container and pops them from the front. - -See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue) for a functional reference. - -## Header file and declaration -```c++ -#define T ,[,] // shorthand for defining T, i_key, i_opt -#define T // queue container type name (default: queue_{i_key}) -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // conversion "raw" type - defaults to i_key -#define i_cmpclass // conversion "raw class". binds _cmp(), _eq(), _hash() -#define i_keyfrom // conversion func i_keyraw => i_key -#define i_keytoraw // conversion func i_key* => i_keyraw - -#include -``` -In the following, `X` is the value of `i_key` unless `T` is defined. - - -## Methods - -```c++ -queue_X queue_X_init(void); -queue_X queue_X_with_capacity(isize cap); -queue_X queue_X_with_size(isize size, i_keyraw rawval); -queue_X queue_X_with_size_uninit(isize size); - -queue_X queue_X_clone(queue_X q); -void queue_X_copy(queue_X* self, const queue_X* other); -void queue_X_take(queue_X* self, queue_X unowned); // take ownership of unowned -queue_X queue_X_move(queue_X* self); // move -void queue_X_drop(const queue_X* self); // destructor - -void queue_X_clear(queue_X* self); -bool queue_X_reserve(queue_X* self, isize cap); -void queue_X_shrink_to_fit(queue_X* self); - -isize queue_X_size(const queue_X* self); -isize queue_X_capacity(const queue_X* self); -bool queue_X_is_empty(const queue_X* self); - -i_key* queue_X_front(const queue_X* self); -i_key* queue_X_back(const queue_X* self); - -i_key* queue_X_push(queue_X* self, i_key value); -i_key* queue_X_emplace(queue_X* self, i_keyraw raw); -void queue_X_pop(queue_X* self); -i_key queue_X_pull(queue_X* self); // move out last element - -queue_X_iter queue_X_begin(const queue_X* self); -queue_X_iter queue_X_end(const queue_X* self); -void queue_X_next(queue_X_iter* it); -queue_X_iter queue_X_advance(queue_X_iter it, isize n); - -bool queue_X_eq(const queue_X* c1, const queue_X* c2); // require i_eq/i_cmp/i_less. -i_key queue_X_value_clone(const queue_X* self, i_key value); -queue_X_raw queue_X_value_toraw(const i_key* pval); -void queue_X_value_drop(i_key* pval); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:-------------------|:--------------------|:------------------------| -| `queue_X` | `deque_X` | The queue type | -| `queue_X_value` | `i_key` | The queue element type | -| `queue_X_raw` | `i_keyraw` | queue raw value type | -| `queue_X_iter` | `deque_X_iter` | queue iterator | - -## Examples -```c++ -#define T queue, int -#include - -#include - -int main(void) { - queue Q = {0}; - - // push() and pop() a few. - for (c_range(i, 20)) - queue_push(&Q, i); - - for (c_range(5)) - queue_pop(&Q); - - for (c_each(i, queue, Q)) - printf(" %d", *i.ref); - - queue_drop(&Q); -} - -``` -Output: -``` -5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 -``` diff --git a/src/finchlite/codegen/stc/docs/random_api.md b/src/finchlite/codegen/stc/docs/random_api.md deleted file mode 100644 index 1f103a8a..00000000 --- a/src/finchlite/codegen/stc/docs/random_api.md +++ /dev/null @@ -1,135 +0,0 @@ -# STC [crand64 / crand32](../include/stc/random.h): Pseudo Random Number Generator -![Random](pics/random.jpg) - -A high quality, very fast 32- and 64-bit Pseudo Random Number Geneator (PRNG). It features -uniform and normal distributed random numbers and float/doubles conversions. - -
-A comparison of crand64 with xoshiro256** - -Several programming languages uses xoshiro256\*\* as the default PRNG. Let's compare. - -### A comparison of crand64 with [xoshiro256\*\*](https://prng.di.unimi.it/) -- **crand64** is based on **SFC64**, which along with **xoshiro256\*\*** both have excellent results -from currently available random test-suites. **SFC64** has a minimum period length of 2^64, whereas crand64 -uses a modified output function that incorporate a "stream" parameter value. -- **xoshiro256\*\*** has the full 2^256 period length, which is good. However, it also has some disadvantages: - - Trivially predictable and invertible: previous outputs along with all future ones can trivially be computed from four - output samples. - - Requires *jump-functions*, which the user must call in order to split up the output ranges before parallel execution. - - Overkill: Even to create "as few as" 2^64 random numbers in one thread at 1ns per number takes 584 years. - - The generator may end up in "zeroland" or "oneland" states (nearly all bits 0s or 1s for multiple outputs in a row), and will - generate low quality output. See [A Quick Look at Xoshiro256\*\*](https://www.pcg-random.org/posts/a-quick-look-at-xoshiro256.html). - - Output is not fed back into the state, instead every possible bit-state is iterated over by applying XOR and - SHIFT bit-operations only. As with Mersenne-Twister, the extreme period length has a cost: Because of the regulated - state changes, a relative expensive output function with two multiplications is needed to achieve high quality output. -- **crand64** can generate 2^63 unique streams in parallel, where each has 2^64 minimum period lengths. - - This is adequate even for large-scale experiments. - - Does not need jump-functions. Instead one can simply pass a unique odd number to each stream/thread as argument. - - Is 10-20% faster than **xoshiro256\*\***. Unlike **xoshiro**, it does not rely on fast hardware multiplication support. - - It has a 256 bits state. 192 bits are "chaotic" and 64 bits are used to ensure a long minimum period length. The output - function result is fed back into the state, resulting in the partially chaotic random state. It combines XOR, - SHIFT ***and*** ADD state modifying bit-operations, all to ensure excellent state randomness. -
- -## Header file -```c++ -#include -``` - -## Methods (64-bit) - -```c++ - // Use global state -void crand64_seed(uint64_t seed); // seed global rng64 state -uint64_t crand64_uint(void); // global crand64_uint_r(rng64, 1) -double crand64_real(void); // global crand64_real_r(rng64, 1) -crand64_uniform_dist - crand64_make_uniform(int64_t low, int64_t high); // create an unbiased uniform distribution -int64_t crand64_uniform(crand64_uniform_dist* d); // global crand64_uniform_r(rng64, 1, d) - // requires linking with stc lib. -double crand64_normal(crand64_normal_dist* d); // global crand64_normal_r(rng64, 1, d) -``` -```c++ - // Use local state -crand64 crand64_from(uint64_t seed); // create a crand64 state from a seed value -uint64_t crand64_uint_r(crand64* rng, uint64_t strm); // reentrant; return rnd in [0, UINT64_MAX] -double crand64_real_r(crand64* rng, uint64_t strm); // reentrant; return rnd in [0.0, 1.0) -int64_t crand64_uniform_r(crand64* rng, uint64_t strm, crand64_uniform_dist* d); // return rnd in [low, high] -double crand64_normal_r(crand64* rng, uint64_t strm, crand64_normal_dist* d); // return normal distributed rnd's -``` -```c++ - // Generic algorithms (uses 64 or 32 bit depending on word size): -void c_shuffle_seed(size_t seed); // calls crand64_seed() or crand32_seed() -void c_shuffle(TYPE CntType, CntType* cnt); // shuffle a cspan, vec, stack, queue or deque type. -void c_shuffle_array(T* array, isize n); // shuffle an array of elements. -``` -Note that `strm` must be an odd number. -## Types - -| Name | Type definition | Used to represent... | -|:-----------------------|:----------------------------------|:-----------------------------| -| `crand64` | `struct {uint64_t data[3];}` | The PRNG engine type | -| `crand64_uniform_dist` | `struct {...}` | Uniform int distribution struct | -| `crand64_normal_dist` | `struct {double mean, stddev;}` | Normal distribution struct | - -## Methods (32-bit) -```c++ -void crand32_seed(uint32_t seed); // seed global rng32 state -uint32_t crand32_uint(void); // global crand32_uint_r(rng32, 1) -float crand32_real(void); // global crand32_real_r(rng32, 1) -crand32_uniform_dist crand32_make_uniform(int32_t low, int32_t high); // create an unbiased uniform distribution -int32_t crand32_uniform(crand64_uniform_dist* d); // global crand32_uniform_r(rng32, 1, d) - -crand32 crand32_from(uint32_t seed); // create a crand32 state from a seed value -uint32_t crand32_uint_r(crand32* rng, uint32_t strm); // reentrant; return rnd in [0, UINT32_MAX] -float crand32_real_r(crand32* rng, uint32_t strm); // reentrant; return rnd in [0.0, 1.0) -int32_t crand32_uniform_r(crand32* rng, uint32_t strm, crand32_uniform_dist* d); // return rnd in [low, high] -``` - -| Name | Type definition | Used to represent... | -|:-----------------------|:----------------------------------|:-----------------------------| -| `crand32` | `struct {uint32_t data[3];}` | The PRNG engine type | -| `crand32_uniform_dist` | `struct {...}` | Uniform int distribution struct | - -## Example - -[ [Run this code](https://godbolt.org/z/d77x58Kna) ] -```c++ -#include -#include -#include -#include - -#define T SortedMap, int, long -#include - -int main(void) -{ - enum {N = 5000000}; - printf("Demo of gaussian / normal distribution of %d random samples\n", N); - - // Setup a reentrant random number engine with normal distribution. - crand64_seed((uint64_t)time(NULL)); - crand64_normal_dist dist = {.mean=-12.0, .stddev=4.0}; - - // Create histogram map - SortedMap mhist = {0}; - for (c_range(N)) { - int index = (int)round(crand64_normal(&dist)); - SortedMap_insert(&mhist, index, 0).ref->second += 1; - } - - // Print the gaussian bar chart - const double scale = 50; - for (c_each(i, SortedMap, mhist)) { - int n = (int)((double)i.ref->second * dist.stddev * scale * 2.5 / N); - if (n > 0) { - printf("%4d ", i.ref->first); - for (c_range(n)) printf("*"); - puts(""); - } - } - SortedMap_drop(&mhist); -} -``` diff --git a/src/finchlite/codegen/stc/docs/smap_api.md b/src/finchlite/codegen/stc/docs/smap_api.md deleted file mode 100644 index 189b48f4..00000000 --- a/src/finchlite/codegen/stc/docs/smap_api.md +++ /dev/null @@ -1,256 +0,0 @@ -# STC [smap](../include/stc/smap.h): Sorted Map -![Map](pics/smap.jpg) - -A **smap** is a sorted associative container that contains key-value pairs with unique keys. Keys are sorted by -using the comparison function *keyCompare*. Search, removal, and insertion operations have logarithmic complexity. -**smap** is implemented as an AA-tree (Arne Andersson, 1993), which tends to create a flatter structure -(slightly more balanced) than red-black trees. - -***Iterator invalidation***: Iterators are invalidated after insert and erase. References are only invalidated -after erase. It is possible to erase individual elements while iterating through the container by using the -returned iterator from *erase_at()*, which references the next element. Alternatively *erase_range()* can be used. - -See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) for a functional description. - -## Header file and declaration - -```c++ -#define T ,,[,] // shorthand for defining T, i_key, i_val -#define T // container type name (default: smap_{i_key}) -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -// One of the following: -#define i_val // mapped value type -#define i_valclass // mapped type, and bind _clone() and _drop() function names -#define i_valpro // mapped "pro" type, use for cstr, arc, box types - -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type -#define i_less // less comparison. Alternative to i_cmp -#define i_eq // equality comparison. Implicitly defined with i_cmp, but not i_less. - -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_valdrop defined -#define i_keyraw // conversion "raw" type - defaults to i_key -#define i_cmpclass // conversion "raw class". binds _cmp(), _eq(), _hash() -#define i_keyfrom // conversion func i_keyraw => i_key -#define i_keytoraw // conversion func i_key* => i_keyraw - -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined -#define i_valraw // conversion "raw" type - defaults to i_val -#define i_valfrom // conversion func i_valraw => i_val -#define i_valtoraw // conversion func i_val* => i_valraw - -#include -``` -- In the following, `X` is the value of `i_key` unless `T` is defined. -- **emplace**-functions are only available when `i_keyraw`/`i_valraw` are implicitly or explicitly defined. - -## Methods - -```c++ -smap_X smap_X_init(void); -sset_X smap_X_with_capacity(isize cap); - -smap_X smap_X_clone(smap_x map); -void smap_X_copy(smap_X* self, const smap_X* other); -void smap_X_take(smap_X* self, smap_X unowned); // take ownership of unowned -smap_X smap_X_move(smap_X* self); // move -void smap_X_drop(const smap_X* self); // destructor - -void smap_X_clear(smap_X* self); -bool smap_X_reserve(smap_X* self, isize cap); -void smap_X_shrink_to_fit(smap_X* self); - -bool smap_X_is_empty(const smap_X* self); -isize smap_X_size(const smap_X* self); -isize smap_X_capacity(const smap_X* self); - -const X_mapped* smap_X_at(const smap_X* self, i_keyraw rkey); // rkey must be in map -X_mapped* smap_X_at_mut(smap_X* self, i_keyraw rkey); // mutable at -const i_key* smap_X_get(const smap_X* self, i_keyraw rkey); // return NULL if not found -i_key* smap_X_get_mut(smap_X* self, i_keyraw rkey); // mutable get -bool smap_X_contains(const smap_X* self, i_keyraw rkey); -smap_X_iter smap_X_find(const smap_X* self, i_keyraw rkey); -i_key* smap_X_find_it(const smap_X* self, i_keyraw rkey, smap_X_iter* out); // return NULL if not found -smap_X_iter smap_X_lower_bound(const smap_X* self, i_keyraw rkey); // find closest entry >= rkey - -i_key* smap_X_front(const smap_X* self); -i_key* smap_X_back(const smap_X* self); - -smap_X_result smap_X_insert(smap_X* self, i_key key, i_val mapped); // no change if key in map -smap_X_result smap_X_insert_or_assign(smap_X* self, i_key key, i_val mapped); // always update mapped -smap_X_result smap_X_push(smap_X* self, i_key entry); // similar to insert() -smap_X_result smap_X_put(smap_X* self, i_keyraw rkey, i_valraw rmapped); // like emplace_or_assign() - -smap_X_result smap_X_emplace(smap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map -smap_X_result smap_X_emplace_or_assign(smap_X* self, i_keyraw rkey, i_valraw rmapped); // always update rmapped - -int smap_X_erase(smap_X* self, i_keyraw rkey); -smap_X_iter smap_X_erase_at(smap_X* self, smap_X_iter it); // returns iter after it -smap_X_iter smap_X_erase_range(smap_X* self, smap_X_iter it1, smap_X_iter it2); // returns updated it2 - -smap_X_iter smap_X_begin(const smap_X* self); -smap_X_iter smap_X_end(const smap_X* self); -void smap_X_next(smap_X_iter* iter); -smap_X_iter smap_X_advance(smap_X_iter it, isize n); - -i_key smap_X_value_clone(const smap_X* self, i_key val); -smap_X_raw smap_X_value_toraw(const i_key* pval); -void smap_X_value_drop(i_key* pval); -``` -## Types - -| Type name | Type definition | Used to represent... | -|:-------------------|:-------------------------------------------------|:-----------------------------| -| `smap_X` | `struct { ... }` | The smap type | -| `smap_X_key` | `i_key` | The key type | -| `smap_X_mapped` | `i_val` | The mapped type | -| `smap_X_value` | `struct { i_key first; i_val second; }` | The value: key is immutable | -| `smap_X_keyraw` | `i_keyraw` | The raw key type | -| `smap_X_rmapped` | `i_valraw` | The raw mapped type | -| `smap_X_raw` | `struct { i_keyraw first; i_valraw second; }` | i_keyraw+i_valraw type | -| `smap_X_result` | `struct { smap_X_value *ref; bool inserted; }` | Result of insert/put/emplace | -| `smap_X_iter` | `struct { smap_X_value *ref; ... }` | Iterator type | - -## Examples - -[ [Run this code](https://godbolt.org/z/q1EjeKx4b) ] -```c++ -#include - -#define i_keypro cstr // special macro for i_key = cstr -#define i_valpro cstr // ditto -#include - -int main(void) -{ - // Create a sorted map of three strings (maps to string) - smap_cstr colors = c_make(smap_cstr, { - {"RED", "#FF0000"}, - {"GREEN", "#00FF00"}, - {"BLUE", "#0000FF"} - }); - - // Iterate and print keys and values of sorted map - for (c_each(i, smap_cstr, colors)) { - printf("Key:[%s] Value:[%s]\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); - } - - // Add two new entries to the sorted map - smap_cstr_emplace(&colors, "BLACK", "#000000"); - smap_cstr_emplace(&colors, "WHITE", "#FFFFFF"); - - // Output values by key - printf("The HEX of color RED is:[%s]\n", cstr_str(smap_cstr_at(&colors, "RED"))); - printf("The HEX of color BLACK is:[%s]\n", cstr_str(smap_cstr_at(&colors, "BLACK"))); - - smap_cstr_drop(&colors); -} -``` - -### Example 2 -Translate a -[C++ example using *insert* and *emplace*](https://en.cppreference.com/w/cpp/container/map/try_emplace) - to STC: - -[ [Run this code](https://godbolt.org/z/anabce8ox) ] -```c++ -#include -#define T strmap, cstr, cstr, (c_keypro | c_valpro) -#include - -static void print_node(const strmap_value* node) { - printf("[%s] = %s\n", cstr_str(&node->first), cstr_str(&node->second)); -} - -static void print_result(strmap_result result) { - printf("%s", result.inserted ? "inserted: " : "ignored: "); - print_node(result.ref); -} - -int main(void) -{ - strmap m = {0}; - - print_result( strmap_emplace(&m, "a", "a") ); - print_result( strmap_emplace(&m, "b", "abcd") ); - print_result( strmap_insert(&m, cstr_lit("c"), cstr_with_size(10, 'c') ) ); - print_result( strmap_emplace(&m, "c", "Won't be inserted") ); - - for (c_each(p, strmap, m)) { print_node(p.ref); } - strmap_drop(&m); -} -``` - -### Example 3 -This example uses a smap with cstr as mapped value. Note the `i_valpro` usage. - -[ [Run this code](https://godbolt.org/z/PTW9h9b56) ] - -```c++ -#include - - -#define T IdMap, int, cstr, (c_valpro) -#include - -int main(void) -{ - uint32_t col = 0xcc7744ff; - IdMap idnames = c_make(IdMap, {{100, "Red"}, {110, "Blue"}}); - - // Assign/overwrite an existing mapped value with a const char* - IdMap_emplace_or_assign(&idnames, 110, "White"); - - // Insert (or assign) a new cstr - IdMap_insert_or_assign(&idnames, 120, cstr_from_fmt("#%08x", col)); - - // emplace() adds only when key does not already exist: - IdMap_emplace(&idnames, 100, "Green"); // ignored - - for (c_each(i, IdMap, idnames)) - printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second)); - - IdMap_drop(&idnames); -} -``` - - -### Example 4 -Demonstrate smap with plain-old-data key type Vec3i and int as mapped type: smap. - -[ [Run this code](https://godbolt.org/z/os54jhqrj) ] -```c++ -#include -typedef struct { int x, y, z; } Vec3i; - -static int Vec3i_cmp(const Vec3i* a, const Vec3i* b) { - int c; - if ((c = a->x - b->x) != 0) return c; - if ((c = a->y - b->y) != 0) return c; - return a->z - b->z; -} - -#define T smap_vi, Vec3i, int -#define i_cmp Vec3i_cmp -#include - -int main(void) -{ - smap_vi vmap = {0}; - - smap_vi_insert(&vmap, (Vec3i){100, 0, 0}, 1); - smap_vi_insert(&vmap, (Vec3i){0, 100, 0}, 2); - smap_vi_insert(&vmap, (Vec3i){0, 0, 100}, 3); - smap_vi_insert(&vmap, (Vec3i){100, 100, 100}, 4); - - for (c_each_kv(v, n, smap_vi, vmap)) - printf("{ %3d, %3d, %3d }: %d\n", v->x, v->y, v->z, *n); - - smap_vi_drop(&vmap); -} -``` diff --git a/src/finchlite/codegen/stc/docs/sset_api.md b/src/finchlite/codegen/stc/docs/sset_api.md deleted file mode 100644 index c661edb5..00000000 --- a/src/finchlite/codegen/stc/docs/sset_api.md +++ /dev/null @@ -1,138 +0,0 @@ -# STC [sset](../include/stc/sset.h): Sorted Set -![Set](pics/sset.jpg) - -A **sset** is an associative container that contains a sorted set of unique objects of type *i_key*. Sorting is done using the key comparison function *keyCompare*. Search, removal, and insertion operations have logarithmic complexity. **sset** is implemented as an AA-tree. - -See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) for a functional description. - -## Header file and declaration - -```c++ -#define T ,[,] // shorthand for defining T, i_key, i_opt -#define T // container type name (default: sset_{i_key}) -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type -#define i_less // less comparison. Alternative to i_cmp -#define i_eq // equality comparison. Implicitly defined with i_cmp, but not i_less. - -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // conversion "raw" type - defaults to i_key -#define i_cmpclass // conversion "raw class". binds _cmp(), _eq(), _hash() -#define i_keyfrom // conversion func i_keyraw => i_key - defaults to plain copy -#define i_keytoraw // conversion func i_key* => i_keyraw - defaults to plain copy - -#include -``` -- In the following, `X` is the value of `i_key` unless `T` is defined. -- **emplace**-functions are only available when `i_keyraw` is implicitly or explicitly defined. - -## Methods - -```c++ -sset_X sset_X_init(void); -sset_X sset_X_with_capacity(isize cap); - -sset_X sset_X_clone(sset_x set); -void sset_X_copy(sset_X* self, const sset_X* other); -void sset_X_take(sset_X* self, sset_X unowned); // take ownership of unowned -sset_X sset_X_move(sset_X* self); // move -void sset_X_drop(const sset_X* self); // destructor - -void sset_X_clear(sset_X* self); -bool sset_X_reserve(sset_X* self, isize cap); -void sset_X_shrink_to_fit(sset_X* self); - -bool sset_X_is_empty(const sset_X* self); -isize sset_X_size(const sset_X* self); -isize sset_X_capacity(const sset_X* self); - -const i_key* sset_X_get(const sset_X* self, i_keyraw rkey); // const get -i_key* sset_X_get_mut(sset_X* self, i_keyraw rkey); // return NULL if not found -bool sset_X_contains(const sset_X* self, i_keyraw rkey); -sset_X_iter sset_X_find(const sset_X* self, i_keyraw rkey); -i_key* sset_X_find_it(const sset_X* self, i_keyraw rkey, sset_X_iter* out); // return NULL if not found -sset_X_iter sset_X_lower_bound(const sset_X* self, i_keyraw rkey); // find closest entry >= rkey - -sset_X_result sset_X_insert(sset_X* self, i_key key); -sset_X_result sset_X_push(sset_X* self, i_key key); // alias for insert() -sset_X_result sset_X_emplace(sset_X* self, i_keyraw rkey); - -int sset_X_erase(sset_X* self, i_keyraw rkey); -sset_X_iter sset_X_erase_at(sset_X* self, sset_X_iter it); // return iter after it -sset_X_iter sset_X_erase_range(sset_X* self, sset_X_iter it1, sset_X_iter it2); // return updated it2 - -sset_X_iter sset_X_begin(const sset_X* self); -sset_X_iter sset_X_end(const sset_X* self); -void sset_X_next(sset_X_iter* it); - -i_key sset_X_value_clone(const sset_X* self, i_key val); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:------------------|:------------------------------------------------|:----------------------------| -| `sset_X` | `struct { ... }` | The sset type | -| `sset_X_key` | `i_key` | The key type | -| `sset_X_value` | `i_key` | The key type (alias) | -| `sset_X_keyraw` | `i_keyraw` | The raw key type | -| `sset_X_raw` | `i_keyraw` | The raw key type (alias) | -| `sset_X_result` | `struct { sset_X_value* ref; bool inserted; }` | Result of insert/emplace | -| `sset_X_iter` | `struct { sset_X_value *ref; ... }` | Iterator type | - -## Example -```c++ -#include - -#define T SSet, cstr, (c_keypro) -#include - -int main(void) -{ - SSet second = c_make(SSet, {"red", "green", "blue"}); - SSet third={0}, fourth={0}, fifth={0}; - - for (c_items(i, const char*, {"orange", "pink", "yellow"})) - SSet_emplace(&third, *i.ref); - - SSet_emplace(&fourth, "potatoes"); - SSet_emplace(&fourth, "milk"); - SSet_emplace(&fourth, "flour"); - - // Copy all to fifth: - - fifth = SSet_clone(second); - - for (c_each(i, SSet, third)) - SSet_emplace(&fifth, cstr_str(i.ref)); - - for (c_each(i, SSet, fourth)) - SSet_emplace(&fifth, cstr_str(i.ref)); - - printf("fifth contains:\n\n"); - for (c_each(i, SSet, fifth)) - printf("%s\n", cstr_str(i.ref)); - - c_drop(SSet, &second, &third, &fourth, &fifth); -} -``` -Output: -``` -fifth contains: - -blue -flour -green -milk -orange -pink -potatoes -red -yellow -``` diff --git a/src/finchlite/codegen/stc/docs/stack_api.md b/src/finchlite/codegen/stc/docs/stack_api.md deleted file mode 100644 index 0e0b11b3..00000000 --- a/src/finchlite/codegen/stc/docs/stack_api.md +++ /dev/null @@ -1,130 +0,0 @@ -# STC [stack](../include/stc/stack.h): Stack -![Stack](pics/stack.jpg) - -The **stack** is a container that gives the programmer the functionality of a stack - specifically, -a LIFO (last-in, first-out) data structure. The stack pushes and pops the element from the back of -the container, known as the top of the stack. A stack may be defined ***inplace***, i.e. with a -fixed size on the stack by specifying `i_capacity CAP`. - -See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack) for a functional description. - -## Header file and declaration - -```c++ -#define T , [,] // define both T and i_key types -#define T // container type name (default: stack_{i_key}) -#define i_capacity // define an inplace stack (on the stack) with CAP capacity. -// One of the following: -#define i_key // key type -#define i_capacity // define an inplace stack (on the stack) with CAP capacity. -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // "pro" key type, use for `cstr`, `arc`, and `box` types. - // Defines i_keyclass = , i_cmpclass = _raw - -// Use alone or combined with i_keyclass: -#define i_cmpclass // comparison "class". , aka `raw` defaults to - // binds _cmp(), _eq(), _hash() member functions. -#define i_opt // enable optional properties, see ... - -// Override or define when not "class" or "pro" is used: -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_cmp // three-way compare two i_keyraw* -#define i_less // less comparison. Alternative to i_cmp -#define i_eq // equality comparison. Implicitly defined with i_cmp, but not i_less. - -#include -``` -- Defining either `i_use_cmp`, `i_less` or `i_cmp` will enable sorting, binary_search and lower_bound -- **emplace**-functions are only available when `i_keyraw` is implicitly or explicitly defined. -- In the following, `X` is the value of `i_key` unless `T` is defined. - -## Methods - -```c++ -stack_X stack_X_init(void); -stack_X stack_X_with_capacity(isize cap); -stack_X stack_X_with_size(isize size, i_keyraw rawval); -stack_X stack_X_with_size_uninit(isize size); - -stack_X stack_X_clone(stack_X st); -void stack_X_copy(stack_X* self, const stack_X* other); -stack_X stack_X_move(stack_X* self); // move -void stack_X_take(stack_X* self, stack_X unowned); // take ownership of unowned -void stack_X_drop(const stack_X* self); // destructor - -void stack_X_clear(stack_X* self); -bool stack_X_reserve(stack_X* self, isize n); -void stack_X_shrink_to_fit(stack_X* self); - -isize stack_X_size(const stack_X* self); -isize stack_X_capacity(const stack_X* self); -bool stack_X_is_empty(const stack_X* self); - -const i_key* stack_X_at(const stack_X* self, isize idx); -const i_key* stack_X_top(const stack_X* self); -const i_key* stack_X_front(const stack_X* self); -const i_key* stack_X_back(const stack_X* self); - -i_key* stack_X_at_mut(stack_X* self, isize idx); -i_key* stack_X_top_mut(stack_X* self); -i_key* stack_X_front_mut(stack_X* self); -i_key* stack_X_back_mut(stack_X* self); - -i_key* stack_X_push(stack_X* self, i_key value); -i_key* stack_X_emplace(stack_X* self, i_keyraw raw); -i_key* stack_X_append_uninit(stack_X* self, isize n); - -void stack_X_pop(stack_X* self); // destroy last element -i_key stack_X_pull(stack_X* self); // move out last element - -// Requires either i_use_cmp, i_cmp or i_less defined: -void stack_X_sort(stack_X* self); // quicksort from sort.h -isize stack_X_lower_bound(const stack_X* self, const i_keyraw raw); // return c_NPOS if not found -isize stack_X_binary_search(const stack_X* self, const i_keyraw raw); // return c_NPOS if not found - -stack_X_iter stack_X_begin(const stack_X* self); -stack_X_iter stack_X_end(const stack_X* self); -void stack_X_next(stack_X_iter* it); - -bool stack_X_eq(const stack_X* c1, const stack_X* c2); // require i_eq/i_cmp/i_less. -i_key stack_X_value_clone(const stack_X* self, i_key value); -i_keyraw stack_X_value_toraw(const vec_X_value* pval); -void stack_X_value_drop(vec_X_value* pval); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:-------------------|:------------------------------------|:----------------------------| -| `stack_X` | `struct { stack_value *data; ... }` | The stack type | -| `stack_X_value` | `i_key` | The stack element type | -| `stack_X_raw` | `i_keyraw` | stack raw value type | -| `stack_X_iter` | `struct { stack_value *ref; }` | stack iterator | - -## Example -```c++ -#define T IStack, int -#include - -#include - -int main(void) { - IStack stk = {0}; - - for (int i=0; i < 100; ++i) - IStack_push(&stk, i*i); - - for (int i=0; i < 90; ++i) - IStack_pop(&stk); - - printf("top: %d\n", *IStack_top(&stk)); - - IStack_drop(&stk); -} -``` -Output: -``` -top: 81 -``` diff --git a/src/finchlite/codegen/stc/docs/utf8_api.md b/src/finchlite/codegen/stc/docs/utf8_api.md deleted file mode 100644 index 54f9711b..00000000 --- a/src/finchlite/codegen/stc/docs/utf8_api.md +++ /dev/null @@ -1,71 +0,0 @@ -# STC [UTF8](../include/stc/utf8.h): string functionality -![String](pics/string.jpg) - -This contains low-level utf8 functions which are used by [cstr](cstr_api.md) (string), [csview](csview_api.md) (string-view), and [zsview](zsview_api.md) (zero-terminated string-view). A utf8 codepoint is often -referred to as a ***rune***, and can be 1 to 4 bytes long. - -## Header file - -This header file is rarely needed alone. It is included by all the string/view types mentioned above. - -```c++ -#include -``` -## Methods -```c++ -isize utf8_count(const char *s); // number of utf8 runes in s -isize utf8_count_n(const char *s, isize nbytes); // number of utf8 runes within n bytes -isize utf8_to_index(const char* s, isize u8pos); // from utf8 pos to byte index -int utf8_chr_size(const char* s); // utf8 character size: 1-4 -const char* utf8_at(const char *s, isize u8pos); // return the char* at u8pos -csview utf8_subview(const char* s, isize u8pos, isize u8len); // return a csview as the span - -bool utf8_valid(const char* s); -bool utf8_valid_n(const char* s, isize nbytes); -uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, returns state. -int utf8_encode(char *out, uint32_t codepoint); // encode unicode cp to out. returns nbytes. -uint32_t utf8_peek(const char* s); // codepoint value at character pos s -uint32_t utf8_peek_at(const char* s, isize u8offset); // codepoint at utf8 offset (may be negative) -int utf8_icmp(const char* s1, const char* s2); // case-insensitive char* comparison -int utf8_icompare(csview s1, csview s2); // case-insensitive csview comparison - -uint32_t utf8_casefold(uint32_t c); // fold to a non-unique lowercase char. -uint32_t utf8_tolower(uint32_t c); -uint32_t utf8_toupper(uint32_t c); - -bool utf8_isalpha(uint32_t c); -bool utf8_isalnum(uint32_t c); -bool utf8_isword(uint32_t c); -bool utf8_iscased(uint32_t c); -bool utf8_isblank(uint32_t c); -bool utf8_isspace(uint32_t c); -bool utf8_isupper(uint32_t c); -bool utf8_islower(uint32_t c); -bool utf8_isgroup(int group, uint32_t c); -``` - -## Example: UTF8 iteration and case conversion -```c++ -#include -#include - -int main(void) -{ - zsview say = c_zv("Liberté, égalité, fraternité."); - printf("%s\n", zs.str); - - for (c_each(i, zsview, say)) - printf(c_svfmt " ", c_svarg(i.chr)); - puts(""); - - cstr upper = cstr_toupper_sv(zsview_sv(say)); - printf("%s\n", cstr_str(&upper)); - cstr_drop(&upper); -} -``` -Output: -``` -Liberté, égalité, fraternité. -L i b e r t é , é g a l i t é , f r a t e r n i t é . -LIBERTÉ, ÉGALITÉ, FRATERNITÉ. -``` diff --git a/src/finchlite/codegen/stc/docs/vec_api.md b/src/finchlite/codegen/stc/docs/vec_api.md deleted file mode 100644 index 9cdefb30..00000000 --- a/src/finchlite/codegen/stc/docs/vec_api.md +++ /dev/null @@ -1,239 +0,0 @@ -# STC [vec](../include/stc/vec.h): Vector -![Vector](pics/vector.jpg) - -A **vec** is a sequence container that encapsulates dynamic size arrays. - -The storage of the vector is handled automatically, being expanded and contracted as needed. Vectors usually occupy more space than static arrays, because more memory is allocated to handle future growth. This way a vector does not need to reallocate each time an element is inserted, but only when the additional memory is exhausted. The total amount of allocated memory can be queried using *vec_X_capacity()* function. Extra memory can be returned to the system via a call to *vec_X_shrink_to_fit()*. - -Reallocations are usually costly operations in terms of performance. The *vec_X_reserve()* function can be used to eliminate reallocations if the number of elements is known beforehand. - -See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vector) for a functional description. - -## Header file and declaration - -```c++ -#define T ,[,] // shorthand for defining T, i_key, i_opt -#define T // container type name (default: vec_{i_key}) -// One of the following: -#define i_key // key type -#define i_keyclass // key type, and bind _clone() and _drop() function names -#define i_keypro // key "pro" type, use for cstr, arc, box types - -// Use alone or combined with i_keyclass: -#define i_cmpclass // Comparison "class". , aka `raw` defaults to - // Bind _cmp(), _eq(), _hash() member functions. - -// Override or define when not "class" or "pro" is used: -#define i_keydrop // Destroy element func - defaults to empty destruct -#define i_keyclone // Clone element func (required when i_keydrop is defined) - -#define i_cmp // Three-way compare two i_keyraw* -#define i_less // Less comparison. Alternative to i_cmp -#define i_eq // Equality comparison. Implicitly defined with i_cmp, but not i_less. - -#include -``` -- Defining either `i_use_cmp`, `i_less` or `i_cmp` will enable sorting, binary_search and lower_bound -- **emplace**-functions are only available when `i_keyraw` is implicitly or explicitly defined. -- In the following, `X` is the value of `i_key` unless `T` is defined. - -## Methods - -```c++ -vec_X vec_X_init(void); -vec_X vec_X_with_capacity(isize size); -vec_X vec_X_with_size(isize size, i_keyraw rawval); -vec_X vec_X_with_size_uninit(isize size); - -vec_X vec_X_clone(vec_X vec); -void vec_X_copy(vec_X* self, const vec_X* other); -vec_X_iter vec_X_copy_to(vec_X* self, isize idx, const i_key* arr, isize n); -vec_X vec_X_move(vec_X* self); // move -void vec_X_take(vec_X* self, vec_X unowned); // take ownership of unowned -void vec_X_drop(const vec_X* self); // destructor - -void vec_X_clear(vec_X* self); -bool vec_X_reserve(vec_X* self, isize cap); -bool vec_X_resize(vec_X* self, isize size, i_key null); -void vec_X_shrink_to_fit(vec_X* self); - -bool vec_X_is_empty(const vec_X* self); -isize vec_X_size(const vec_X* self); -isize vec_X_capacity(const vec_X* self); - -vec_X_iter vec_X_find(const vec_X* self, i_keyraw raw); -vec_X_iter vec_X_find_in(vec_X_iter i1, vec_X_iter i2, i_keyraw raw); // return vec_X_end() if not found - -const i_key* vec_X_at(const vec_X* self, isize idx); -const i_key* vec_X_front(const vec_X* self); -const i_key* vec_X_back(const vec_X* self); - -i_key* vec_X_at_mut(vec_X* self, isize idx); // return mutable at idx -i_key* vec_X_front_mut(vec_X* self); -i_key* vec_X_back_mut(vec_X* self); - - // Requires either i_use_cmp, i_cmp or i_less defined: -void vec_X_sort(vec_X* self); // quicksort from sort.h -isize vec_X_lower_bound(const vec_X* self, const i_keyraw raw); // return c_NPOS if not found -isize vec_X_binary_search(const vec_X* self, const i_keyraw raw); // return c_NPOS if not found - -i_key* vec_X_push(vec_X* self, i_key value); -i_key* vec_X_push_back(vec_X* self, i_key value); // alias for push -i_key* vec_X_emplace(vec_X* self, i_keyraw raw); -i_key* vec_X_emplace_back(vec_X* self, i_keyraw raw); // alias for emplace - -void vec_X_pop(vec_X* self); // destroy last element -void vec_X_pop_back(vec_X* self); // alias for pop -i_key vec_X_pull(vec_X* self); // move out last element - -vec_X_iter vec_X_insert_n(vec_X* self, isize idx, const i_key arr[], isize n); // move values -vec_X_iter vec_X_insert_at(vec_X* self, vec_X_iter it, i_key value); // move value -vec_X_iter vec_X_insert_uninit(vec_X* self, isize idx, isize n); // return iter at idx - -vec_X_iter vec_X_emplace_n(vec_X* self, isize idx, const i_keyraw raw[], isize n); -vec_X_iter vec_X_emplace_at(vec_X* self, vec_X_iter it, i_keyraw raw); - -vec_X_iter vec_X_erase_n(vec_X* self, isize idx, isize n); -vec_X_iter vec_X_erase_at(vec_X* self, vec_X_iter it); -vec_X_iter vec_X_erase_range(vec_X* self, vec_X_iter it1, vec_X_iter it2); - - -vec_X_iter vec_X_begin(const vec_X* self); -vec_X_iter vec_X_end(const vec_X* self); -void vec_X_next(vec_X_iter* iter); -vec_X_iter vec_X_advance(vec_X_iter it, size_t n); - -bool vec_X_eq(const vec_X* c1, const vec_X* c2); // equality comp. -vec_X_value vec_X_value_clone(const vec_X* self, vec_X_value val); -vec_X_raw vec_X_value_toraw(const vec_X_value* pval); -vec_X_raw vec_X_value_drop(vec_X_value* pval); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:------------------|:---------------------------------|:----------------------| -| `vec_X` | `struct { vec_X_value* data; }` | The vec type | -| `vec_X_value` | `i_key` | The vec value type | -| `vec_X_raw` | `i_keyraw` | The raw value type | -| `vec_X_iter` | `struct { vec_X_value* ref; }` | The iterator type | - -## Examples - -[ [Run this code](https://godbolt.org/z/P84zMWro8) ] -```c++ -#include - -// enable sorting/searching using default <, == operators -#define T vec_int, int, (c_use_cmp) -#include - -int main(void) -{ - // Create a vector containing integers - vec_int vec = {0}; - - // Add two integers to vector - vec_int_push(&vec, 25); - vec_int_push(&vec, 13); - - // Append a set of numbers - for (c_items(i, int, {7, 5, 16, 8})) - vec_int_push(&vec, *i.ref); - - printf("initial:"); - for (c_each(k, vec_int, vec)) { - printf(" %d", *k.ref); - } - - // Sort the vector - vec_int_sort(&vec); - - printf("\nsorted:"); - for (c_each(k, vec_int, vec)) { - printf(" %d", *k.ref); - } - vec_int_drop(&vec); -} -``` -### Example 2 - -[ [Run this code](https://godbolt.org/z/c7e3q5v14) ] -```c++ -#include -#include - -#define i_keypro cstr -#include - -int main(void) { - vec_cstr names = {0}; - - vec_cstr_emplace(&names, "Mary"); - vec_cstr_emplace(&names, "Joe"); - cstr_assign(&names.data[1], "Jake"); // replace "Joe". - - cstr tmp = cstr_from_fmt("%d elements so far", vec_cstr_size(&names)); - - // vec_cstr_emplace() only accept const char*, so use push(): - vec_cstr_push(&names, tmp); // tmp is "moved" to names (must not be dropped). - - printf("%s\n", cstr_str(&names.data[1])); // Access second element - - for (c_each(i, vec_cstr, names)) - printf("item: %s\n", cstr_str(i.ref)); - - vec_cstr_drop(&names); -} -``` -### Example 3 -Container with elements of structs: - -[ [Run this code](https://godbolt.org/z/bWEb5vc4K) ] -```c++ -#include -#include - -typedef struct { - cstr name; // dynamic string - int id; -} User; - -int User_cmp(const User* a, const User* b) { - int c = strcmp(cstr_str(&a->name), cstr_str(&b->name)); - return c ? c : a->id - b->id; -} - -User User_clone(User user) { - user.name = cstr_clone(user.name); - return user; -} - -void User_drop(User* self) { - cstr_drop(&self->name); -} - -// Declare a managed, clonable vector of users. -// c_keyclass: User is a "class" and binds the _clone(), _drop(), and _cmp() functions. -// c_use_cmp: Sorting/searching a vec is only enabled by either directly specifying an -// i_cmp function or by specifying c_use_cmp. In this case i_cmp is indirectly -// bound to User_cmp because c_keyclass was specified, otherwise it is assumed that -// i_key is a built-in type that works with < and == operators). -#define T Users, User, (c_keyclass | c_use_cmp) -#include - -int main(void) { - Users users = {0}; - Users_push(&users, (User){cstr_lit("mary"), 0}); - Users_push(&users, (User){cstr_lit("joe"), 1}); - Users_push(&users, (User){cstr_lit("admin"), 2}); - - Users users2 = Users_clone(users); - Users_sort(&users2); - - for (c_each(i, Users, users2)) - printf("%s: %d\n", cstr_str(&i.ref->name), i.ref->id); - - c_drop(Users, &users, &users2); // cleanup -} -``` diff --git a/src/finchlite/codegen/stc/docs/zsview_api.md b/src/finchlite/codegen/stc/docs/zsview_api.md deleted file mode 100644 index c509b6e1..00000000 --- a/src/finchlite/codegen/stc/docs/zsview_api.md +++ /dev/null @@ -1,103 +0,0 @@ -# STC [zsview](../include/stc/zsview.h): Zero-terminated UTF8 String View -![String](pics/string.jpg) - -The type **zsview** is a ***zero-terminated*** and ***utf8-iterable*** string view. It refers to a -constant contiguous sequence of char-elements with the first element of the sequence at position zero. -The implementation holds two members: a pointer to constant char and a size. See [csview](csview_api.md) -for a ***non zero-terminated*** string view/span type. - -Because **zsview** is zero-terminated, it can be an efficient replacent for `const char*`. E.g., the .str -char* pointer can safely be passed to c-api's which expects standard zero terminated c-strings. It never -allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string -storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations. - -## Header file - -All zsview definitions and prototypes are available by including a single header file. - -```c++ -#include -``` - -## Methods -```c++ -zsview c_zv(const char literal_only[]); // create from string literal only -zsview zsview_from(const char* str); // construct from const char* -zsview zsview_from_pos(zsview zv, isize pos); // subview starting from index pos - -isize zsview_size(zsview zv); -bool zsview_is_empty(zsview zv); // check if size == 0 -void zsview_clear(zsview* self); - -csview zsview_sv(zsview zv); // convert to csview type -csview zsview_subview(zsview zv, isize pos, isize len); // return as csview span -zsview zsview_tail(zsview zv, isize len); // subview of the trailing n bytes - -bool zsview_equals(zsview zv, const char* str); -isize zsview_find(zsview zv, const char* str); -bool zsview_contains(zsview zv, const char* str); -bool zsview_starts_with(zsview zv, const char* str); -bool zsview_ends_with(zsview zv, const char* str); -``` - -#### UTF8 methods -```c++ -zsview zsview_u8_from_pos(zsview zv, isize u8pos); // subview starting from rune u8pos -isize zsview_u8_size(zsview zv); // number of utf8 runes -zsview_iter zsview_u8_at(zsview zv, isize u8pos); // get rune at rune position -csview zsview_u8_subview(zsview zs, isize u8pos, isize u8len); -zsview zsview_u8_tail(zsview zv, isize u8len); // subview of the last u8len runes -bool zsview_u8_valid(zsview zv); // check utf8 validity of zv - -bool zsview_iequals(zsview zs, const char* str); // utf8 case-insensitive comparison -bool zsview_istarts_with(zsview zs, const char* str); // utf8 case-insensitive -bool zsview_iends_with(zsview zs, const char* str); // utf8 case-insensitive - -zsview_iter zsview_begin(const zsview* self); // utf8 iteration -zsview_iter zsview_end(const zsview* self); -void zsview_next(zsview_iter* it); // next rune -zsview_iter zsview_advance(zsview_iter it, isize u8pos); // advance +/- runes -``` - -#### Helper methods for usage in containers -```c++ -size_t zsview_hash(const zsview* x); -int zsview_cmp(const zsview* x, const zsview* y); -bool zsview_eq(const zsview* x, const zsview* y); -int zsview_icmp(const zsview* s1, const zsview* s2); // utf8 case-insensitive comparison -bool zsview_ieq(const zsview* s1, const zsview* s2); // " -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:---------------|:---------------------------------------------|:-------------------------| -| `zsview` | `struct { const char *str; isize size; }` | The string view type | -| `zsview_value` | `const char` | The element type | -| `zsview_iter` | `union { zsview_value *ref; csview chr; }` | UTF8 iterator | - -## Example: UTF8 iteration and case conversion -```c++ -#include -#include - -int main(void) -{ - zsview say = c_zv("Liberté, égalité, fraternité."); - printf("%s\n", zs.str); - - for (c_each(i, zsview, say)) - printf(c_svfmt " ", c_svarg(i.chr)); - puts(""); - - cstr upper = cstr_toupper_sv(zsview_sv(say)); - printf("%s\n", cstr_str(&upper)); - cstr_drop(&upper); -} -``` -Output: -``` -Liberté, égalité, fraternité. -L i b e r t é , é g a l i t é , f r a t e r n i t é . -LIBERTÉ, ÉGALITÉ, FRATERNITÉ. -``` diff --git a/src/finchlite/codegen/stc/examples/README.md b/src/finchlite/codegen/stc/examples/README.md deleted file mode 100644 index 4c0aa763..00000000 --- a/src/finchlite/codegen/stc/examples/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Examples -======== -This folder contains various examples of STC container usage. - diff --git a/src/finchlite/codegen/stc/examples/algorithms/event.c b/src/finchlite/codegen/stc/examples/algorithms/event.c deleted file mode 100644 index c8e53a65..00000000 --- a/src/finchlite/codegen/stc/examples/algorithms/event.c +++ /dev/null @@ -1,30 +0,0 @@ -// https://www.janekbieser.dev/posts/exploring-tagged-unions/ -// https://godbolt.org/z/Pd815sxfb // compare Rust - STC -#include -#include - -c_union (Event, - (Event_KeyPress, int), - (Event_MouseClick, struct {int x, y;}), - (Event_MouseMove, struct {int x, y;}), -); - -int process_event(Event evt) { - c_when (&evt) { - c_is(Event_KeyPress, key_code) return *key_code * 1234; - c_is(Event_MouseClick, pos) return pos->x + pos->y * 457; - c_is(Event_MouseMove, delta) return delta->x + delta->y * 987; - } - return 0; -} - -int main(void) { - for (c_items(evt, Event, { - c_variant(Event_KeyPress, 100), - c_variant(Event_MouseClick, {10, 20}), - c_variant(Event_MouseMove, {3, 1}), - })){ - int result = process_event(*evt.ref); - printf("Event Result: %d\n", result); - } -} diff --git a/src/finchlite/codegen/stc/examples/algorithms/filterdemos.c b/src/finchlite/codegen/stc/examples/algorithms/filterdemos.c deleted file mode 100644 index d06a63f0..00000000 --- a/src/finchlite/codegen/stc/examples/algorithms/filterdemos.c +++ /dev/null @@ -1,126 +0,0 @@ -#include -#include -#include -#include -#include - -#define T IVec, int -#include - -// filters and transforms: -#define f_skipValue(x) (*value != (x)) -#define f_isEven() ((*value & 1) == 0) -#define f_square() (*value * *value) - -void demo1(void) -{ - IVec vec = c_make(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80, - 10, 11, 12, 13, 14, 15, 80, 16, 17}); - - c_filter(IVec, vec, f_skipValue(80) && printf(" %d", (int) *value)); - puts(""); - - int sum = 0; - c_filter(IVec, vec, true - && c_flt_skipwhile(*value != 80) - && c_flt_skip(1) - && f_isEven() - && f_skipValue(80) - && (sum += f_square(), c_flt_take(5)) - ); - printf("\n sum: %d\n", sum); - IVec_drop(&vec); -} - - -/* Rust: -fn main() { - let vector = (1..) // Infinite range of integers - .skip_while(|x| *x != 11) // Skip initial numbers unequal 11 - .filter(|x| x % 2 != 0) // Collect odd numbers - .take(5) // Only take five numbers - .map(|x| x * x) // Square each number - .collect::>(); // Return as a new Vec - println!("{:?}", vector); // Print result -} -*/ -void demo2(void) -{ - IVec vector = {0}; - c_filter(crange, c_iota(0), true // Infinite range of integers - && c_flt_skipwhile(*value != 11) // Skip initial numbers unequal 11 - && (*value % 2) != 0 // Collect odd numbers - && (c_flt_map(*value * *value), // Square each number - IVec_push(&vector, (int)*value), // Populate output IVec - c_flt_take(5)) // Only take five numbers - ); - for (c_each(i, IVec, vector)) - printf(" %d", *i.ref); // Print result - puts(""); - IVec_drop(&vector); -} - -/* Rust: -fn main() { - let sentence = "This is a sentence in Rust."; - let words: Vec<&str> = sentence - .split_whitespace() - .collect(); - let words_containing_i: Vec<&str> = words - .into_iter() - .filter(|word| word.contains("i")) - .collect(); - println!("{:?}", words_containing_i); -} -*/ -// Bind and enable csview comparison functions for vec. -#define T SVec, csview, (c_cmpclass | c_use_cmp) -#include - -void demo3(void) -{ - const char* sentence = "This is a sentence in C99."; - SVec words = {0}; - for (c_token(i, " ", sentence)) // split words - SVec_push(&words, i.token); - - SVec words_containing_i = {0}; - c_filter(SVec, words, true - && csview_contains(*value, "i") - && SVec_push(&words_containing_i, *value) - ); - for (c_each(w, SVec, words_containing_i)) - printf(" " c_svfmt, c_svarg(*w.ref)); - puts(""); - - - SVec_iter it = SVec_find(&words, c_sv("sentence")); - if (it.ref) printf("found: " c_svfmt "\n", c_svarg(*it.ref)); - - c_drop(SVec, &words, &words_containing_i); -} - -void demo4(void) -{ - // Keep only uppercase letters and convert them to lowercase: - csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte - cstr out = {0}; - char chr[4]; - - c_filter(csview, s, true - && utf8_isupper(utf8_peek(value)) - && (utf8_encode(chr, utf8_tolower(utf8_peek(value))), - cstr_push(&out, chr)) - ); - printf(" %s\n", cstr_str(&out)); - cstr_drop(&out); -} - - -int main(void) -{ - puts("demo1"); demo1(); - puts("demo2"); demo2(); - puts("demo3"); demo3(); - puts("demo4"); demo4(); -} diff --git a/src/finchlite/codegen/stc/examples/algorithms/forloops.c b/src/finchlite/codegen/stc/examples/algorithms/forloops.c deleted file mode 100644 index 1be7123d..00000000 --- a/src/finchlite/codegen/stc/examples/algorithms/forloops.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include - -#define T IVec, int -#include - -#define T IMap, int, int -#include - - -int main(void) -{ - puts("for c_range:"); - for (c_range(30)) printf(" xx"); - puts(""); - - for (c_range(i, 30)) printf(" %d", (int)i); - puts(""); - - for (c_range(i, 30, 60)) printf(" %d", (int)i); - puts(""); - - for (c_range(i, 30, 90, 2)) printf(" %d", (int)i); - - puts("\n\nfor c_items:"); - for (c_items(i, int, {12, 23, 453, 65, 676})) - printf(" %d", *i.ref); - puts(""); - - for (c_items(i, const char*, {"12", "23", "453", "65", "676"})) - printf(" %s", *i.ref); - puts(""); - - IVec vec = c_make(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199}); - IMap map = c_make(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}}); - - puts("\n\nfor c_each:"); - for (c_each(i, IVec, vec)) - printf(" %d", *i.ref); - - puts("\n\nfor c_each in a map:"); - for (c_each(i, IMap, map)) - printf(" (%d %d)", i.ref->first, i.ref->second); - - puts("\n\nfor c_each_item:"); - for (c_each_item(e, IMap, map)) - printf(" (%d %d)", e->first, e->second); - - puts("\n\nfor c_each_kv:"); - for (c_each_kv(key, val, IMap, map)) - printf(" (%d %d)", *key, *val); - - #define f_isOdd() (*value & 1) - - puts("\n\nc_filter:"); - c_filter(IVec, vec, true - && f_isOdd() - && c_flt_skip(4) - && (printf(" %d", *value), c_flt_take(4)) - ); - - IVec_drop(&vec); - IMap_drop(&map); -} diff --git a/src/finchlite/codegen/stc/examples/algorithms/meson.build b/src/finchlite/codegen/stc/examples/algorithms/meson.build deleted file mode 100644 index d678f83c..00000000 --- a/src/finchlite/codegen/stc/examples/algorithms/meson.build +++ /dev/null @@ -1,19 +0,0 @@ -foreach sample : [ - 'filterdemos', - 'forloops', - 'random', - 'shape', - 'tree', - 'tree_rc', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'algorithm', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/algorithms/random.c b/src/finchlite/codegen/stc/examples/algorithms/random.c deleted file mode 100644 index 2cdaf752..00000000 --- a/src/finchlite/codegen/stc/examples/algorithms/random.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include - -int main(void) -{ - const long long N = 10000000, range = 1000000; - const uint64_t seed = (uint64_t)time(NULL); - crand64 rng = crand64_from(seed); - clock_t t; - - printf("Compare speed of full and unbiased ranged random numbers...\n"); - long long sum = 0; - t = clock(); - for (c_range(N)) { - sum += (int32_t)crand64_uint_r(&rng, 1); - } - t = clock() - t; - printf("full range\t\t: %f secs, %d, avg: %f\n", - (double)t/CLOCKS_PER_SEC, (int)N, (double)(sum/N)); - - sum = 0; - rng = crand64_from(seed); - t = clock(); - for (c_range(N)) { - sum += (int32_t)crand64_uint_r(&rng, 1) % (range + 1); // biased - } - t = clock() - t; - printf("biased 0-%d \t: %f secs, %d, avg: %f\n", - (int)range, (double)t/CLOCKS_PER_SEC, (int)N, (double)(sum/N)); -} diff --git a/src/finchlite/codegen/stc/examples/algorithms/shape.c b/src/finchlite/codegen/stc/examples/algorithms/shape.c deleted file mode 100644 index dea8ccb7..00000000 --- a/src/finchlite/codegen/stc/examples/algorithms/shape.c +++ /dev/null @@ -1,157 +0,0 @@ -// Demo of typesafe polymorphism in C99, using STC. - -#include -#include -#include - -#define DYN_CAST(T, s) \ - (&T##_api == (s)->api ? (T*)(s) : (T*)0) - -// Shape definition -// ============================================================ - -typedef struct { - float x, y; -} Point; - -typedef struct Shape Shape; - -struct ShapeAPI { - void (*drop)(Shape*); - void (*draw)(const Shape*); -}; - -struct Shape { - struct ShapeAPI* api; - uint32_t color; - uint16_t style; - uint8_t thickness; - uint8_t hardness; -}; - -void Shape_drop(Shape* shape) -{ - (void)shape; - printf("shape destructed\n"); -} - -void Shape_delete(Shape* shape) -{ - if (shape) { - shape->api->drop(shape); - free(shape); - } -} - -// Triangle implementation -// ============================================================ - -typedef struct { - Shape shape; - Point p[3]; -} Triangle; - -extern struct ShapeAPI Triangle_api; - - -Triangle Triangle_from(Point a, Point b, Point c) { - Triangle t = {{&Triangle_api}, {a, b, c}}; - return t; -} - -static void Triangle_draw(const Shape* shape) -{ - const Triangle* self = DYN_CAST(Triangle, shape); - printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n", - (double)self->p[0].x, (double)self->p[0].y, - (double)self->p[1].x, (double)self->p[1].y, - (double)self->p[2].x, (double)self->p[2].y); -} - -struct ShapeAPI Triangle_api = { - .drop = Shape_drop, - .draw = Triangle_draw, -}; - -// Polygon implementation -// ============================================================ - -#define T PointVec, Point -#include - -typedef struct { - Shape shape; - PointVec points; -} Polygon; - -extern struct ShapeAPI Polygon_api; - - -Polygon Polygon_init(void) { - Polygon p = {{&Polygon_api}, {0}}; - return p; -} - -void Polygon_addPoint(Polygon* self, Point p) -{ - PointVec_push(&self->points, p); -} - -static void Polygon_drop(Shape* shape) -{ - Polygon* self = DYN_CAST(Polygon, shape); - printf("poly destructed\n"); - PointVec_drop(&self->points); -} - -static void Polygon_draw(const Shape* shape) -{ - const Polygon* self = DYN_CAST(Polygon, shape); - printf("Polygon :"); - for (c_each(i, PointVec, self->points)) - printf(" (%g,%g)", (double)i.ref->x, (double)i.ref->y); - puts(""); -} - -struct ShapeAPI Polygon_api = { - .drop = Polygon_drop, - .draw = Polygon_draw, -}; - -// Test -// ============================================================ - -#define T Shapes, Shape* -#define i_keydrop(x) Shape_delete(*x) -#define i_no_clone -#include - -void testShape(const Shape* shape) -{ - shape->api->draw(shape); -} - - -int main(void) -{ - Shapes shapes = {0}; - - Triangle* tri1 = c_new(Triangle, Triangle_from(c_literal(Point){5, 7}, c_literal(Point){12, 7}, c_literal(Point){12, 20})); - Polygon* pol1 = c_new(Polygon, Polygon_init()); - Polygon* pol2 = c_new(Polygon, Polygon_init()); - - for (c_items(i, Point, {{50, 72}, {123, 73}, {127, 201}, {828, 333}})) - Polygon_addPoint(pol1, *i.ref); - - for (c_items(i, Point, {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}})) - Polygon_addPoint(pol2, *i.ref); - - Shapes_push(&shapes, &tri1->shape); - Shapes_push(&shapes, &pol1->shape); - Shapes_push(&shapes, &pol2->shape); - - for (c_each(i, Shapes, shapes)) - testShape(*i.ref); - - Shapes_drop(&shapes); -} diff --git a/src/finchlite/codegen/stc/examples/algorithms/shape.cpp b/src/finchlite/codegen/stc/examples/algorithms/shape.cpp deleted file mode 100644 index 9bbfd44e..00000000 --- a/src/finchlite/codegen/stc/examples/algorithms/shape.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// Demo of polymorphism in C++ - -#include -#include -#include - -// Shape definition -// ============================================================ - -struct Point { - float x, y; -}; - -std::ostream& operator<<(std::ostream& os, const Point& p) { - os << " (" << p.x << "," << p.y << ")"; - return os; -} - -struct Shape { - virtual ~Shape(); - virtual void draw() const = 0; - - uint32_t color; - uint16_t style; - uint8_t thickness; - uint8_t hardness; -}; - -Shape::~Shape() -{ - std::cout << "base destructed" << std::endl; -} - -// Triangle implementation -// ============================================================ - -struct Triangle : public Shape -{ - Triangle(Point a, Point b, Point c); - void draw() const override; - - private: Point p[3]; -}; - - -Triangle::Triangle(Point a, Point b, Point c) - : p{a, b, c} {} - -void Triangle::draw() const -{ - std::cout << "Triangle :" - << p[0] << p[1] << p[2] - << std::endl; -} - - -// Polygon implementation -// ============================================================ - - -struct Polygon : public Shape -{ - ~Polygon(); - void draw() const override; - void addPoint(const Point& p); - - private: std::vector points; -}; - - -void Polygon::addPoint(const Point& p) -{ - points.push_back(p); -} - -Polygon::~Polygon() -{ - std::cout << "poly destructed" << std::endl; -} - -void Polygon::draw() const -{ - std::cout << "Polygon :"; - for (auto& p : points) - std::cout << p ; - std::cout << std::endl; -} - - -// Test -// ============================================================ - -void testShape(const Shape* shape) -{ - shape->draw(); -} - -#include - -int main(void) -{ - std::vector> shapes; - - auto tri1 = std::make_unique(Point{5, 7}, Point{12, 7}, Point{12, 20}); - auto pol1 = std::make_unique(); - auto pol2 = std::make_unique(); - - for (auto& p: std::array - {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}}) - pol1->addPoint(p); - - for (auto& p: std::array - {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}}) - pol2->addPoint(p); - - shapes.push_back(std::move(tri1)); - shapes.push_back(std::move(pol1)); - shapes.push_back(std::move(pol2)); - - for (auto& shape: shapes) - testShape(shape.get()); -} diff --git a/src/finchlite/codegen/stc/examples/algorithms/tree.c b/src/finchlite/codegen/stc/examples/algorithms/tree.c deleted file mode 100644 index a7f17683..00000000 --- a/src/finchlite/codegen/stc/examples/algorithms/tree.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include -#include - -c_union (Tree, - (TreeEmpty, bool), - (TreeLeaf, int), - (TreeNode, struct { int value; Tree *left, *right; }) -); - -void Tree_drop(Tree* self) { - if (c_is(self, TreeNode, n)) { - Tree_drop(n->left); - free(n->left); - Tree_drop(n->right); - free(n->right); - } - free(self); -} - -int tree_sum(Tree* tree) { - c_when (tree) { - c_is(TreeEmpty) return 0; - c_is(TreeLeaf, v) return *v; - c_is(TreeNode, n) return n->value + tree_sum(n->left) + tree_sum(n->right); - } - return -1; -} - -int main(void) { - Tree* tree = - &c_variant(TreeNode, {1, - &c_variant(TreeNode, {2, - &c_variant(TreeLeaf, 3), - &c_variant(TreeLeaf, 4) - }), - &c_variant(TreeLeaf, 5) - }); - - printf("sum = %d\n", tree_sum(tree)); -} diff --git a/src/finchlite/codegen/stc/examples/algorithms/tree_rc.c b/src/finchlite/codegen/stc/examples/algorithms/tree_rc.c deleted file mode 100644 index a53ee7ec..00000000 --- a/src/finchlite/codegen/stc/examples/algorithms/tree_rc.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include - -declare_rc(TreeRc, union Tree); - -c_union (Tree, - (TreeEmpty, bool), - (TreeLeaf, int), - (TreeNode, struct { int value; TreeRc left, right; }) -); -void Tree_drop(Tree*); - -#define T TreeRc, Tree, (c_declared | c_keyclass) -#include - -void Tree_drop(Tree* self) { - if (c_is(self, TreeNode, n)) { - TreeRc_drop(&n->left); - TreeRc_drop(&n->right); - } -} - -int tree_sum(TreeRc tree) { - c_when (tree.get) { - c_is(TreeEmpty) return 0; - c_is(TreeLeaf, v) return *v; - c_is(TreeNode, n) return n->value + tree_sum(n->left) + tree_sum(n->right); - } - return -1; -} - -int main(void) { - TreeRc tree = - TreeRc_make(c_variant(TreeNode, {1, - TreeRc_make(c_variant(TreeNode, {2, - TreeRc_make(c_variant(TreeLeaf, 3)), - TreeRc_make(c_variant(TreeLeaf, 4)) - })), - TreeRc_make(c_variant(TreeLeaf, 5)) - })); - - printf("sum = %d\n", tree_sum(tree)); - TreeRc_drop(&tree); -} diff --git a/src/finchlite/codegen/stc/examples/bitsets/bits.c b/src/finchlite/codegen/stc/examples/bitsets/bits.c deleted file mode 100644 index aef9ae0e..00000000 --- a/src/finchlite/codegen/stc/examples/bitsets/bits.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include - -int main(void) -{ - cbits set = cbits_with_size(23, true); - cbits s2; - c_defer( - cbits_drop(&set), - cbits_drop(&s2) - ){ - printf("count %d, %d\n", (int)cbits_count(&set), (int)cbits_size(&set)); - cbits s1 = cbits_from("1110100110111"); - char buf[256]; - cbits_to_str(&s1, buf, 0, 255); - printf("buf: %s: %d\n", buf, (int)cbits_count(&s1)); - cbits_drop(&s1); - - cbits_reset(&set, 9); - cbits_resize(&set, 43, false); - printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255)); - - printf("%4d: ", (int)cbits_size(&set)); - for (c_range(i, cbits_size(&set))) - printf("%d", cbits_test(&set, i)); - puts(""); - - cbits_set(&set, 28); - cbits_resize(&set, 77, true); - cbits_resize(&set, 93, false); - cbits_resize(&set, 102, true); - cbits_set_value(&set, 99, false); - printf("%4d: ", (int)cbits_size(&set)); - for (c_range(i, cbits_size(&set))) - printf("%d", cbits_test(&set, i)); - - puts("\nIterate:"); - printf("%4d: ", (int)cbits_size(&set)); - for (c_range(i, cbits_size(&set))) - printf("%d", cbits_test(&set, i)); - puts(""); - - // Make a clone - s2 = cbits_clone(set); - cbits_flip_all(&s2); - cbits_set(&s2, 16); - cbits_set(&s2, 17); - cbits_set(&s2, 18); - printf(" new: "); - for (c_range(i, cbits_size(&s2))) - printf("%d", cbits_test(&s2, i)); - puts(""); - - printf(" xor: "); - cbits_xor(&set, &s2); - for (c_range(i, cbits_size(&set))) - printf("%d", cbits_test(&set, i)); - puts(""); - - cbits_set_all(&set, false); - printf("%4d: ", (int)cbits_size(&set)); - for (c_range(i, cbits_size(&set))) - printf("%d", cbits_test(&set, i)); - puts(""); - } -} diff --git a/src/finchlite/codegen/stc/examples/bitsets/bits2.c b/src/finchlite/codegen/stc/examples/bitsets/bits2.c deleted file mode 100644 index 797a72ec..00000000 --- a/src/finchlite/codegen/stc/examples/bitsets/bits2.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -// Example of static sized (stack allocated) bitsets - -#define T Bits, 80 // enable fixed size bitset on the stack -#include - -int main(void) -{ - Bits s1 = Bits_from("1110100110111"); - - printf("size %d\n", (int)Bits_size(&s1)); - char buf[256]; - Bits_to_str(&s1, buf, 0, 256); - printf("buf: %s: count=%d\n", buf, (int)Bits_count(&s1)); - - Bits_reset(&s1, 8); - printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256)); - - Bits s2 = Bits_clone(s1); - - Bits_flip_all(&s2); - Bits_reset(&s2, 66); - Bits_reset(&s2, 67); - printf(" s2: "); - for (c_range(i, Bits_size(&s2))) - printf("%d", Bits_test(&s2, i)); - puts(""); - - printf("xor: "); - Bits_xor(&s1, &s2); - for (c_range(i, Bits_size(&s1))) - printf("%d", Bits_test(&s1, i)); - puts(""); - - printf("all: "); - Bits_set_pattern(&s1, 0x3333333333333333); - for (c_range(i, Bits_size(&s1))) - printf("%d", Bits_test(&s1, i)); - puts(""); -} diff --git a/src/finchlite/codegen/stc/examples/bitsets/meson.build b/src/finchlite/codegen/stc/examples/bitsets/meson.build deleted file mode 100644 index c26d0e04..00000000 --- a/src/finchlite/codegen/stc/examples/bitsets/meson.build +++ /dev/null @@ -1,16 +0,0 @@ -foreach sample : [ - 'bits2', - 'bits', - 'prime', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'cbits', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/bitsets/prime.c b/src/finchlite/codegen/stc/examples/bitsets/prime.c deleted file mode 100644 index 3d7fb11d..00000000 --- a/src/finchlite/codegen/stc/examples/bitsets/prime.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include -#include - -cbits sieveOfEratosthenes(isize n) -{ - cbits bits = cbits_with_size(n/2 + 1, true); - isize q = (isize)sqrt((double) n) + 1; - for (isize i = 3; i < q; i += 2) { - for (isize j = i; j < n; j += 2) { - if (cbits_test(&bits, j/2)) { - i = j; - break; - } - } - for (isize j = i*i; j < n; j += i*2) - cbits_reset(&bits, j/2); - } - return bits; -} - -int main(void) -{ - int n = 100000000; - printf("Computing prime numbers up to %d\n", n); - - clock_t t = clock(); - cbits primes = sieveOfEratosthenes(n + 1); - - int np = (int)cbits_count(&primes); - t = clock() - t; - - printf("Number of primes: %d, time: %f\n\n", np, (double)t/CLOCKS_PER_SEC); - - puts("Show all the primes in the range [2, 1000):"); - printf("2"); - for (c_range(i, 3, 1000, 2)) - if (cbits_test(&primes, i/2)) printf(" %d", (int)i); - puts("\n"); - - puts("Show the last 50 primes using a temporary crange generator, 10 per line:"); - - c_filter(crange, c_iota(n - 1, 1, -2), true - && cbits_test(&primes, *value/2) - && printf("%d ", (int) *value) - && c_flt_take(50) - && c_flt_getcount() % 10 == 0 - && printf("\n") - ); - cbits_drop(&primes); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/cointerleave.c b/src/finchlite/codegen/stc/examples/coroutines/cointerleave.c deleted file mode 100644 index 0f335287..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/cointerleave.c +++ /dev/null @@ -1,64 +0,0 @@ -// https://www.youtube.com/watch?v=8sEe-4tig_A -#include -#include -#define T IVec, int -#include - -struct GenValue { - IVec *v; - IVec_iter it; - cco_base base; -}; - -static long get_value(struct GenValue* o) -{ - cco_async (o) { - for (cco_each(o->it, IVec, *o->v)) - cco_yield_v(*o->it.ref); - } - return 1L<<31; -} - -struct Generator { - struct GenValue a, b; - bool xactive, yactive; - long value; - cco_base base; -}; - -int interleaved(struct Generator* o) -{ - cco_async (o) { - do { - o->value = get_value(&o->a); - o->xactive = cco_is_active(&o->a); - if (o->xactive) - cco_yield; - - o->value = get_value(&o->b); - o->yactive = cco_is_active(&o->b); - if (o->yactive) - cco_yield; - } while (o->xactive | o->yactive); - } - return 0; -} - -void Use(void) -{ - IVec a = c_make(IVec, {2, 4, 6, 8, 10, 11}); - IVec b = c_make(IVec, {3, 5, 7, 9}); - - struct Generator gen = {{&a}, {&b}}; - - cco_run_coroutine(interleaved(&gen)) { - printf("%ld ", gen.value); - } - puts(""); - c_drop(IVec, &a, &b); -} - -int main(void) -{ - Use(); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/coread.c b/src/finchlite/codegen/stc/examples/coroutines/coread.c deleted file mode 100644 index bdf1c779..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/coread.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include - -// Read file line by line using coroutines: - -struct file_read { - const char* filename; - FILE* fp; - cstr line; - cco_base base; -}; - -int file_read(struct file_read* o) -{ - cco_async (o) { - o->fp = fopen(o->filename, "r"); - if (o->fp == NULL) - cco_exit(); - o->line = (cstr){0}; - cco_await( !cstr_getline(&o->line, o->fp) ); - - cco_finalize: - cstr_drop(&o->line); - if (o->fp) fclose(o->fp); - puts("finish"); - } - return 0; -} - -int main(void) -{ - struct file_read reader = {.filename=__FILE__}; - int n = 0; - cco_run_coroutine(file_read(&reader)) - { - printf("%3d %s\n", ++n, cstr_str(&reader.line)); - //if (n == 10) cco_stop(&reader); - } -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/coroutines1.c b/src/finchlite/codegen/stc/examples/coroutines/coroutines1.c deleted file mode 100644 index e250e6f8..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/coroutines1.c +++ /dev/null @@ -1,114 +0,0 @@ -#include -#include -#include - -// Demonstrate calling two coroutine from a coroutine: -// First call them concurrently, then in parallel: - - -// Suspend yield values -enum { YIELD_PRM = 1<<0, YIELD_FIB = 1<<1}; - -bool is_prime(long long i) { - for (long long j=2; j*j <= i; ++j) - if (i % j == 0) return false; - return true; -} - -struct prime { - cco_base base; - int count; - long long value; -}; - -int prime(struct prime* o) { - cco_async (o) { - if (o->value <= 2) { - o->value = 2; - if (o->count-- == 0) - cco_return; - cco_yield_v(YIELD_PRM); - } - for (o->value |= 1; o->count > 0; o->value += 2) { - if (is_prime(o->value)) { - --o->count; - cco_yield_v(YIELD_PRM); - } - } - cco_finalize: - puts("DONE prm"); - } - return 0; -} - - -// Use coroutine to create a fibonacci sequence generator: - -struct fibonacci { - cco_base base; - int count; - long long value, b; -}; - -int fibonacci(struct fibonacci* o) { - cco_async (o) { - assert(o->count < 94); - if (o->value == 0) - o->b = 1; - - while (true) { - if (o->count-- == 0) - cco_return; - // NB! locals lasts only until next yield/await! - long long tmp = o->value; - o->value = o->b; - o->b += tmp; - cco_yield_v(YIELD_FIB); - } - - cco_finalize: - puts("DONE fib"); - } - return 0; -} - - -struct combined { - struct prime prm; - struct fibonacci fib; - cco_base base; -}; - -int combined(struct combined* o) { - cco_async (o) { - puts("SERIAL:"); - o->prm = (struct prime){.count = 8}; - o->fib = (struct fibonacci){.count = 12}; - - cco_await_coroutine( prime(&o->prm) ); - cco_await_coroutine( fibonacci(&o->fib) ); - - puts("\nCONCURRENT:"); - o->prm = (struct prime){.count = 8}; - o->fib = (struct fibonacci){.count = 12}; - - cco_await_coroutine( prime(&o->prm) | fibonacci(&o->fib) ); - - cco_finalize: - puts("DONE prime and fib"); - } - return 0; -} - - -int main(void) { - struct combined comb = {0}; - int res; - - cco_run_coroutine(res = combined(&comb)) { - if (res & YIELD_PRM) - printf(" Prime=%lld\n", comb.prm.value); - if (res & YIELD_FIB) - printf(" Fibon=%lld\n", comb.fib.value); - } -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/coroutines2.c b/src/finchlite/codegen/stc/examples/coroutines/coroutines2.c deleted file mode 100644 index 0d9232a0..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/coroutines2.c +++ /dev/null @@ -1,112 +0,0 @@ -#include -#include -#include - -// Demonstrate calling two coroutine from a coroutine: -// First call them concurrently, then in parallel: - - -// Suspend yield values -enum { YIELD_PRM = 1<<0, YIELD_FIB = 1<<1}; - -bool is_prime(long long i) { - for (long long j=2; j*j <= i; ++j) - if (i % j == 0) return false; - return true; -} - -cco_task_struct (prime) { - prime_base base; - int count; - long long value; -}; - -int prime(struct prime* o) { - cco_async (o) { - if (o->value <= 2) { - o->value = 2; - if (o->count-- == 0) - cco_return; - cco_yield_v(YIELD_PRM); - } - for (o->value |= 1; o->count > 0; o->value += 2) { - if (is_prime(o->value)) { - --o->count; - cco_yield_v(YIELD_PRM); - } - } - - cco_finalize: - puts("DONE prm"); - } - return 0; -} - - -// Use coroutine to create a fibonacci sequence generator: - -cco_task_struct (fibonacci) { - fibonacci_base base; - int count; - long long value, b; -}; - -int fibonacci(struct fibonacci* o) { - cco_async (o) { - assert(o->count < 94); - if (o->value == 0) - o->b = 1; - - while (true) { - if (o->count-- == 0) - cco_return; - // NB! locals lasts only until next yield/await! - long long tmp = o->value; - o->value = o->b; - o->b += tmp; - cco_yield_v(YIELD_FIB); - } - - cco_finalize: - puts("DONE fib"); - } - return 0; -} - - -int main(void) { - struct prime prm; - struct fibonacci fib; - - puts("SERIAL:"); - prm = (struct prime){{prime}, .count=8}; - fib = (struct fibonacci){{fibonacci}, .count=12}; - - cco_run_task(&prm) { - printf(" Prime=%lld\n", prm.value); - } - cco_run_task(&fib) { - printf(" Fibon=%lld\n", fib.value); - } - - - puts("\nCONCURRENT:"); - prm = (struct prime){{prime}, .count=8}; - fib = (struct fibonacci){{fibonacci}, .count=12}; - - cco_fiber* fb = c_new(cco_fiber, 0); - cco_spawn(&prm, NULL, NULL, fb); - cco_spawn(&fib, NULL, NULL, fb); - - cco_run_fiber(&fb) { - switch (fb->status) { - case YIELD_PRM: - printf(" Prime=%lld\n", prm.value); - break; - case YIELD_FIB: - printf(" Fibon=%lld\n", fib.value); - break; - } - } - puts("DONE prime and fib"); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/coroutines3.c b/src/finchlite/codegen/stc/examples/coroutines/coroutines3.c deleted file mode 100644 index 16b93a02..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/coroutines3.c +++ /dev/null @@ -1,117 +0,0 @@ -#include -#include -#include - -// Demonstrate calling two coroutine from a coroutine: -// First call them concurrently, then in parallel: - - -// Suspend yield values -enum { YIELD_PRM = 1<<0, YIELD_FIB = 1<<1}; - -bool is_prime(long long i) { - for (long long j=2; j*j <= i; ++j) - if (i % j == 0) return false; - return true; -} - -cco_task_struct (prime) { - prime_base base; - int count; - long long value; -}; - -int prime(struct prime* o) { - cco_async (o) { - if (o->value <= 2) { - o->value = 2; - if (o->count-- == 0) - cco_return; - cco_yield_v(YIELD_PRM); - } - for (o->value |= 1; o->count > 0; o->value += 2) { - if (is_prime(o->value)) { - --o->count; - cco_yield_v(YIELD_PRM); - } - } - - cco_finalize: - puts("DONE prm"); - } - return 0; -} - - -// Use coroutine to create a fibonacci sequence generator: - -cco_task_struct (fibonacci) { - fibonacci_base base; - int count; - long long value, b; -}; - -int fibonacci(struct fibonacci* o) { - cco_async (o) { - assert(o->count < 94); - if (o->value == 0) - o->b = 1; - - while (true) { - if (o->count-- == 0) - cco_return; - // NB! locals lasts only until next yield/await! - long long tmp = o->value; - o->value = o->b; - o->b += tmp; - cco_yield_v(YIELD_FIB); - } - - cco_finalize: - puts("DONE fib"); - } - return 0; -} - -// Combine - -cco_task_struct (combined) { - combined_base base; - struct prime prm; - struct fibonacci fib; -}; - -int combined(struct combined* o) { - cco_async (o) { - puts("SERIAL:"); - o->prm = (struct prime){.base={prime}, .count=8}; - o->fib = (struct fibonacci){.base={fibonacci}, .count=12}; - - cco_await_task(&o->prm); - cco_await_task(&o->fib); - - puts("\nCONCURRENT:"); - o->prm = (struct prime){.base={prime}, .count=8}; - o->fib = (struct fibonacci){.base={fibonacci}, .count=12}; - cco_spawn(&o->prm); - cco_spawn(&o->fib); - - cco_await(cco_joined()); - - cco_finalize: - puts("DONE prime and fib"); - } - return 0; -} - - -int main(void) { - struct combined comb = {{combined}}; - - cco_run_task(it, &comb, NULL) { - if (it->status & YIELD_PRM) - printf(" Prime=%lld\n", comb.prm.value); - if (it->status & YIELD_FIB) - printf(" Fibon=%lld\n", comb.fib.value); - } -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/dining_philosophers.c b/src/finchlite/codegen/stc/examples/coroutines/dining_philosophers.c deleted file mode 100644 index cf161bcb..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/dining_philosophers.c +++ /dev/null @@ -1,86 +0,0 @@ -// https://en.wikipedia.org/wiki/Dining_philosophers_problem -#include -#include -#include -#include - -enum {num_philosophers = 5}; -enum PhMode {ph_THINKING, ph_HUNGRY, ph_EATING}; - -// Philosopher coroutine: use task coroutine -cco_task_struct (Philosopher) { - Philosopher_base base; // required - int id; - cco_timer tm; - enum PhMode mode; - int hunger; - struct Philosopher* left; - struct Philosopher* right; -}; - -int Philosopher(struct Philosopher* o) { - cco_async (o) { - while (1) { - double duration = 1.0 + crand64_real()*2.0; - printf("Philosopher %d is thinking for %.0f minutes...\n", o->id, duration*10); - o->hunger = 0; - o->mode = ph_THINKING; - cco_await_timer(&o->tm, duration); - - printf("Philosopher %d is hungry...\n", o->id); - o->mode = ph_HUNGRY; - cco_await(o->hunger >= o->left->hunger && - o->hunger >= o->right->hunger); - o->left->hunger += (o->left->mode == ph_HUNGRY); // don't starve the neighbours - o->right->hunger += (o->right->mode == ph_HUNGRY); - o->hunger = INT32_MAX; - o->mode = ph_EATING; - - duration = 0.5 + crand64_real(); - printf("Philosopher %d is eating for %.0f minutes...\n", o->id, duration*10); - cco_await_timer(&o->tm, duration); - } - cco_finalize: - printf("Philosopher %d done\n", o->id); - } - - return 0; -} - -// Dining coroutine -cco_task_struct (Dining) { - Dining_base base; // required - float duration; - struct Philosopher philos[num_philosophers]; - int i; - cco_timer tm; - cco_group wg; -}; - -int Dining(struct Dining* o) { - cco_async (o) { - for (int i = 0; i < num_philosophers; ++i) { - o->philos[i] = (struct Philosopher){ - .base = {Philosopher}, - .id = i + 1, - .left = &o->philos[(i - 1 + num_philosophers) % num_philosophers], - .right = &o->philos[(i + 1) % num_philosophers], - }; - cco_spawn(&o->philos[i], &o->wg); - } - cco_await_timer(&o->tm, o->duration); - - cco_finalize: - cco_await_cancel_group(&o->wg); - puts("Dining done"); - } - return 0; -} - -int main(void) -{ - struct Dining dining = {.base={Dining}, .duration=5.0f, .wg = {0}}; - - crand64_seed((uint64_t)time(NULL)); - cco_run_task(&dining); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/fibonacci.c b/src/finchlite/codegen/stc/examples/coroutines/fibonacci.c deleted file mode 100644 index 97077dfa..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/fibonacci.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include - -// Use coroutine to create a fibonacci sequence generator: - -cco_task_struct (fibonacci) { - fibonacci_base base; - unsigned long long value, b; -}; - -int fibonacci(struct fibonacci* o) { - unsigned long long tmp; - cco_async (o) { - o->value = 0; - o->b = 1; - cco_yield; - - while (true) { - tmp = o->value; - o->value = o->b; - o->b += tmp; - cco_yield; - } - - cco_finalize: - puts("done"); - } - return 0; -} - - -int main(void) { - struct fibonacci fib = {{fibonacci}}; - int n = 0; - - //cco_run_task(&fib) { - while (cco_resume(&fib)) { - printf("Fib(%d) = %llu\n", n++, fib.value); - - if (fib.value > fib.b) - cco_stop(&fib); - } -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/filetask.c b/src/finchlite/codegen/stc/examples/coroutines/filetask.c deleted file mode 100644 index 000df5b5..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/filetask.c +++ /dev/null @@ -1,92 +0,0 @@ -// https://github.com/lewissbaker/cppcoro#taskt - -#include -#include -#include -#include - -cco_task_struct (file_read) { - file_read_base base; - const char* path; - cstr line; - FILE* fp; - cco_timer tm; -}; - - -int file_read(struct file_read* o) -{ - cco_async (o) { - o->fp = fopen(o->path, "r"); - if (!o->fp) - goto fail; - o->line = cstr_init(); - - while (true) { - // emulate async io: await 1ms per line - cco_await_timer(&o->tm, 0.001); - - if (!cstr_getline(&o->line, o->fp)) - break; - cco_yield; - } - - cco_finalize: - fclose(o->fp); - cstr_drop(&o->line); - puts("done file_read"); - break; - - fail: - printf("error: couldn't open file '%s'.\n", o->path); - } - return 0; -} - - -cco_task_struct (count_line) { - count_line_base base; - cstr path; - struct file_read reader; - int lineCount; -}; - - -int count_line(struct count_line* o) -{ - cco_async (o) { - o->reader.base.func = file_read; - o->reader.path = cstr_str(&o->path); - - while (true) { - // await for next CCO_YIELD (or CCO_DONE) in file_read() - cco_await_task(&o->reader, CCO_YIELD); - if (cco_status() == CCO_DONE) break; - o->lineCount += 1; - cco_yield; - } - - cco_finalize: - cstr_drop(&o->path); - puts("done count_line"); - } - return 0; -} - - -int main(void) -{ - // Creates a new task - struct count_line countTask = { - .base = {count_line}, - .path = cstr_from(__FILE__), - }; - - // Execute coroutine as top-level blocking - int loop = 0; - - cco_run_task(&countTask) { ++loop; } - - printf("line count = %d\n", countTask.lineCount); - printf("exec count = %d\n", loop); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/generator.c b/src/finchlite/codegen/stc/examples/coroutines/generator.c deleted file mode 100644 index fddca2ac..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/generator.c +++ /dev/null @@ -1,68 +0,0 @@ -// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ - -#include -#include -#include - -// Create an iterable generator Triple with max_triples items. -// Requires coroutine Triple_next() and function Triple_begin() to be defined. - -typedef struct { - int a, b, c; -} Triple, Triple_value; - -typedef struct { - Triple* ref; // required by iterator - cco_base base; // required by coroutine -} Triple_iter; - -int Triple_next(Triple_iter* it) { - Triple* g = it->ref; // get generator before cco_async starts! - cco_async (it) - { - for (g->c = 5;; ++g->c) { - for (g->a = 1; g->a < g->c; ++g->a) { - for (g->b = g->a; g->b < g->c; ++g->b) { - if (g->a*g->a + g->b*g->b == g->c*g->c) { - cco_yield; - } - } - } - } - - cco_finalize: - it->ref = NULL; // stop iteration - printf("Coroutine done\n"); - } - return 0; -} - -Triple_iter Triple_begin(Triple* g) { - Triple_iter it = {.ref = g}; - Triple_next(&it); // advance to first - return it; -} - -int main(void) -{ - Triple triple = {0}; - - puts("Pythagorean triples.\nGet all triples with c < 40, using for c_each:"); - int n=0; - for (c_each(i, Triple, triple)) { - Triple* t = i.ref; - if (t->c < 40) - printf("%u: (%d, %d, %d)\n", n++, t->a, t->b, t->c); - else - cco_stop(&i); - } - - puts("\nGet the 10 first triples with c < 40, using c_filter:"); - c_filter(Triple, triple, true - && (value->c < 40) - && cco_flt_take(10) // NB! use cco_flt_take(n) instead of c_flt_take(n) - // to ensure coroutine cleanup. - // Also applies to cco_flt_takewhile(pred) - && printf("%d: (%d, %d, %d)\n", c_flt_getcount(), value->a, value->b, value->c) - ); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/launch.c b/src/finchlite/codegen/stc/examples/coroutines/launch.c deleted file mode 100644 index f9f89295..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/launch.c +++ /dev/null @@ -1,137 +0,0 @@ -#include -#include - -cco_task_struct (taskA, struct Output) { - taskA_base base; - int a; -}; -cco_task_struct (taskB, struct Output) { - taskB_base base; - double d; -}; -cco_task_struct (taskC, struct Output) { - taskC_base base; - float x, y; -}; - - -cco_task_struct (myTask) { - myTask_base base; - int n, end; -}; - -int myTask(struct myTask* o) { - cco_async (o) { - puts("start myTask"); - for (; o->n < o->end; ++o->n) { - printf("myTask: %d\n", o->n); - cco_yield; - } - - cco_finalize: - printf("myTask %d done\n", o->n); - } - - - puts("FREE myTask"); - c_free_n(o, 1); - return 0; -} - - -struct Output { - double value; - int error; - cco_group wg; -}; - -int taskC(struct taskC* o) { - cco_async (o) { - printf("taskC start: {%g, %g}\n", o->x, o->y); - - // assume there is an error... - cco_throw(99); - - puts("taskC work"); - cco_yield; - puts("taskC more work"); - - // initial return value - cco_env(o)->value = o->x * o->y; - cco_yield; - - cco_finalize: - puts("taskC done"); - } - - puts("FREE taskC"); - c_free_n(o, 1); - return 0; -} - - -int taskB(struct taskB* o) { - cco_async (o) { - printf("taskB start: %g\n", o->d); - cco_await_task(c_new(struct taskC, {{taskC}, 1.2f, 3.4f})); - - puts("taskB work"); - cco_env(o)->value += o->d; - cco_yield; - - puts("Spawning 3 tasks."); - cco_reset_group(&cco_env(o)->wg); - cco_spawn(c_new(struct myTask, {{myTask}, 1, 6}), &cco_env(o)->wg); - cco_spawn(c_new(struct myTask, {{myTask}, 101, 104}), &cco_env(o)->wg); - cco_spawn(c_new(struct myTask, {{myTask}, 1001, 1008}), &cco_env(o)->wg); - cco_yield; - puts("Spawned 3 tasks."); - - cco_finalize: - if (cco_err()->code == 99) { - printf("taskA recovered error '99' thrown on line %d\n", cco_err()->line); - cco_recover; // reset error to 0 and proceed after the await taskB call. - } - cco_await_group(&cco_env(o)->wg); - puts("Joined"); - puts("taskB done"); - } - - puts("FREE taskB"); - c_free_n(o, 1); - return 0; -} - - -int taskA(struct taskA* o) { - cco_async (o) { - printf("taskA start: %d\n", o->a); - cco_await_task(c_new(struct taskB, {{taskB}, 3.1415})); - - puts("taskA work"); - cco_env(o)->value += o->a; // final return value; - cco_yield; - - cco_finalize: - puts("taskA done"); - } - - puts("FREE taskA"); - c_free_n(o, 1); - return 0; -} - - -int main(void) -{ - struct Output output = {0}; - int count = 0; - - puts("start"); - - struct taskA* start = c_new(struct taskA, {{taskA}, 42}); - cco_run_task(start, &output) { ++count; } - - printf("\nresult: %g, error: %d\n", output.value, output.error); - printf("resumes: %d, fb size: %d\n", count, (int)sizeof(cco_fiber)); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/meson.build b/src/finchlite/codegen/stc/examples/coroutines/meson.build deleted file mode 100644 index 910da2db..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/meson.build +++ /dev/null @@ -1,29 +0,0 @@ -foreach sample : [ - 'cointerleave', - 'coread', - 'coroutines1', - 'coroutines2', - 'coroutines3', - 'launch', - 'producer', - 'producer_task', - 'dining_philosophers', - 'fibonacci', - 'filetask', - 'generator', - 'neco', - 'scheduler', - 'triples', - 'waitgroup', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'coroutine', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/coroutines/neco.c b/src/finchlite/codegen/stc/examples/coroutines/neco.c deleted file mode 100644 index e625a41d..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/neco.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -cco_task_struct (ticktock) { - ticktock_base base; - cco_timer tm; -}; - -int ticker(struct ticktock* o) { - cco_async (o) { - while (1) { - cco_await_timer(&o->tm, 1.0); - puts("tick"); - } - cco_finalize: - puts("drop tick"); - } - return 0; -} - -int tocker(struct ticktock* o) { - cco_async (o) { - while (1) { - cco_await_timer(&o->tm, 2.0); - puts("tock"); - } - cco_finalize: - puts("drop tock"); - } - return 0; -} - -int main(void) { - struct ticktock tick = {{ticker}}, tock = {{tocker}}; - cco_fiber* fb = c_new(cco_fiber, {0}); - cco_spawn(&tick, NULL, NULL, fb); - cco_spawn(&tock, NULL, NULL, fb); - - cco_timer tm = cco_make_timer(5.0); - cco_run_fiber(&fb) { - if (cco_timer_expired(&tm)) { - cco_stop(fb->task); - } - } -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/nested_awaits.c b/src/finchlite/codegen/stc/examples/coroutines/nested_awaits.c deleted file mode 100644 index df5e5c1c..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/nested_awaits.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -cco_task_struct (nested) { - nested_base base; - const char* name; - int level; - cco_timer tm; -}; - -int nested(struct nested* o) { - cco_async (o) { - printf("%s%d: start\n", o->name, o->level); - - if (o->level < 6) { - struct nested* c = c_new(struct nested, {{nested}, .name=o->name, .level=o->level + 1}); - cco_await_task(c); - } - printf("%s%d: running\n", o->name, o->level); - cco_await_timer(&o->tm, 0.2); - - if (o->level == 3) { - puts("CANCEL"); - cco_throw(CCO_CANCEL); - } - cco_await_timer(&o->tm, 0.2); - - cco_finalize: - printf("%s%d: done\n", o->name, o->level); - } - - c_free_n(o, 1); - return 0; -} - - -int main(void) -{ - struct nested* go = c_new(struct nested, {{nested}, .name="A", .level=1}); - cco_run_task(go); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/producer.c b/src/finchlite/codegen/stc/examples/coroutines/producer.c deleted file mode 100644 index 172179f8..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/producer.c +++ /dev/null @@ -1,92 +0,0 @@ -// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/ - -#include -#include -#include -#include - -struct next_value { - int val; - cco_timer tm; - cco_base base; -}; - -int next_value(struct next_value* co) { - cco_async (co) { - while (true) { - cco_await_timer(&co->tm, 1 + rand() % 2); - co->val = rand(); - cco_yield; - } - } - return 0; -} - -void print_time(void) { - time_t now = time(NULL); - char mbstr[64]; - strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now)); - printf("%s ", mbstr); -} - -// PRODUCER -struct produce { - struct next_value next; - cstr text; - cco_base base; -}; - -int produce(struct produce* pr) { - cco_async (pr) { - pr->text = cstr_init(); - while (true) { - cco_await_coroutine(next_value(&pr->next), CCO_YIELD); - cstr_printf(&pr->text, "item %d", pr->next.val); - print_time(); - printf("produced %s\n", cstr_str(&pr->text)); - cco_yield; - } - - cco_finalize: - cstr_drop(&pr->text); - puts("done producer"); - } - return 0; -} - -// CONSUMER -struct consume { - int n, i; - cco_base base; -}; - -int consume(struct consume* co, struct produce* pr) { - cco_async (co) { - for (co->i = 1; co->i <= co->n; ++co->i) { - printf("consumer #%d\n", co->i); - cco_await_coroutine(produce(pr), CCO_YIELD); - print_time(); - printf("consumed %s\n", cstr_str(&pr->text)); - } - - cco_finalize: - puts("done consumer"); - } - return 0; -} - -int main(void) { - struct produce producer = {0}; - struct consume consumer = {.n=5}; - int count = 0; - - cco_run_coroutine(consume(&consumer, &producer)) { - ++count; - //cco_sleep(0.001); - //if (consumer.i == 3) cco_stop(&consumer); - } - - cco_stop(&producer); - produce(&producer); - printf("count: %d\n", count); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/producer_task.c b/src/finchlite/codegen/stc/examples/coroutines/producer_task.c deleted file mode 100644 index 3503e83a..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/producer_task.c +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include -#include -#define T Inventory, int -#include - -// Example shows symmetric coroutines producer/consumer style. - -cco_task_struct (produce) { - produce_base base; // must be first (compile-time checked) - struct consume* consumer; - Inventory inv; - int limit, batch, serial, total; -}; - -cco_task_struct (consume) { - consume_base base; // must be first - struct produce* producer; -}; - - -int produce(struct produce* o) { - cco_async (o) { - while (1) { - if (o->serial > o->total) { - if (Inventory_is_empty(&o->inv)) - cco_return; // cleanup and finish - } - else if (Inventory_size(&o->inv) < o->limit) { - for (c_range(o->batch)) - Inventory_push(&o->inv, ++o->serial); - - printf("produced %d items, Inventory has now %d items:\n", - o->batch, (int)Inventory_size(&o->inv)); - - for (c_each(i, Inventory, o->inv)) - printf(" %2d", *i.ref); - puts(""); - } - - cco_yield_to(o->consumer); // symmetric transfer - } - - cco_finalize: - puts("stop consumer"); - cco_await_cancel_task(o->consumer); - Inventory_drop(&o->inv); - puts("producer dropped"); - } - return 0; -} - -int consume(struct consume* o) { - cco_async (o) { - int n, sz; - while (1) { - n = rand() % 10; - sz = (int)Inventory_size(&o->producer->inv); - if (n > sz) n = sz; - - for (c_range(n)) - Inventory_pop(&o->producer->inv); - printf("consumed %d items\n", n); - - cco_yield_to(o->producer); // symmetric transfer - } - - cco_finalize: - puts("consumer drop step 1"); - cco_yield; - puts("consumer drop step 2"); - cco_yield; - puts("consumer dropped"); - } - return 0; -} - -int main(void) -{ - srand((unsigned)time(0)); - struct produce producer = { - .base = {produce}, - .inv = {0}, - .limit = 12, - .batch = 8, - .total = 50, - }; - struct consume consumer = { - .base = {consume}, - .producer = &producer, - }; - producer.consumer = &consumer; - - cco_run_task(&producer); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/scheduler.c b/src/finchlite/codegen/stc/examples/coroutines/scheduler.c deleted file mode 100644 index 382001eb..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/scheduler.c +++ /dev/null @@ -1,80 +0,0 @@ -// https://www.youtube.com/watch?v=8sEe-4tig_A -#include -#include - -#define T Tasks, cco_task* -#define i_keydrop(x) { puts("free task"); free(*x); } -#define i_no_clone -#include - -cco_task_struct (Scheduler) { - Scheduler_base base; - cco_task* pulled; - Tasks tasks; -}; - -int Scheduler(struct Scheduler* o) { - cco_async (o) { - while (!Tasks_is_empty(&o->tasks)) { - o->pulled = Tasks_pull(&o->tasks); - - int result = cco_resume(o->pulled); - - if (result == CCO_YIELD) { - Tasks_push(&o->tasks, o->pulled); - } else { - Tasks_value_drop(&o->tasks, &o->pulled); - } - } - - cco_finalize: - Tasks_drop(&o->tasks); - puts("Task queue dropped"); - } - return 0; -} - - -static int TaskA(struct cco_task* o) { - cco_async (o) { - puts("Hello, from task A"); - cco_yield; - puts("A is back doing work"); - cco_yield; - puts("A is back doing more work"); - cco_yield; - puts("A is back doing even more work"); - - cco_finalize: - puts("A done"); - } - - return 0; -} - - -static int TaskB(struct cco_task* o) { - cco_async (o) { - puts("Hello, from task B"); - cco_yield; - puts("B is back doing work"); - cco_yield; - puts("B is back doing more work"); - - cco_finalize: - puts("B done"); - } - return 0; -} - -int main(void) { - struct Scheduler schedule = { - .base={Scheduler}, - .tasks = c_make(Tasks, { - c_new(cco_task, {.base={TaskA}}), - c_new(cco_task, {.base={TaskB}}), - }) - }; - - cco_run_task(&schedule); -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/triples.c b/src/finchlite/codegen/stc/examples/coroutines/triples.c deleted file mode 100644 index c38383dd..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/triples.c +++ /dev/null @@ -1,76 +0,0 @@ -// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ - -#include -#include - -void triples_vanilla(int max_c) { - for (int c = 5, i = 0;; ++c) { - for (int a = 1; a < c; ++a) { - for (int b = a + 1; b < c; ++b) { - if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) { - if (c > max_c) - goto done; - printf("%d: {%d, %d, %d}\n", ++i, a, b, c); - } - } - } - } - done:; -} - -struct triples { - int max_c; - int a, b, c; - cco_base base; -}; - -int triples_coro(struct triples* o) { - cco_async (o) { - for (o->c = 5;; ++o->c) { - for (o->a = 1; o->a < o->c; ++o->a) { - for (o->b = o->a + 1; o->b < o->c; ++o->b) { - if ((int64_t)o->a * o->a + - (int64_t)o->b * o->b == - (int64_t)o->c * o->c) - { - if (o->c > o->max_c) - cco_return; - cco_yield; - } - } - } - } - - cco_finalize: - puts("done"); - } - return 0; -} - -int gcd(int a, int b) { - while (b) { - int tmp = a % b; - a = b; - b = tmp; - } - return a; -} - -int main(void) -{ - puts("Vanilla triples:"); - triples_vanilla(20); - - puts("\nCoroutine triples with GCD = 1:"); - struct triples tri = {.max_c = 100}; - int n = 0; - - cco_run_coroutine(triples_coro(&tri)) { - if (gcd(tri.a, tri.b) > 1) - continue; - if (++n <= 20) - printf("%d: {%d, %d, %d}\n", n, tri.a, tri.b, tri.c); - else - cco_stop(&tri); - } -} diff --git a/src/finchlite/codegen/stc/examples/coroutines/waitgroup.c b/src/finchlite/codegen/stc/examples/coroutines/waitgroup.c deleted file mode 100644 index 3bcf56aa..00000000 --- a/src/finchlite/codegen/stc/examples/coroutines/waitgroup.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include - -cco_task_struct (worker) { - worker_base base; - int id; - cco_timer tm; -}; - -int worker(struct worker* o) { - cco_async (o) { - printf("Worker %d starting\n", o->id); - cco_yield; - - cco_await_timer(&o->tm, 1.0 + o->id/8.0); - - cco_finalize: - printf("Worker %d done: %f\n", o->id, cco_timer_elapsed(&o->tm)); - } - - c_free_n(o, 1); - return 0; -} - - -cco_task_struct (sleeper) { - sleeper_base base; - cco_timer tm; -}; - -int sleeper(struct sleeper* o) { - cco_async (o) { - printf("Sleeper starting\n"); - cco_await_timer(&o->tm, 3.0); - - cco_finalize: - printf("Sleeper done: %f\n", cco_timer_elapsed(&o->tm)); - } - - c_free_n(o, 1); - return 0; -} - - -cco_task_struct (everyone) { - everyone_base base; - struct sleeper* sleep; - cco_group wg; -}; - -int everyone(struct everyone* o) { - cco_async (o) { - o->sleep = c_new(struct sleeper, {{sleeper}}); - cco_spawn(o->sleep); - cco_yield; // allow sleep-task to start - - cco_reset_group(&o->wg); - for (c_range32(i, 8)) { // NB: local i, do not yield or await inside loop. - struct worker* work = c_new(struct worker, {.base={worker}, .id=i}); - cco_spawn(work, &o->wg); - } - cco_yield; - - puts("Here 1"); - //cco_cancel_task(o->sleep); - //puts("sleep cancelled"); - //cco_throw(CCO_CANCEL); - puts("Here 2"); - - cco_finalize: - puts("Await one"); - cco_await_n(&o->wg, 1); // await for 1 launched worker to finish - puts("1 worker done."); - cco_await_n(&o->wg, 3); // await for 3 more workers to finish - puts("3 more workers done"); - cco_await_group(&o->wg); // await for remaining workers to finish - //cco_await_cancel_group(&o->wg); // cancel + cco_await_group() - puts("All workers done."); - } - - c_free_n(o, 1); - return 0; -} - - -int main(void) -{ - struct everyone* go = c_new(struct everyone, {{everyone}}); - cco_run_task(go); - puts("Everyone done"); -} diff --git a/src/finchlite/codegen/stc/examples/hashmaps/birthday.c b/src/finchlite/codegen/stc/examples/hashmaps/birthday.c deleted file mode 100644 index 7fabcd02..00000000 --- a/src/finchlite/codegen/stc/examples/hashmaps/birthday.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include - -#define T hmap_ui, uint64_t, int -#include - -static uint64_t seed = 12345; - -static void test_repeats(void) -{ - enum {BITS = 46, BITS_TEST = BITS/2 + 2}; - static const isize N = (isize)(1ull << BITS_TEST); - static const uint64_t mask = (1ull << BITS) - 1; - - printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST); - crand64 rng = crand64_from(seed); - - hmap_ui m = hmap_ui_with_capacity(N); - for (c_range(i, N)) { - uint64_t k = crand64_uint_r(&rng, 1) & mask; - int v = hmap_ui_insert(&m, k, 0).ref->second += 1; - if (v > 1) printf("repeated value %" PRIu64 " (%d) at 2^%d\n", - k, v, (int)log2((double)i)); - } - hmap_ui_drop(&m); -} - -#define T hmap_uu, uint32_t, uint64_t -#include - -void test_distribution(void) -{ - enum {BITS = 24}; - printf("distribution test: 2^%d values\n", BITS); - crand64 rng = crand64_from(seed); - const isize N = (isize)(1ull << BITS); - - hmap_uu map = {0}; - for (c_range(N)) { - uint64_t k = crand64_uint_r(&rng, 1); - hmap_uu_insert(&map, k & 0xf, 0).ref->second += 1; - } - - uint64_t sum = 0; - for (c_each(i, hmap_uu, map)) sum += i.ref->second; - sum /= (uint64_t)map.size; - - for (c_each_kv(k, v, hmap_uu, map)) { - printf("%4" PRIu32 ": %" PRIu64 " - %" PRIu64 ": %11.8f\n", - *k, *v, sum, - (1.0 - (double)*v / (double)sum)); - } - - hmap_uu_drop(&map); -} - -int main(void) -{ - seed = (uint64_t)time(NULL); - test_distribution(); - test_repeats(); -} diff --git a/src/finchlite/codegen/stc/examples/hashmaps/books.c b/src/finchlite/codegen/stc/examples/hashmaps/books.c deleted file mode 100644 index 4bfb7f97..00000000 --- a/src/finchlite/codegen/stc/examples/hashmaps/books.c +++ /dev/null @@ -1,61 +0,0 @@ -// https://doc.rust-lang.org/std/collections/struct.HashMap.html -#include -#define i_keypro cstr -#define i_valpro cstr -#include - -// Type inference lets us omit an explicit type signature (which -// would be `HashMap` in this example). -int main(void) -{ - hmap_cstr book_reviews = {0}; - - // Review some books. - hmap_cstr_emplace(&book_reviews, - "Adventures of Huckleberry Finn", - "My favorite book." - ); - hmap_cstr_emplace(&book_reviews, - "Grimms' Fairy Tales", - "Masterpiece." - ); - hmap_cstr_emplace(&book_reviews, - "Pride and Prejudice", - "Very enjoyable" - ); - hmap_cstr_insert(&book_reviews, - cstr_lit("The Adventures of Sherlock Holmes"), - cstr_lit("Eye lyked it alot.") - ); - - // Check for a specific one. - // When collections store owned values (String), they can still be - // queried using references (&str). - if (hmap_cstr_contains(&book_reviews, "Les Misérables")) { - printf("We've got %d reviews, but Les Misérables ain't one.", - (int)hmap_cstr_size(&book_reviews)); - } - - // oops, this review has a lot of spelling mistakes, let's delete it. - hmap_cstr_erase(&book_reviews, "The Adventures of Sherlock Holmes"); - - // Look up the values associated with some keys. - const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"}; - for (c_range(i, c_countof(to_find))) { - const hmap_cstr_value* b = hmap_cstr_get(&book_reviews, to_find[i]); - if (b) - printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second)); - else - printf("%s is unreviewed.\n", to_find[i]); - } - - // Look up the value for a key (will panic if the key is not found). - printf("Review for Jane: %s\n", cstr_str(hmap_cstr_at(&book_reviews, "Pride and Prejudice"))); - - // Iterate over everything. - for (c_each_kv(book, review, hmap_cstr, book_reviews)) { - printf("%s: \"%s\"\n", cstr_str(book), cstr_str(review)); - } - - hmap_cstr_drop(&book_reviews); -} diff --git a/src/finchlite/codegen/stc/examples/hashmaps/hashmap.c b/src/finchlite/codegen/stc/examples/hashmaps/hashmap.c deleted file mode 100644 index 2cacec2a..00000000 --- a/src/finchlite/codegen/stc/examples/hashmaps/hashmap.c +++ /dev/null @@ -1,48 +0,0 @@ -// https://doc.rust-lang.org/rust-by-example/std/hash.html -#include -#include -#define T StrMap, cstr, cstr, (c_keypro | c_valpro) -#include - -const char* call(const char* number) { - if (strcmp(number, "798-1364") == 0) - return "We're sorry, the call cannot be completed as dialed." - " Please hang up and try again."; - else if (strcmp(number, "645-7689") == 0) - return "Hello, this is Mr. Awesome's Pizza. My name is Fred." - " What can I get for you today?"; - else - return "Hi! Who is this again?"; -} - -int main(void) { - StrMap contacts = {0}; - - StrMap_emplace(&contacts, "Daniel", "798-1364"); - StrMap_emplace(&contacts, "Ashley", "645-7689"); - StrMap_emplace(&contacts, "Katie", "435-8291"); - StrMap_emplace(&contacts, "Robert", "956-1745"); - - const StrMap_value* v; - if ((v = StrMap_get(&contacts, "Daniel"))) - printf("Calling Daniel: %s\n", call(cstr_str(&v->second))); - else - printf("Don't have Daniel's number."); - - StrMap_emplace_or_assign(&contacts, "Daniel", "164-6743"); - - if ((v = StrMap_get(&contacts, "Ashley"))) - printf("Calling Ashley: %s\n", call(cstr_str(&v->second))); - else - printf("Don't have Ashley's number."); - - StrMap_erase(&contacts, "Ashley"); - - puts(""); - for (c_each_kv(contact, number, StrMap, contacts)) { - printf("Calling %s: %s\n", cstr_str(contact), call(cstr_str(number))); - } - puts(""); - - StrMap_drop(&contacts); -} diff --git a/src/finchlite/codegen/stc/examples/hashmaps/mapmap.c b/src/finchlite/codegen/stc/examples/hashmaps/mapmap.c deleted file mode 100644 index 184b47f7..00000000 --- a/src/finchlite/codegen/stc/examples/hashmaps/mapmap.c +++ /dev/null @@ -1,59 +0,0 @@ -// create a structure like: std::map>: -#include - -// People: map cstr -> cstr. (name -> email) -#define T People, cstr, cstr, (c_keypro | c_valpro) -#define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override -#include - -// Departments: map cstr -> People. People is a map and has _clone, _drop, therefore a "class". -#define T Departments, cstr, People, (c_keypro | c_valclass) -#include - - -void add(Departments* deps, const char* name, const char* email, const char* dep) -{ - People *people = &Departments_emplace(deps, dep, People_init()).ref->second; - People_put(people, name, email); -} - -int contains(Departments* map, const char* name) -{ - int count = 0; - for (c_each_item(e, Departments, *map)) - if (People_contains(&e->second, name)) - ++count; - return count; -} - -int main(void) -{ - Departments map = {0}; - - add(&map, "Anna Kendro", "Anna@myplace.com", "Support"); - add(&map, "Terry Dane", "Terry@myplace.com", "Development"); - add(&map, "Kik Winston", "Kik@myplace.com", "Finance"); - add(&map, "Nancy Drew", "Nancy@live.com", "Development"); - add(&map, "Nick Denton", "Nick@myplace.com", "Finance"); - add(&map, "Stan Whiteword", "Stan@myplace.com", "Marketing"); - add(&map, "Serena Bath", "Serena@myplace.com", "Support"); - add(&map, "Patrick Dust", "Patrick@myplace.com", "Finance"); - add(&map, "Red Winger", "Red@gmail.com", "Marketing"); - add(&map, "Nick Denton", "Nick@yahoo.com", "Support"); - add(&map, "Colin Turth", "Colin@myplace.com", "Support"); - add(&map, "Dennis Kay", "Dennis@mail.com", "Marketing"); - add(&map, "Anne Dickens", "Anne@myplace.com", "Development"); - - for (c_each_kv(dep, people, Departments, map)) - for (c_each_kv(name, email, People, *people)) - printf("%s: %s - %s\n", cstr_str(dep), cstr_str(name), cstr_str(email)); - puts(""); - - printf("found Nick Denton: %d\n", contains(&map, "Nick Denton")); - printf("found Patrick Dust: %d\n", contains(&map, "Patrick Dust")); - printf("found Dennis Kay: %d\n", contains(&map, "Dennis Kay")); - printf("found Serena Bath: %d\n", contains(&map, "Serena Bath")); - puts("Done"); - - Departments_drop(&map); -} diff --git a/src/finchlite/codegen/stc/examples/hashmaps/meson.build b/src/finchlite/codegen/stc/examples/hashmaps/meson.build deleted file mode 100644 index 373b7cd4..00000000 --- a/src/finchlite/codegen/stc/examples/hashmaps/meson.build +++ /dev/null @@ -1,21 +0,0 @@ -foreach sample : [ - 'birthday', - 'books', - 'hashmap', - 'mapmap', - 'new_map', - 'phonebook', - 'unordered_set', - 'vikings', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'hmap', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/hashmaps/new_map.c b/src/finchlite/codegen/stc/examples/hashmaps/new_map.c deleted file mode 100644 index 6f3ade98..00000000 --- a/src/finchlite/codegen/stc/examples/hashmaps/new_map.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include - -declare_hashmap(hmap_pnt, struct Point, int); - -typedef struct MyStruct { - hmap_pnt pntmap; - cstr name; -} MyStruct; - -// int => int map -#define T hmap_int, int, int -#include - -// Point => int map -typedef struct Point { int x, y; } Point; - -// Point => int map, uses default hash function -#define T hmap_pnt, struct Point, int, (c_declared) -#define i_eq c_memcmp_eq -#include - -// cstr => cstr map -#define i_keypro cstr -#define i_valpro cstr -#include - -// string set -#define i_keypro cstr -#include - - -int main(void) -{ - hmap_pnt pmap = c_make(hmap_pnt, { - {{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3} - }); - - for (c_each_kv(k, v, hmap_pnt, pmap)) - printf(" (%d, %d: %d)", k->x, k->y, *v); - puts(""); - - hmap_cstr smap = c_make(hmap_cstr, { - {"Hello, friend", "long time no see"}, - {"So long", "see you around"}, - }); - - hset_cstr sset = c_make(hset_cstr, { - "Hello, friend", - "Nice to see you again", - "So long", - }); - - hmap_int map = {0}; - hmap_int_insert(&map, 123, 321); - hmap_int_insert(&map, 456, 654); - hmap_int_insert(&map, 789, 987); - - for (c_each_item(s, hset_cstr, sset)) - printf(" %s\n", cstr_str(s)); - - hmap_int_drop(&map); - hset_cstr_drop(&sset); - hmap_cstr_drop(&smap); - hmap_pnt_drop(&pmap); -} diff --git a/src/finchlite/codegen/stc/examples/hashmaps/phonebook.c b/src/finchlite/codegen/stc/examples/hashmaps/phonebook.c deleted file mode 100644 index c6d8b87f..00000000 --- a/src/finchlite/codegen/stc/examples/hashmaps/phonebook.c +++ /dev/null @@ -1,69 +0,0 @@ -// The MIT License (MIT) -// Copyright (c) 2018 Maksim Andrianov -// -// 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. - -// Program to emulates the phone book. -#include -#define T StrMap, cstr, cstr, (c_keypro | c_valpro) -#include - -#define T StrSet, cstr, (c_keypro) -#include - -void print_phone_book(StrMap phone_book) -{ - for (c_each_kv(k, v, StrMap, phone_book)) - printf("%s\t- %s\n", cstr_str(k), cstr_str(v)); -} - -int main(void) -{ - StrMap phone_book = c_make(StrMap, { - {"Lilia Friedman", "(892) 670-4739"}, - {"Tariq Beltran", "(489) 600-7575"}, - {"Laiba Juarez", "(303) 885-5692"}, - {"Elliott Mooney", "(945) 616-4482"}, - }); - - printf("Phone book:\n"); - print_phone_book(phone_book); - - StrMap_emplace(&phone_book, "Zak Byers", "(551) 396-1880"); - StrMap_emplace(&phone_book, "Zak Byers", "(551) 396-1990"); - - printf("\nPhone book after adding Zak Byers:\n"); - print_phone_book(phone_book); - - if (StrMap_contains(&phone_book, "Tariq Beltran")) - printf("\nTariq Beltran is in phone book\n"); - - StrMap_erase(&phone_book, "Tariq Beltran"); - StrMap_erase(&phone_book, "Elliott Mooney"); - - printf("\nPhone book after erasing Tariq and Elliott:\n"); - print_phone_book(phone_book); - - StrMap_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188"); - - printf("\nPhone book after update phone of Zak Byers:\n"); - print_phone_book(phone_book); - - StrMap_drop(&phone_book); -} diff --git a/src/finchlite/codegen/stc/examples/hashmaps/unordered_set.c b/src/finchlite/codegen/stc/examples/hashmaps/unordered_set.c deleted file mode 100644 index 01b68bdb..00000000 --- a/src/finchlite/codegen/stc/examples/hashmaps/unordered_set.c +++ /dev/null @@ -1,44 +0,0 @@ -// https://iq.opengenus.org/containers-cpp-stl/ -// C program to demonstrate various function of stc hset -#include -#define i_keypro cstr -#include - -int main(void) -{ - // declaring set for storing string data-type - hset_cstr stringSet = {0}; - c_defer( - hset_cstr_drop(&stringSet) - ){ - // inserting various string, same string will be stored - // once in set - hset_cstr_emplace(&stringSet, "code"); - hset_cstr_emplace(&stringSet, "in"); - hset_cstr_emplace(&stringSet, "C"); - hset_cstr_emplace(&stringSet, "is"); - hset_cstr_emplace(&stringSet, "fast"); - - const char* key = "slow"; - - // find returns end iterator if key is not found, - // else it returns iterator to that key - - if (hset_cstr_find(&stringSet, key).ref == NULL) - printf("\"%s\" not found\n", key); - else - printf("Found \"%s\"\n", key); - - key = "C"; - if (!hset_cstr_contains(&stringSet, key)) - printf("\"%s\" not found\n", key); - else - printf("Found \"%s\"\n", key); - - // now iterating over whole set and printing its - // content - printf("All elements :\n"); - for (c_each(itr, hset_cstr, stringSet)) - printf("%s\n", cstr_str(itr.ref)); - } -} diff --git a/src/finchlite/codegen/stc/examples/hashmaps/vikings.c b/src/finchlite/codegen/stc/examples/hashmaps/vikings.c deleted file mode 100644 index bc54f09e..00000000 --- a/src/finchlite/codegen/stc/examples/hashmaps/vikings.c +++ /dev/null @@ -1,65 +0,0 @@ -#include - -typedef struct Viking { - cstr name; - cstr country; -} Viking; - -Viking Viking_make(cstr_raw name, cstr_raw country) { - return (Viking){.name = cstr_from(name), .country = cstr_from(country)}; -} - -void Viking_drop(Viking* vk) { - cstr_drop(&vk->name); - cstr_drop(&vk->country); -} - -Viking Viking_clone(Viking v) { - v.name = cstr_clone(v.name); - v.country = cstr_clone(v.country); - return v; -} - -// Define Viking_raw, a Viking lookup struct with eq, hash and conversion functions between them: -typedef struct { - const char* name; - const char* country; -} Viking_raw; - -bool Viking_raw_eq(const Viking_raw* rx, const Viking_raw* ry) { - return strcmp(rx->name, ry->name)==0 && strcmp(rx->country, ry->country)==0; -} - -size_t Viking_raw_hash(const Viking_raw* rv) { - return c_hash_mix(c_hash_str(rv->name), c_hash_str(rv->country)); -} - -Viking Viking_from(Viking_raw raw) { // note: parameter is by value - Viking v = {cstr_from(raw.name), cstr_from(raw.country)}; return v; -} - -Viking_raw Viking_toraw(const Viking* vp) { - Viking_raw rv = {cstr_str(&vp->name), cstr_str(&vp->country)}; return rv; -} - -// Define the map. Viking is now a "pro"-type: -#define T Players, Viking, int, (c_keypro) -#include - -int main(void) -{ - Players vikings = c_make(Players, { - {{"Einar", "Norway"}, 25}, - {{"Olaf", "Denmark"}, 24}, - {{"Harald", "Iceland"}, 12}, - }); - - // Now lookup is using Viking_raw, not Viking: - printf("Lookup: Olaf of Denmark has %d hp\n\n", *Players_at(&vikings, (Viking_raw){"Olaf", "Denmark"})); - - for (c_each(v, Players, vikings)) { - Players_raw r = Players_value_toraw(v.ref); - printf("%s of %s has %d hp\n", r.first.name, r.first.country, r.second); - } - Players_drop(&vikings); -} diff --git a/src/finchlite/codegen/stc/examples/linkedlists/intrusive.c b/src/finchlite/codegen/stc/examples/linkedlists/intrusive.c deleted file mode 100644 index 9fcb1a1b..00000000 --- a/src/finchlite/codegen/stc/examples/linkedlists/intrusive.c +++ /dev/null @@ -1,31 +0,0 @@ -// Example of list using the node API. - -#include - -#define T List, int, (c_use_cmp) -#include - -void printList(List list) { - printf("list:"); - for (c_each(i, List, list)) - printf(" %d", *i.ref); - puts(""); -} - -int main(void) { - List list = {0}; - for (c_items(i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8})) - List_push_back_node(&list, c_new(List_node, {.value=*i.ref})); - - printList(list); - - puts("Sort list"); - List_sort(&list); - printList(list); - - puts("Remove nodes from list"); - while (!List_is_empty(&list)) - free(List_unlink_after_node(&list, list.last)); - - printList(list); -} diff --git a/src/finchlite/codegen/stc/examples/linkedlists/list_erase.c b/src/finchlite/codegen/stc/examples/linkedlists/list_erase.c deleted file mode 100644 index 827ef1b7..00000000 --- a/src/finchlite/codegen/stc/examples/linkedlists/list_erase.c +++ /dev/null @@ -1,29 +0,0 @@ -// erasing from list -#include - -#define T IList, int -#include - -int main(void) -{ - IList L = c_make(IList, {10, 20, 30, 40, 50}); - - for (c_each(x, IList, L)) - printf("%d ", *x.ref); - puts(""); - // 10 20 30 40 50 - IList_iter it = IList_begin(&L); // ^ - IList_next(&it); - it = IList_erase_at(&L, it); // 10 30 40 50 - // ^ - IList_iter end = IList_end(&L); // - IList_next(&it); - it = IList_erase_range(&L, it, end); // 10 30 - // ^ - printf("list contains:"); - for (c_each(x, IList, L)) - printf(" %d", *x.ref); - puts(""); - - IList_drop(&L); -} diff --git a/src/finchlite/codegen/stc/examples/linkedlists/list_splice.c b/src/finchlite/codegen/stc/examples/linkedlists/list_splice.c deleted file mode 100644 index d29537c7..00000000 --- a/src/finchlite/codegen/stc/examples/linkedlists/list_splice.c +++ /dev/null @@ -1,37 +0,0 @@ -#include - -#define T IList, int -#include - -void print_IList(const char* s, IList list) -{ - printf("%s", s); - for (c_each(i, IList, list)) { - printf(" %d", *i.ref); - } - puts(""); -} - -int main(void) -{ - IList list1 = c_make(IList, {1, 2, 3, 4, 5}); - IList list2 = c_make(IList, {10, 20, 30, 40, 50}); - - print_IList("list1:", list1); - print_IList("list2:", list2); - - IList_iter it = IList_advance(IList_begin(&list1), 2); - it = IList_splice(&list1, it, &list2); - - puts("After splice"); - print_IList("list1:", list1); - print_IList("list2:", list2); - - IList_splice_range(&list2, IList_begin(&list2), &list1, it, IList_end(&list1)); - - puts("After splice_range"); - print_IList("list1:", list1); - print_IList("list2:", list2); - - c_drop(IList, &list1, &list2); -} diff --git a/src/finchlite/codegen/stc/examples/linkedlists/lists.c b/src/finchlite/codegen/stc/examples/linkedlists/lists.c deleted file mode 100644 index 3e403b4e..00000000 --- a/src/finchlite/codegen/stc/examples/linkedlists/lists.c +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include -#include -#include - -#define T DList, double, (c_use_cmp) -#include - -int main(void) { - const int n = 3000000; - DList list = {0}; - - crand64_seed(1234567); - int m = 0; - for (c_range(n)) - DList_push_back(&list, crand64_real()*n + 100), ++m; - - printf("sum of %d: ", m); - double sum = 0.0; - c_filter(DList, list, sum += *value); - printf("%f\n", sum); - - // Print 10 first items using c_filter: - c_filter(DList, list, true - && c_flt_take(10) - && printf("%4d: %10f\n", c_flt_getcount(), *value)); - - puts("sort:"); - DList_sort(&list); // qsort O(n*log n) - - c_filter(DList, list, true - && c_flt_take(10) - && printf("%4d: %10f\n", c_flt_getcount(), *value)); - - DList_drop(&list); - list = c_make(DList, {10, 20, 30, 40, 30, 50}); - - printf("List: "); - for (c_each(i, DList, list)) - printf(" %g", *i.ref); - puts(""); - - const double* v = DList_find(&list, 30).ref; - printf("Found: %g\n", *v); - - DList_remove(&list, 30); - DList_insert_at(&list, DList_begin(&list), 5); // same as push_front() - DList_push_front(&list, 2023); - DList_push_back(&list, 2024); - - printf("Full: "); - for (c_each(i, DList, list)) - printf(" %g", *i.ref); - - printf("\nTail: "); - DList_iter it = DList_begin(&list); - - for (c_each(i, DList, DList_advance(it, 4), DList_end(&list))) - printf(" %g", *i.ref); - puts(""); - - DList_drop(&list); -} diff --git a/src/finchlite/codegen/stc/examples/linkedlists/meson.build b/src/finchlite/codegen/stc/examples/linkedlists/meson.build deleted file mode 100644 index 3e56e45e..00000000 --- a/src/finchlite/codegen/stc/examples/linkedlists/meson.build +++ /dev/null @@ -1,18 +0,0 @@ -foreach sample : [ - 'intrusive', - 'list_erase', - 'lists', - 'list_splice', - 'new_list', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'list', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/linkedlists/new_list.c b/src/finchlite/codegen/stc/examples/linkedlists/new_list.c deleted file mode 100644 index 7b6c52a5..00000000 --- a/src/finchlite/codegen/stc/examples/linkedlists/new_list.c +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -declare_list(list_i32, int32_t); -declare_list(list_pnt, struct Point); - -typedef struct { - list_i32 intlist; - list_pnt pntlist; -} MyStruct; - -#define T list_i32, int32_t, (c_declared) -#include - -typedef struct Point { int x, y; } Point; -int point_cmp(const Point* a, const Point* b) { - int c = a->x - b->x; - return c ? c : a->y - b->y; -} - -#define T list_pnt, Point, (c_declared) -#define i_cmp point_cmp -#include - -// use < and == operators for comparison -#define T list_float, float, (c_use_cmp) -#include - -void MyStruct_drop(MyStruct* s); - -// exclude cloning support because of class/drop: -#define T MyList, MyStruct, (c_keyclass | c_no_clone) -#include - -void MyStruct_drop(MyStruct* s) { - list_i32_drop(&s->intlist); - list_pnt_drop(&s->pntlist); -} - - -int main(void) -{ - MyStruct my = {0}; - list_i32_push_back(&my.intlist, 123); - list_pnt_push_back(&my.pntlist, c_literal(Point){123, 456}); - MyStruct_drop(&my); - - list_pnt plist = c_make(list_pnt, {{42, 14}, {32, 94}, {62, 81}}); - list_pnt_sort(&plist); - - for (c_each_item(i, list_pnt, plist)) - printf(" (%d %d)", i->x, i->y); - puts(""); - list_pnt_drop(&plist); - - - list_float flist = c_make(list_float, {123.3f, 321.2f, -32.2f, 78.2f}); - list_float_sort(&flist); - - for (c_each_item(i, list_float, flist)) - printf(" %g", (double)*i); - - puts(""); - list_float_drop(&flist); -} diff --git a/src/finchlite/codegen/stc/examples/make.sh b/src/finchlite/codegen/stc/examples/make.sh deleted file mode 100755 index 58b5fc18..00000000 --- a/src/finchlite/codegen/stc/examples/make.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh - -#set -e - -if [ "$(uname)" = 'Linux' ]; then - sanitize='-fsanitize=address -fsanitize=undefined -fsanitize-trap' - clibs='-lm' # -pthread - oflag='-o ' -fi -common="-std=c99 -Wpedantic -Wall -Werror" -#cc=clang; cflags="-s -O3 $common" -cc=gcc; cflags="-s -O3 $common" -#cc=gcc; cflags="-g $sanitize $common" -#cc=gcc; cflags="-x c++ -std=c++17 -O2 -s -DSTC_IMPLEMENT -Di_import" -#cc=tcc; cflags="-std=c99" -#cc=cl; cflags="-nologo -O2 -MD -W3 -std:c11 -wd4003" -#cc=cl; cflags="-nologo -c -TP -std:c++20 -wd4003 -DSTC_IMPLEMENT -Di_import" - -if [ "$cc" = "cl" ]; then - oflag='/Fe:' -else - oflag='-o ' -fi - -run=0 -if [ "$1" = '-h' -o "$1" = '--help' ]; then - echo usage: runall.sh [-run] [compiler + options] - exit -fi -if [ "$1" = '-run' ]; then - run=1 - shift -fi -if [ ! -z "$1" ] ; then - comp="$@" -else - comp="$cc $cflags" -fi - -INC= -#INC=-I../include -#INC=-I../../stcsingle -#CPATH= -if [ $run = 0 ] ; then - for i in */*.c ; do - out=$(basename $i .c).exe - #out=$(dirname $i)/$(basename $i .c).exe - #echo $comp -I../../../stcsingle $i $clibs $oflag$out - echo $comp $INC $i $clibs $oflag$out - #$comp $INC $i $clibs $oflag$out -lstc - $comp $INC $i $clibs $oflag$out -I../include -DSTC_STATIC - done -else - for i in */*.c ; do - out=$(basename $i .c).exe - #out=$(dirname $i)/$(basename $i .c).exe - echo $comp $INC $i $clibs $oflag$out - $comp $INC $i $clibs $oflag$out -lstc - if [ -f $out ]; then ./$out; fi - done -fi - -#rm -f a.out *.o *.obj # *.exe diff --git a/src/finchlite/codegen/stc/examples/meson.build b/src/finchlite/codegen/stc/examples/meson.build deleted file mode 100644 index e38d5188..00000000 --- a/src/finchlite/codegen/stc/examples/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -examples = get_option('examples').enable_auto_if(root) - -if examples.enabled() - example_deps = [ - stc_dep, - cc.find_library('m', required: false), - ] - subdir('algorithms') - subdir('bitsets') - subdir('coroutines') - subdir('hashmaps') - subdir('linkedlists') - subdir('mixed') - subdir('priorityqueues') - subdir('queues') - subdir('regularexpressions') - subdir('smartpointers') - subdir('sortedmaps') - subdir('spans') - subdir('strings') - subdir('vectors') -endif diff --git a/src/finchlite/codegen/stc/examples/mixed/FMD.c b/src/finchlite/codegen/stc/examples/mixed/FMD.c deleted file mode 100644 index 8c156788..00000000 --- a/src/finchlite/codegen/stc/examples/mixed/FMD.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include -#include - -typedef struct { - cstr fileName; - cstr directory; - isize size; - time_t lastWriteTime; -} FileMetaData; - -enum FMDActive {FMD_fileName, FMD_directory, FMD_size, FMD_lastWriteTime, FMD_LAST}; -typedef struct { enum FMDActive activeField; bool reverse; } FMDVectorSorting; - -int FileMetaData_cmp(const FMDVectorSorting*, const FileMetaData*, const FileMetaData*); -void FileMetaData_drop(FileMetaData*); - -#define T FMDVector, FileMetaData, (c_keyclass | c_no_clone) -#define i_aux FMDVectorSorting -#define i_cmp(x, y) FileMetaData_cmp(&self->aux, x, y) -#include -// -------------- - -int FileMetaData_cmp(const FMDVectorSorting* aux, const FileMetaData* a, const FileMetaData* b) { - int dir = aux->reverse ? -1 : 1; - switch (aux->activeField) { - case FMD_fileName: return dir*cstr_cmp(&a->fileName, &b->fileName); - case FMD_directory: return dir*cstr_cmp(&a->directory, &b->directory); - case FMD_size: return dir*c_default_cmp(&a->size, &b->size); - case FMD_lastWriteTime: return dir*c_default_cmp(&a->lastWriteTime, &b->lastWriteTime); - default:; - } - return 0; -} - -void FileMetaData_drop(FileMetaData* fmd) { - cstr_drop(&fmd->fileName); - cstr_drop(&fmd->directory); -} - -int main(void) { - FMDVector vec = c_make(FMDVector, { - {cstr_from("WScript.cpp"), cstr_from("code/unix"), 3624, 123567}, - {cstr_from("CanvasBackground.cpp"), cstr_from("code/unix/canvas"), 38273, 12398}, - {cstr_from("Brush_test.cpp"), cstr_from("code/tests"), 67236, 7823}, - }); - - vec.aux.reverse = true; - for (c_range_t(enum FMDActive, field, FMD_LAST)) { - vec.aux.activeField = field; - FMDVector_sort(&vec); - - for (c_each_item(e, FMDVector, vec)) { - fmt_println("{:30}{:30}{:10}{:10}", - cstr_str(&e->fileName), cstr_str(&e->directory), - e->size, e->lastWriteTime); - } - puts(""); - } - FMDVector_drop(&vec); -} diff --git a/src/finchlite/codegen/stc/examples/mixed/astar.c b/src/finchlite/codegen/stc/examples/mixed/astar.c deleted file mode 100644 index f2e7534b..00000000 --- a/src/finchlite/codegen/stc/examples/mixed/astar.c +++ /dev/null @@ -1,169 +0,0 @@ -// -// -- An A* pathfinder inspired by the excellent tutorial at Red Blob Games -- -// -// This is a reimplementation of the CTL example to STC: -// https://github.com/glouw/ctl/blob/master/examples/astar.c -// https://www.redblobgames.com/pathfinding/a-star/introduction.html -#include -#include - -typedef struct -{ - int x; - int y; - int priorty; - int width; -} -point; - -point -point_init(int x, int y, int width) -{ - return c_literal(point){ x, y, 0, width }; -} - -int -point_cmp_priority(const point* a, const point* b) -{ - return c_default_cmp(&a->priorty, &b->priorty); -} - -int -point_equal(const point* a, const point* b) -{ - return a->x == b->x && a->y == b->y; -} - -point -point_from(const cstr* maze, const char* c, int width) -{ - int index = (int)cstr_find(maze, c); - return point_init(index % width, index / width, width); -} - -int -point_index(const point* p) -{ - return p->x + p->width * p->y; -} - -int -point_key_cmp(const point* a, const point* b) -{ - int i = point_index(a); - int j = point_index(b); - return (i == j) ? 0 : (i < j) ? -1 : 1; -} - -#define T pqueue_pnt, point -#define i_cmp point_cmp_priority -#include - -#define T deque_pnt, point -#include - -#define T smap_pcost, point,int -#define i_cmp point_key_cmp -#include - -#define T smap_pstep, point,point -#define i_cmp point_key_cmp -#include - - -deque_pnt -astar(cstr* maze, int width) -{ - deque_pnt ret_path = {0}; - - pqueue_pnt front = {0}; - smap_pstep from = {0}; - smap_pcost costs = {0}; - c_defer( - pqueue_pnt_drop(&front), - smap_pstep_drop(&from), - smap_pcost_drop(&costs) - ){ - point start = point_from(maze, "@", width); - point goal = point_from(maze, "!", width); - smap_pcost_insert(&costs, start, 0); - pqueue_pnt_push(&front, start); - while (!pqueue_pnt_is_empty(&front)) - { - point current = *pqueue_pnt_top(&front); - pqueue_pnt_pop(&front); - if (point_equal(¤t, &goal)) - break; - point deltas[] = { - { -1, +1, 0, width }, { 0, +1, 0, width }, { 1, +1, 0, width }, - { -1, 0, 0, width }, /* ~ ~ ~ ~ ~ ~ ~ */ { 1, 0, 0, width }, - { -1, -1, 0, width }, { 0, -1, 0, width }, { 1, -1, 0, width }, - }; - for (size_t i = 0; i < c_countof(deltas); i++) - { - point delta = deltas[i]; - point next = point_init(current.x + delta.x, current.y + delta.y, width); - int new_cost = *smap_pcost_at(&costs, current); - if (cstr_str(maze)[point_index(&next)] != '#') - { - const smap_pcost_value *cost = smap_pcost_get(&costs, next); - if (cost == NULL || new_cost < cost->second) - { - smap_pcost_insert(&costs, next, new_cost); - next.priorty = new_cost + abs(goal.x - next.x) + abs(goal.y - next.y); - pqueue_pnt_push(&front, next); - smap_pstep_insert(&from, next, current); - } - } - } - } - point current = goal; - while (!point_equal(¤t, &start)) - { - deque_pnt_push_front(&ret_path, current); - current = *smap_pstep_at(&from, current); - } - deque_pnt_push_front(&ret_path, start); - } - return ret_path; -} - -int -main(void) -{ - cstr maze = cstr_lit( - "#########################################################################\n" - "# # # # # # #\n" - "# # ######### # ##### ######### ##### ##### ##### # ! #\n" - "# # # # # # # # # #\n" - "######### # ######### ######### ##### # # # ######### #\n" - "# # # # # # # # # # #\n" - "# # ############# # # ######### ##### # ######### # #\n" - "# # # # # # # # # #\n" - "# ############# ##### ##### # ##### ######### # ##### #\n" - "# # # # # # # # # #\n" - "# ##### ##### # ##### # ######### # # # #############\n" - "# # # # # # # # # # # #\n" - "############# # # # ######### # ##### # ##### ##### #\n" - "# # # # # # # # # #\n" - "# ##### # ######### ##### # ##### ##### ############# #\n" - "# # # # # # # # # #\n" - "# # ######### # ##### ######### # # ############# # #\n" - "# # # # # # # # # # #\n" - "# ######### # # # ##### ######### ######### # #########\n" - "# # # # # # # # # #\n" - "# @ # ##### ##### ##### ######### ##### # ######### # #\n" - "# # # # # # #\n" - "#########################################################################\n" - ); - int width = (int)cstr_find(&maze, "\n") + 1; - deque_pnt ret_path = astar(&maze, width); - - for (c_each(it, deque_pnt, ret_path)) - cstr_data(&maze)[point_index(it.ref)] = 'x'; - - printf("%s", cstr_str(&maze)); - - deque_pnt_drop(&ret_path); - cstr_drop(&maze); -} diff --git a/src/finchlite/codegen/stc/examples/mixed/aux_alloc.c b/src/finchlite/codegen/stc/examples/mixed/aux_alloc.c deleted file mode 100644 index 1e62dda1..00000000 --- a/src/finchlite/codegen/stc/examples/mixed/aux_alloc.c +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include "myalloc.h" - -#define T List, double, (c_use_eq) -#define i_aux MyAlloc* // define an auxiliary field `aux` in the List -#define i_allocator my // explicitly define allocator prefix. -#include - -#define T ListDeque, List, (c_keyclass | c_use_eq) -// Shorthand for defining both i_aux AND i_allocator as above, in one line: -#define i_aux MyAlloc*, my -#include - -int main(void) -{ - MyAlloc myalloc = {.bytes=0}; - List* v; - ListDeque store_a = {.aux=&myalloc}; // All containers in STC can be initialized with {0}. - - v = ListDeque_push(&store_a, (List){.aux=&myalloc}); // push() returns a pointer to the new element in vec. - List_push(v, 100.0); - List_push(v, 200.0); - - v = ListDeque_push(&store_a, (List){.aux=&myalloc}); - List_push(v, 300.0); - List_push(v, 400.0); - - printf("alloc: %d\n", (int)myalloc.bytes); - ListDeque store_b = {.aux=&myalloc}; - - v = ListDeque_push(&store_b, (List){.aux=&myalloc}); - List_push(v, 10.0); - List_push(v, 20.0); - - v = ListDeque_push(&store_b, (List){.aux=&myalloc}); - List_push(v, 30.0); - List_push(v, 40.0); - - printf("store_a == store_b is %s.\n", ListDeque_eq(&store_a, &store_b) ? "true" : "false"); - printf("alloc: %d\n", (int)myalloc.bytes); - - ListDeque store_c = ListDeque_clone(store_a); // Make a deep-copy, using myalloc. - - for (c_each(i, ListDeque, store_c)) // Loop through the cloned deque - for (c_each(j, List, *i.ref)) - printf(" %g", *j.ref); - printf("\nalloc: %d\n", (int)myalloc.bytes); - - c_drop(ListDeque, &store_a, &store_b, &store_c); // Free all 9 storages. - printf("alloc: %d\n", (int)myalloc.bytes); -} diff --git a/src/finchlite/codegen/stc/examples/mixed/complex.c b/src/finchlite/codegen/stc/examples/mixed/complex.c deleted file mode 100644 index 4349333f..00000000 --- a/src/finchlite/codegen/stc/examples/mixed/complex.c +++ /dev/null @@ -1,52 +0,0 @@ - -// Define similar c++ data types: -// -// using FloatStack = std::stack; -// using StackList = std::forward_list; -// using ListMap = std::unordered_map; -// using MapMap = std::unordered_map; -#include - -#define T FloatStack, float -#define i_keydrop(p) printf("drop %g\n", *p) -#define i_keyclone(v) v // only because i_keydrop was defined -#include - -// container as elements is "class"; has _clone() and _drop() "members" -#define T StackList, FloatStack, (c_keyclass) -#include - -// same, but StackList is the mapped value type, not the key: -#define T ListMap, int, StackList, (c_valclass) -#include - -// cstr is "pro"; has _clone, _drop, _cmp, _hash, _toraw, and _from. -#define T MapMap, cstr, ListMap, (c_keypro | c_valclass) -#include - - -int main(void) -{ - MapMap mmap = {0}; - - // Put in some data in the structures - ListMap* lmap = &MapMap_emplace(&mmap, "first", ListMap_init()).ref->second; - StackList* list = &ListMap_insert(lmap, 42, StackList_init()).ref->second; - FloatStack* stack = StackList_push_back(list, FloatStack_with_size(10, 42)); - stack->data[3] = 3.1415927f; - - // Access the data entry - const ListMap* lmap_p = MapMap_at(&mmap, "first"); - const StackList* list_p = ListMap_at(lmap_p, 42); - const FloatStack* stack_p = StackList_back(list_p); - - printf("value is: %g\n", - stack_p->data[3] // pi - ); - printf("directly: %g\n", - StackList_back(ListMap_at(MapMap_at(&mmap, "first"), 42))->data[3] // pi - ); - - // Free everything - MapMap_drop(&mmap); -} diff --git a/src/finchlite/codegen/stc/examples/mixed/convert.c b/src/finchlite/codegen/stc/examples/mixed/convert.c deleted file mode 100644 index 3f2d38f0..00000000 --- a/src/finchlite/codegen/stc/examples/mixed/convert.c +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include - -#define i_keypro cstr // key = cstr -#define i_valpro cstr -#include - -#define i_keypro cstr -#include - -#define i_keypro cstr -#include - -int main(void) -{ - hmap_cstr map = {0}, mclone = {0}; - vec_cstr keys = {0}, values = {0}; - list_cstr list = {0}; - c_defer( - hmap_cstr_drop(&map), - hmap_cstr_drop(&mclone), - vec_cstr_drop(&keys), - vec_cstr_drop(&values), - list_cstr_drop(&list) - ){ - map = c_make(hmap_cstr, { - {"green", "#00ff00"}, - {"blue", "#0000ff"}, - {"yellow", "#ffff00"}, - }); - - puts("MAP:"); - c_filter(hmap_cstr, map, - printf(" %s: %s\n", cstr_str(&value->first), cstr_str(&value->second))); - - puts("\nCLONE MAP:"); - mclone = hmap_cstr_clone(map); - // print - c_filter(hmap_cstr, mclone, - printf(" %s: %s\n", cstr_str(&value->first), cstr_str(&value->second))); - - puts("\nCOPY MAP TO VECS:"); - c_filter(hmap_cstr, mclone, - (vec_cstr_push(&keys, cstr_clone(value->first)), - vec_cstr_push(&values, cstr_clone(value->second)))); - // print both keys and values zipped - c_filter_zip(vec_cstr, keys, values, - printf(" %s: %s\n", cstr_str(value1), cstr_str(value2))); - - puts("\nCOPY VEC TO LIST:"); - c_copy_to(list_cstr, &list, vec_cstr, keys); - // print - c_filter(list_cstr, list, printf(" %s\n", cstr_str(value))); - - puts("\nCOPY VEC AND LIST TO MAP:"); - hmap_cstr_clear(&map); - c_filter_zip(vec_cstr, values, list_cstr, list, - hmap_cstr_emplace(&map, cstr_str(value1), cstr_str(value2))); - // print inverted map - c_filter(hmap_cstr, map, - printf(" %s: %s\n", cstr_str(&value->first), cstr_str(&value->second))); - } -} diff --git a/src/finchlite/codegen/stc/examples/mixed/demos.c b/src/finchlite/codegen/stc/examples/mixed/demos.c deleted file mode 100644 index d7617ee9..00000000 --- a/src/finchlite/codegen/stc/examples/mixed/demos.c +++ /dev/null @@ -1,190 +0,0 @@ -#include - -void stringdemo1(void) -{ - cstr cs = cstr_lit("one-nine-three-seven-five"); - printf("%s.\n", cstr_str(&cs)); - - cstr_insert(&cs, 3, "-two"); - printf("%s.\n", cstr_str(&cs)); - - cstr_erase(&cs, 7, 5); // -nine - printf("%s.\n", cstr_str(&cs)); - - cstr_replace_nfirst(&cs, "seven", "four", 1); - printf("%s.\n", cstr_str(&cs)); - - cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs))); - printf("%s.\n", cstr_str(&cs)); - - printf("find \"four\": %s\n", cstr_str(&cs) + cstr_find(&cs, "four")); - - // reassign: - cstr_assign(&cs, "one two three four five six seven"); - cstr_append(&cs, " eight"); - printf("append: %s\n", cstr_str(&cs)); - - cstr_drop(&cs); -} - -#define T Vec64, long long -#include - -void vectordemo1(void) -{ - Vec64 bignums = Vec64_with_capacity(11); - - for (int i = 10; i <= 100; i += 10) - Vec64_push(&bignums, i * i); - - printf("erase - %d: %lld\n", 3, bignums.data[3]); - Vec64_erase_n(&bignums, 3, 1); // erase index 3 - - Vec64_pop(&bignums); // erase the last - Vec64_erase_n(&bignums, 0, 1); // erase the first - - for (c_range(i, Vec64_size(&bignums))) { - printf("%d: %lld\n", (int)i, bignums.data[i]); - } - - Vec64_drop(&bignums); -} - -#define T Strvec, cstr, (c_keypro | c_use_cmp) -#include - -void vectordemo2(void) -{ - Strvec names = {0}; - Strvec_emplace_back(&names, "Mary"); - Strvec_emplace_back(&names, "Joe"); - Strvec_emplace_back(&names, "Chris"); - - cstr_assign(&names.data[1], "Jane"); // replace Joe - printf("names[1]: %s\n", cstr_str(&names.data[1])); - - Strvec_sort(&names); // Sort the array - - for (c_each(i, Strvec, names)) - printf("sorted: %s\n", cstr_str(i.ref)); - - Strvec_drop(&names); -} - -#define T Intlist, int, (c_use_cmp) -#include - -void listdemo1(void) -{ - Intlist nums = {0}, nums2 = {0}; - for (int i = 0; i < 10; ++i) - Intlist_push_back(&nums, i); - for (int i = 100; i < 110; ++i) - Intlist_push_back(&nums2, i); - - /* splice nums2 to front of nums */ - Intlist_splice(&nums, Intlist_begin(&nums), &nums2); - for (c_each(i, Intlist, nums)) - printf("spliced: %d\n", *i.ref); - puts(""); - - *Intlist_find(&nums, 104).ref += 50; - Intlist_remove(&nums, 103); - - Intlist_iter it = Intlist_begin(&nums); - Intlist_erase_range(&nums, Intlist_advance(it, 5), Intlist_advance(it, 15)); - Intlist_pop_front(&nums); - Intlist_push_back(&nums, 99); - - Intlist_sort(&nums); - - for (c_each(i, Intlist, nums)) - printf("sorted: %d\n", *i.ref); - - c_drop(Intlist, &nums, &nums2); -} - -#define T hset_int, int -#include - -void setdemo1(void) -{ - hset_int nums = {0}; - hset_int_insert(&nums, 8); - hset_int_insert(&nums, 11); - - for (c_each(i, hset_int, nums)) - printf("set: %d\n", *i.ref); - hset_int_drop(&nums); -} - -#define T Intmap, int, int -#include - -void mapdemo1(void) -{ - Intmap nums = {0}; - Intmap_insert(&nums, 8, 64); - Intmap_insert(&nums, 11, 121); - - printf("val 8: %d\n", *Intmap_at(&nums, 8)); - Intmap_drop(&nums); -} - -#define T SImap, cstr, int, (c_keypro) -#include - -void mapdemo2(void) -{ - SImap nums = {0}; - SImap_put(&nums, "Hello", 64); - SImap_put(&nums, "Groovy", 121); - SImap_put(&nums, "Groovy", 200); // overwrite previous - - // iterate the map: - for (SImap_iter i = SImap_begin(&nums); i.ref; SImap_next(&i)) - printf("long: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); - - // or rather use the short form: - for (c_each_kv(k, v, SImap, nums)) - printf("short: %s: %d\n", cstr_str(k), *v); - - SImap_drop(&nums); -} - -#define T Strmap, cstr, cstr, (c_keypro|c_valpro) -#include - -void mapdemo3(void) -{ - Strmap table = {0}; - Strmap_emplace(&table, "Map", "test"); - Strmap_emplace(&table, "Make", "my"); - Strmap_emplace(&table, "Sunny", "day"); - - Strmap_iter it = Strmap_find(&table, "Make"); - for (c_each_kv(k, v, Strmap, table)) - printf("entry: %s: %s\n", cstr_str(k), cstr_str(v)); - - printf("size %d: remove: Make: %s\n", (int)Strmap_size(&table), cstr_str(&it.ref->second)); - //Strmap_erase(&table, "Make"); - Strmap_erase_at(&table, it); - - printf("size %d\n", (int)Strmap_size(&table)); - for (c_each_kv(k, v, Strmap, table)) - printf("entry: %s: %s\n", cstr_str(k), cstr_str(v)); - - Strmap_drop(&table); // frees key and value cstrs, and hash table. -} - -int main(void) -{ - printf("\nSTRINGDEMO1\n"); stringdemo1(); - printf("\nVECTORDEMO1\n"); vectordemo1(); - printf("\nVECTORDEMO2\n"); vectordemo2(); - printf("\nLISTDEMO1\n"); listdemo1(); - printf("\nSETDEMO1\n"); setdemo1(); - printf("\nMAPDEMO1\n"); mapdemo1(); - printf("\nMAPDEMO2\n"); mapdemo2(); - printf("\nMAPDEMO3\n"); mapdemo3(); -} diff --git a/src/finchlite/codegen/stc/examples/mixed/inits.c b/src/finchlite/codegen/stc/examples/mixed/inits.c deleted file mode 100644 index 88f8d79f..00000000 --- a/src/finchlite/codegen/stc/examples/mixed/inits.c +++ /dev/null @@ -1,97 +0,0 @@ -#include - -#define T IdMap, int, cstr, (c_valpro) // Map of int => cstr -#include - -#define T NationMap, cstr, int, (c_keypro) // Map of cstr => int -#include - -typedef struct {int x, y;} IPair; -inline static int IPair_cmp(const IPair* a, const IPair* b) { - int c = c_default_cmp(&a->x, &b->x); - return c ? c : c_default_cmp(&a->y, &b->y); -} - -#define T vec_ip, IPair, (c_cmpclass) -#include - -#define T list_ip, IPair, (c_cmpclass) -#include - -#define T PriorityQ, float -#include - -int main(void) -{ - // VEC FLOAT / PRIORITY QUEUE - - PriorityQ floats = {0}; - const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f}; - - // PRIORITY QUEUE - for (c_range(i, c_countof(nums))) - PriorityQ_push(&floats, nums[i]); - - puts("\npop and show high priorites first:"); - while (! PriorityQ_is_empty(&floats)) { - printf("%.1f ", (double)*PriorityQ_top(&floats)); - PriorityQ_pop(&floats); - } - puts("\n"); - PriorityQ_drop(&floats); - - // CMAP ID - - int year = 2020; - IdMap idnames = {0}; - IdMap_emplace(&idnames, 100, "Hello"); - IdMap_insert(&idnames, 110, cstr_lit("World")); - IdMap_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year)); - - for (c_each_kv(k, v, IdMap, idnames)) - printf("%d: %s\n", *k, cstr_str(v)); - puts(""); - IdMap_drop(&idnames); - - // CMAP CNT - - NationMap countries = c_make(NationMap, { - {"Norway", 100}, - {"Denmark", 50}, - {"Iceland", 10}, - {"Belgium", 10}, - {"Italy", 10}, - {"Germany", 10}, - {"Spain", 10}, - {"France", 10}, - }); - NationMap_emplace(&countries, "Greenland", 0).ref->second += 20; - NationMap_emplace(&countries, "Sweden", 0).ref->second += 20; - NationMap_emplace(&countries, "Norway", 0).ref->second += 20; - NationMap_emplace(&countries, "Finland", 0).ref->second += 20; - - for (c_each_kv(country, health, NationMap, countries)) - printf("%s: %d\n", cstr_str(country), *health); - puts(""); - NationMap_drop(&countries); - - // CVEC PAIR - - vec_ip pairs1 = c_make(vec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); - vec_ip_sort(&pairs1); - - for (c_each_item(e, vec_ip, pairs1)) - printf("(%d %d) ", e->x, e->y); - puts(""); - vec_ip_drop(&pairs1); - - // CLIST PAIR - - list_ip pairs2 = c_make(list_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); - list_ip_sort(&pairs2); - - for (c_each_item(e, list_ip, pairs2)) - printf("(%d %d) ", e->x, e->y); - puts(""); - list_ip_drop(&pairs2); -} diff --git a/src/finchlite/codegen/stc/examples/mixed/meson.build b/src/finchlite/codegen/stc/examples/mixed/meson.build deleted file mode 100644 index e9d71968..00000000 --- a/src/finchlite/codegen/stc/examples/mixed/meson.build +++ /dev/null @@ -1,19 +0,0 @@ -foreach sample : [ - 'astar', - 'complex', - 'convert', - 'demos', - 'FMD', - 'inits', - 'read', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/mixed/myalloc.h b/src/finchlite/codegen/stc/examples/mixed/myalloc.h deleted file mode 100644 index 04678d06..00000000 --- a/src/finchlite/codegen/stc/examples/mixed/myalloc.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MyAlloc_INCLUDED -#define MyAlloc_INCLUDED - -#include -#include - -typedef struct { - isize bytes; -} MyAlloc; - -static inline void* MyMalloc(MyAlloc* m, isize sz) - { m->bytes += sz; return c_malloc(sz); } - -static inline void* MyCalloc(MyAlloc* m, isize nitems, isize item_sz) - { m->bytes += nitems * item_sz; return c_calloc(nitems, item_sz); } - -static inline void* MyRealloc(MyAlloc* m, void* p, isize old_sz, isize sz) - { m->bytes += sz - old_sz; return c_realloc(p, old_sz, sz); } - -static inline void MyFree(MyAlloc* m, void* p, isize sz) - { m->bytes -= sz; c_free(p, sz); } - -#define my_malloc(sz) MyMalloc(self->aux, sz) -#define my_calloc(nitems, item_sz) MyCalloc(self->aux, nitems, item_sz) -#define my_realloc(p, old_sz, sz) MyRealloc(self->aux, p, old_sz, sz) -#define my_free(p, sz) MyFree(self->aux, p, sz) - -#endif - diff --git a/src/finchlite/codegen/stc/examples/mixed/read.c b/src/finchlite/codegen/stc/examples/mixed/read.c deleted file mode 100644 index e32b3091..00000000 --- a/src/finchlite/codegen/stc/examples/mixed/read.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include - -#define i_keypro cstr -#include - -vec_cstr read_file(const char* name) -{ - vec_cstr vec = {0}; - c_with (FILE* f = fopen(name, "r"), f != NULL, fclose(f)) - c_with (cstr line = {0}, cstr_drop(&line)) - while (cstr_getline(&line, f)) - vec_cstr_push(&vec, cstr_clone(line)); - return vec; -} - -int main(void) -{ - int n = 0; - c_with (vec_cstr vec = read_file(__FILE__), vec_cstr_drop(&vec)) - for (c_each(i, vec_cstr, vec)) - printf("%5d: %s\n", ++n, cstr_str(i.ref)); - - if (errno) - printf("error: read_file(" __FILE__ "). errno: %d\n", errno); -} diff --git a/src/finchlite/codegen/stc/examples/priorityqueues/functor.c b/src/finchlite/codegen/stc/examples/priorityqueues/functor.c deleted file mode 100644 index 616cf1d6..00000000 --- a/src/finchlite/codegen/stc/examples/priorityqueues/functor.c +++ /dev/null @@ -1,55 +0,0 @@ -// Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue -// Example of per-instance less-function on a single priority queue type -// - -#include - -#define T IPQueue, int -#define i_aux struct { bool(*less)(const int*, const int*); } -#define i_less(x, y) self->aux.less(x, y) -#include - -void print_queue(const char* name, IPQueue q) { - // Make a clone, because there is no way to traverse - // priority queues ordered without erasing the queue. - - // NB! A clone function for the extended container struct is provided. - // It assumes that the extended member(s) are POD/trivial type(s). - IPQueue copy = IPQueue_clone(q); - printf("%s: \t", name); - while (!IPQueue_is_empty(©)) { - printf("%d ", IPQueue_pull(©)); - } - puts(""); - - IPQueue_drop(©); -} - -static bool int_less(const int* x, const int* y) { return *x < *y; } -static bool int_greater(const int* x, const int* y) { return *x > *y; } -static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); } - -int main(void) -{ - const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_countof(data); - printf("data: \t"); - for (c_range(i, n)) printf("%d ", data[i]); - puts(""); - - // Max priority queue - IPQueue q1 = {.aux={.less=int_less}}; - IPQueue_put_n(&q1, data, n); - print_queue("q1", q1); - - // Min priority queue - IPQueue minq1 = {.aux={.less=int_greater}}; - IPQueue_put_n(&minq1, data, n); - print_queue("minq1", minq1); - - // Using lambda to compare elements. - IPQueue q5 = {.aux={.less=int_lambda}}; - IPQueue_put_n(&q5, data, n); - print_queue("q5", q5); - - c_drop(IPQueue, &q1, &minq1, &q5); -} diff --git a/src/finchlite/codegen/stc/examples/priorityqueues/meson.build b/src/finchlite/codegen/stc/examples/priorityqueues/meson.build deleted file mode 100644 index 2ac3c70c..00000000 --- a/src/finchlite/codegen/stc/examples/priorityqueues/meson.build +++ /dev/null @@ -1,16 +0,0 @@ -foreach sample : [ - 'functor', - 'new_pqueue', - 'priority', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'pqueue', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/priorityqueues/new_pqueue.c b/src/finchlite/codegen/stc/examples/priorityqueues/new_pqueue.c deleted file mode 100644 index e316393c..00000000 --- a/src/finchlite/codegen/stc/examples/priorityqueues/new_pqueue.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -typedef struct Point { int x, y; } Point; - -#define T PointQ, Point -#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) -#include - - -int main(void) -{ - PointQ pqueue = c_make(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}}); - // print - for (; !PointQ_is_empty(&pqueue); PointQ_pop(&pqueue)) - { - const Point *v = PointQ_top(&pqueue); - printf(" (%d,%d)", v->x, v->y); - } - puts(""); - PointQ_drop(&pqueue); -} diff --git a/src/finchlite/codegen/stc/examples/priorityqueues/priority.c b/src/finchlite/codegen/stc/examples/priorityqueues/priority.c deleted file mode 100644 index 80599c40..00000000 --- a/src/finchlite/codegen/stc/examples/priorityqueues/priority.c +++ /dev/null @@ -1,33 +0,0 @@ - -#include -#include -#include - -#define T PQueue, int -#define i_cmp -c_default_cmp // min-heap (increasing values) -#include - -int main(void) { - int N = 10000000; - crand64 rng = crand64_from((uint64_t)time(NULL)); - PQueue heap = {0}; - - // Push ten million random numbers to priority queue - printf("Push %d numbers\n", N); - for (c_range(N)) - PQueue_push(&heap, crand64_uint_r(&rng, 1) & ((1<<20) - 1)); - - // push some negative numbers too. - for (c_items(i, int, {-231, -32, -873, -4, -343})) - PQueue_push(&heap, *i.ref); - - for (c_range(N)) - PQueue_push(&heap, crand64_uint_r(&rng, 1) & ((1<<20) - 1)); - - puts("Extract the hundred smallest."); - for (c_range(100)) { - printf("%d ", PQueue_pull(&heap)); - } - - PQueue_drop(&heap); -} diff --git a/src/finchlite/codegen/stc/examples/queues/meson.build b/src/finchlite/codegen/stc/examples/queues/meson.build deleted file mode 100644 index cee0b298..00000000 --- a/src/finchlite/codegen/stc/examples/queues/meson.build +++ /dev/null @@ -1,15 +0,0 @@ -foreach sample : [ - 'new_queue', - 'queue', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'queue', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/queues/new_queue.c b/src/finchlite/codegen/stc/examples/queues/new_queue.c deleted file mode 100644 index 2e777506..00000000 --- a/src/finchlite/codegen/stc/examples/queues/new_queue.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include -declare_queue(queue_pnt, struct Point); - -typedef struct Point { int x, y; } Point; -#define T queue_pnt, Point -#define i_declared -#include - -#define T IntQ, int -#include - -int main(void) { - int n = 50000000; - crand64 rng = crand64_from((uint64_t)time(NULL)); - - IntQ Q = {0}; - - // Push 50'000'000 random numbers onto the queue. - for (c_range(n)) - IntQ_push(&Q, crand64_uint_r(&rng, 1) & ((1<<24) - 1)); - - // Push or pop on the queue 50 million times - printf("befor: size %" c_ZI ", capacity %" c_ZI "\n", IntQ_size(&Q), IntQ_capacity(&Q)); - - for (c_range(n)) { - int r = crand64_uint_r(&rng, 1) & ((1<<24) - 1); - if (r & 3) - IntQ_push(&Q, r); - else - IntQ_pop(&Q); - } - - printf("after: size %" c_ZI ", capacity %" c_ZI "\n", IntQ_size(&Q), IntQ_capacity(&Q)); - IntQ_drop(&Q); -} diff --git a/src/finchlite/codegen/stc/examples/queues/queue.c b/src/finchlite/codegen/stc/examples/queues/queue.c deleted file mode 100644 index 030ab529..00000000 --- a/src/finchlite/codegen/stc/examples/queues/queue.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include - -#define T IntQ, int -#include - -int main(void) { - int n = 1000000; - crand64_seed(1234); - - IntQ queue = {0}; - - // Push ten million random numbers onto the queue. - for (c_range(n)) - IntQ_push(&queue, crand64_uint() & ((1 << 20) - 1)); - - // Push or pop on the queue ten million times - printf("%d\n", n); - for (c_range(n)) { // forrange uses initial n only. - int r = (int)crand64_uint() & ((1 << 20) - 1); - if (r & 1) - ++n, IntQ_push(&queue, r); - else - --n, IntQ_pop(&queue); - } - printf("%d, %" c_ZI "\n", n, IntQ_size(&queue)); - - IntQ_drop(&queue); -} diff --git a/src/finchlite/codegen/stc/examples/regularexpressions/meson.build b/src/finchlite/codegen/stc/examples/regularexpressions/meson.build deleted file mode 100644 index c44b1870..00000000 --- a/src/finchlite/codegen/stc/examples/regularexpressions/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -foreach sample : [ - 'regex1', - 'regex2', - 'regex_match', - 'regex_replace', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'cregex', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/regularexpressions/regex1.c b/src/finchlite/codegen/stc/examples/regularexpressions/regex1.c deleted file mode 100644 index 5cc7bda8..00000000 --- a/src/finchlite/codegen/stc/examples/regularexpressions/regex1.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -int main(int argc, char* argv[]) -{ - (void)argv; - if (argc <= 1) { - printf("Usage: regex1 -i\n"); - return 0; - } - cstr input = {0}; - cregex float_expr = {0}; - - int res = cregex_compile(&float_expr, "^[+-]?[0-9]+((\\.[0-9]*)?|\\.[0-9]+)$"); - // Until "q" is given, ask for another number - if (res > 0) while (true) - { - printf("Enter a double precision number (q for quit): "); - cstr_getline(&input, stdin); - - // Exit when the user inputs q - if (cstr_equals(&input, "q")) - break; - - if (cregex_is_match(&float_expr, cstr_str(&input))) - printf("Input is a float\n"); - else - printf("Invalid input : Not a float\n"); - } - - cstr_drop(&input); - cregex_drop(&float_expr); -} diff --git a/src/finchlite/codegen/stc/examples/regularexpressions/regex2.c b/src/finchlite/codegen/stc/examples/regularexpressions/regex2.c deleted file mode 100644 index 0e8e625f..00000000 --- a/src/finchlite/codegen/stc/examples/regularexpressions/regex2.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include - -int main(void) -{ - struct { const char *pattern, *input; } s[] = { - {"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])", - "date: 2024-02-29 leapyear day, christmas eve is on 2022-12-24." - }, - {"(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?", - "https://en.cppreference.com/w/cpp/regex/regex_search" - }, - {"!((abc|123)+)!", "!123abcabc!"}, - {"(\\p{Alpha}+ )+(\\p{Nd}+)", "Großpackung süßigkeiten 199"}, - {"\\p{Han}+", "This is Han: 王明:那是杂志吗?"}, - }; - - cregex re = {0}; - for (c_range(i, c_countof(s))) - { - int res = cregex_compile(&re, s[i].pattern); - if (res < 0) { - printf("error in regex pattern: %d\n", res); - continue; - } - printf("\ninput: %s\n", s[i].input); - - for (c_match(j, &re, s[i].input)) { - for (c_range(k, cregex_captures(&re) + 1)) - printf(" submatch %d: " c_svfmt "\n", (int)k, c_svarg(j.match[k])); - } - } - cregex_drop(&re); -} diff --git a/src/finchlite/codegen/stc/examples/regularexpressions/regex_match.c b/src/finchlite/codegen/stc/examples/regularexpressions/regex_match.c deleted file mode 100644 index 91eb3429..00000000 --- a/src/finchlite/codegen/stc/examples/regularexpressions/regex_match.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include - -#define T Fvec, float -#include - -int main(void) -{ - // Lets find the first sequence of digits in a string - const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour. " - "Around 365.25 days a year, and 52 weeks in a year. " - "Boltzmann const: 1.38064852E-23, is very small. " - "Bohrradius is 5.29177210903e-11, and Avogadros number is 6.02214076e23."; - cregex re = {0}; - Fvec vec = {0}; - - const char* num_pattern = "[+-]?([0-9]*\\.)?\\d+([Ee][+-]?\\d+)?"; - int res = cregex_compile(&re, num_pattern); - printf("%d: %s\n", res, num_pattern); - - // extract and convert all numbers in str to floats - for (c_match(i, &re, str)) - Fvec_push(&vec, (float)atof(i.match[0].buf)); - - for (c_each(i, Fvec, vec)) - printf(" %g\n", (double)*i.ref); - - // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", .flags=CREG_STRIP); - printf("\n%s\n", cstr_str(&nums)); - - cstr_drop(&nums); - cregex_drop(&re); - Fvec_drop(&vec); -} diff --git a/src/finchlite/codegen/stc/examples/regularexpressions/regex_replace.c b/src/finchlite/codegen/stc/examples/regularexpressions/regex_replace.c deleted file mode 100644 index b0a395c2..00000000 --- a/src/finchlite/codegen/stc/examples/regularexpressions/regex_replace.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include - -bool add_10_years(int group, csview match, cstr* out) { - if (group == 1) { // year match - int year; - sscanf(match.buf, "%4d", &year); // scan 4 chars only - cstr_printf(out, "%04d", year + 10); - return true; - } - return false; -} - -int main(void) -{ - const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b"; - const char* input = "start date: 2015-12-31, end date: 2022-02-28"; - - cstr str = {0}; - cregex re = {0}; - c_defer( - cregex_drop(&re), - cstr_drop(&str) - ){ - printf("INPUT: %s\n", input); - - /* replace with a fixed string, extended all-in-one call: */ - cstr_take(&str, cregex_replace_aio(pattern, input, "YYYY-MM-DD")); - printf("fixed: %s\n", cstr_str(&str)); - - /* US date format, and add 10 years to dates: */ - cstr_take(&str, cregex_replace_aio_sv(pattern, csview_from(input), "$1/$3/$2", .xform=add_10_years)); - printf("us+10: %s\n", cstr_str(&str)); - - /* Wrap first date inside []: */ - cstr_take(&str, cregex_replace_aio(pattern, input, "[$0]")); - printf("brack: %s\n", cstr_str(&str)); - - /* Shows how to compile RE separately */ - re = cregex_from(pattern); - if (cregex_captures(&re) == 0) - continue; /* break c_defer */ - - /* European date format. */ - cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); - printf("euros: %s\n", cstr_str(&str)); - - /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", .flags=CREG_STRIP)); - printf("strip: %s\n", cstr_str(&str)); - - /* Wrap all words in ${} */ - cstr_take(&str, cregex_replace_aio("[a-z]+", "52 apples and 31 mangoes", "$${$0}")); - printf("curly: %s\n", cstr_str(&str)); - } -} diff --git a/src/finchlite/codegen/stc/examples/smartpointers/arc_containers.c b/src/finchlite/codegen/stc/examples/smartpointers/arc_containers.c deleted file mode 100644 index b8e90991..00000000 --- a/src/finchlite/codegen/stc/examples/smartpointers/arc_containers.c +++ /dev/null @@ -1,71 +0,0 @@ -// Create a vec and a list of shared pointers to maps, -// and demonstrate sharing and cloning of maps. -#include -#define T Map, cstr, int, (c_keypro) -#define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p)) -#include - -#define T Arc, Map, (c_no_atomic) // non-atomic ref. counted Map -#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) -#include - -#define T Vec, Arc, (c_keypro) // arc is a "pro" type -#include - -#define T List, Arc, (c_keypro) -#include - -int main(void) -{ - Vec vec = {0}; - List list = {0}; - c_defer(Vec_drop(&vec), List_drop(&list)) - { - // POPULATE vec with shared pointers to Maps: - Map *map; - //map = Vec_push(&vec, Arc_from(Map_init()))->get; - map = Vec_emplace(&vec, Map_init())->get; - Map_emplace(map, "Joey", 1990); - Map_emplace(map, "Mary", 1995); - Map_emplace(map, "Joanna", 1992); - - map = Vec_emplace(&vec, Map_init())->get; - Map_emplace(map, "Rosanna", 2001); - Map_emplace(map, "Brad", 1999); - Map_emplace(map, "Jack", 1980); - - // POPULATE list: - map = List_emplace_back(&list, Map_init())->get; - Map_emplace(map, "Steve", 1979); - Map_emplace(map, "Rick", 1974); - Map_emplace(map, "Tracy", 2003); - - // Share two Maps from the vec with the list using emplace (clone the arc): - List_push_back(&list, Arc_clone(vec.data[0])); - List_push_back(&list, Arc_clone(vec.data[1])); - - // Clone (deep copy) a Map from the vec to the list - // List will contain two shared and two unshared maps. - map = List_push_back(&list, Arc_from(Map_clone(*vec.data[1].get)))->get; - - // Add one more element to the cloned map: - Map_emplace_or_assign(map, "CLONED", 2021); - - // Add one more element to the shared map: - Map_emplace_or_assign(vec.data[1].get, "SHARED", 2021); - - puts("VEC"); - for (c_each_item(e, Vec, vec)) { - for (c_each_kv(name, year, Map, *e->get)) - printf(" %s:%d", cstr_str(name), *year); - puts(""); - } - - puts("LIST"); - for (c_each_item(e, List, list)) { - for (c_each_kv(name, year, Map, *e->get)) - printf(" %s:%d", cstr_str(name), *year); - puts(""); - } - } -} diff --git a/src/finchlite/codegen/stc/examples/smartpointers/arc_demo.c b/src/finchlite/codegen/stc/examples/smartpointers/arc_demo.c deleted file mode 100644 index 759e0f14..00000000 --- a/src/finchlite/codegen/stc/examples/smartpointers/arc_demo.c +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include - -void int_drop(int* x) { - printf("drop: %d\n", *x); -} - -// arc implements its own clone method using reference counting, -// so 'i_keyclone' is not required to be defined (ignored). - -// Define the Arc, no need for atomic in single thread, enable default int comparisons. -#define T Arc, int, (c_no_atomic| c_use_cmp) -#define i_keydrop int_drop // optional, just to display the elements destroyed -#include // Arc - -#define T Arcset, Arc, (c_keypro) // arc's are "pro" types -#include // Arcset (like: std::set>) - -#define T Arcvec, Arc, (c_keypro| c_use_cmp) -#include // Arcvec (like: std::vector>) - -int main(void) -{ - const int years[] = {2021, 2012, 2022, 2015}; - - Arcvec vec = {0}; - for (c_range(i, c_countof(years))) { - Arcvec_emplace(&vec, years[i]); - // Arcvec_push(&vec, Arc_from(years[i])); // alt. - } - - Arcvec_sort(&vec); - - printf("vec:"); - for (c_each(i, Arcvec, vec)) - printf(" %d", *i.ref->get); - puts(""); - - // add odd numbers from vec to set - Arcset set = {0}; - for (c_each(i, Arcvec, vec)) - if (*i.ref->get & 1) - Arcset_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter. - - // erase the two last elements in vec - Arcvec_pop_back(&vec); - Arcvec_pop_back(&vec); - - printf("vec:"); - for (c_each(i, Arcvec, vec)) printf(" %d", *i.ref->get); - - printf("\nset:"); - for (c_each(i, Arcset, set)) printf(" %d", *i.ref->get); - - Arc p = Arc_clone(vec.data[0]); - printf("\n%d is now owned by %ld objects\n", *p.get, Arc_use_count(p)); - - Arc_drop(&p); - Arcvec_drop(&vec); - Arcset_drop(&set); -} diff --git a/src/finchlite/codegen/stc/examples/smartpointers/arcvec_erase.c b/src/finchlite/codegen/stc/examples/smartpointers/arcvec_erase.c deleted file mode 100644 index cd3341a7..00000000 --- a/src/finchlite/codegen/stc/examples/smartpointers/arcvec_erase.c +++ /dev/null @@ -1,52 +0,0 @@ -#include - -void show_drop(int* x) { printf("drop: %d\n", *x); } - - -// enable sort/search for non-atomic Arc int type -#define T Arc, int, (c_no_atomic | c_use_cmp) -#define i_keydrop show_drop -#include // Shared pointer to int - -// arc is "pro", enable search/sort -#define T Vec, Arc, (c_keypro | c_use_cmp) -#include // Vec: vec - - -int main(void) -{ - Vec vec = c_make(Vec, {2012, 1990, 2012, 2019, 2015}); - printf("elm size: %d\n", (int)sizeof(Arc)); - - // clone the second 2012 and push it back. - // note: cloning make sure that vec.data[2] has ref count 2. - Vec_push(&vec, Arc_clone(vec.data[2])); // => share vec.data[2] - Vec_emplace(&vec, *vec.data[2].get); // => deep-copy vec.data[2] - - printf("vec before erase :"); - for (c_each(i, Vec, vec)) - printf(" %d", *i.ref->get); - - printf("\nerase vec.data[2]; or first matching value depending on compare.\n"); - Vec_iter it; - it = Vec_find(&vec, *vec.data[2].get); - if (it.ref) - Vec_erase_at(&vec, it); - - int year = 2015; - it = Vec_find(&vec, year); // Ok as tmp only. - if (it.ref) - Vec_erase_at(&vec, it); - - printf("vec after erase :"); - for (c_each(i, Vec, vec)) - printf(" %d", *i.ref->get); - - Vec_sort(&vec); - printf("\nvec after sort :"); - for (c_each(i, Vec, vec)) - printf(" %d", *i.ref->get); - - puts("\nDone"); - Vec_drop(&vec); -} diff --git a/src/finchlite/codegen/stc/examples/smartpointers/box.c b/src/finchlite/codegen/stc/examples/smartpointers/box.c deleted file mode 100644 index e621372e..00000000 --- a/src/finchlite/codegen/stc/examples/smartpointers/box.c +++ /dev/null @@ -1,69 +0,0 @@ -/* box: heap allocated boxed type */ -#include - -typedef struct { cstr name, last; } Person; - -Person Person_make(const char* name, const char* last) { - return c_literal(Person){.name = cstr_from(name), .last = cstr_from(last)}; -} - -size_t Person_hash(const Person* a) { - return cstr_hash(&a->name) ^ cstr_hash(&a->last); -} - -int Person_cmp(const Person* a, const Person* b) { - int c = cstr_cmp(&a->name, &b->name); - return c ? c : cstr_cmp(&a->last, &b->last); -} - -Person Person_clone(Person p) { - p.name = cstr_clone(p.name); - p.last = cstr_clone(p.last); - return p; -} - -void Person_drop(Person* p) { - printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); - c_drop(cstr, &p->name, &p->last); -} - -// "class" binds _clone, _drop functions. -// "use_cmp" binds _cmp, _hash functions. -#define T PBox, Person, (c_keyclass | c_use_cmp) -#include - -// box, arc, and cstr types are "pro"-types. -#define T Persons, PBox, (c_keypro) -#include - -int main(void) -{ - Persons vec = {0}; - PBox p = PBox_from(Person_make("Laura", "Palmer")); - PBox q = PBox_clone(p); - cstr_assign(&q.get->name, "Leland"); - - printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); - printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); - - Persons_emplace(&vec, Person_make("Dale", "Cooper")); - Persons_emplace(&vec, Person_make("Audrey", "Home")); - - // NB! Clone/share p and q in the Persons container. - Persons_push(&vec, PBox_clone(p)); - Persons_push(&vec, PBox_clone(q)); - - for (c_each_item(e, Persons, vec)) - printf("%s %s\n", cstr_str(&e->get->name), cstr_str(&e->get->last)); - puts(""); - - // Look-up Audrey! Create a temporary Person for lookup. - Person a = Person_make("Audrey", "Home"); - const PBox *v = Persons_get(&vec, a); // lookup - if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); - - Person_drop(&a); - PBox_drop(&p); - PBox_drop(&q); - Persons_drop(&vec); -} diff --git a/src/finchlite/codegen/stc/examples/smartpointers/box2.c b/src/finchlite/codegen/stc/examples/smartpointers/box2.c deleted file mode 100644 index fe636668..00000000 --- a/src/finchlite/codegen/stc/examples/smartpointers/box2.c +++ /dev/null @@ -1,80 +0,0 @@ -// example: https://doc.rust-lang.org/rust-by-example/std/box.html -#include - -typedef struct { - double x; - double y; -} Point; - -// A Rectangle can be specified by where its top left and bottom right -// corners are in space -typedef struct { - Point top_left; - Point bottom_right; -} Rectangle; - -#define T BoxPoint, Point -#include - -#define T BoxRect, Rectangle -#include - -// Box in box: (box is a "pro" key-type) -#define T BoxBoxPoint, BoxPoint, (c_keypro) -#include - -Point origin(void) { - return c_literal(Point){ .x=1.0, .y=2.0 }; -} - -BoxPoint boxed_origin(void) { - // Allocate this point on the heap, and return a pointer to it - return BoxPoint_from(c_literal(Point){ .x=1.0, .y=2.0 }); -} - - -int main(void) { - // Stack allocated variables - Point point = origin(); - Rectangle rectangle = { - .top_left = origin(), - .bottom_right = { .x=3.0, .y=-4.0 } - }; - - // Heap allocated rectangle - BoxRect boxed_rectangle = BoxRect_from(c_literal(Rectangle){ - .top_left = origin(), - .bottom_right = { .x=3.0, .y=-4.0 } - }); - // The output of functions can be boxed - BoxPoint boxed_point = BoxPoint_from(origin()); - - // Create BoxBoxPoint from either a Point or a BoxPoint: - BoxBoxPoint box_in_a_box = BoxBoxPoint_from(origin()); - - c_defer( - BoxBoxPoint_drop(&box_in_a_box), - BoxPoint_drop(&boxed_point), - BoxRect_drop(&boxed_rectangle) - ){ - printf("box_in_a_box: x = %g\n", BoxBoxPoint_toraw(&box_in_a_box).x); - - printf("Point occupies %d bytes on the stack\n", - (int)sizeof(point)); - printf("Rectangle occupies %d bytes on the stack\n", - (int)sizeof(rectangle)); - - // box size == pointer size - printf("Boxed point occupies %d bytes on the stack\n", - (int)sizeof(boxed_point)); - printf("Boxed rectangle occupies %d bytes on the stack\n", - (int)sizeof(boxed_rectangle)); - printf("Boxed box occupies %d bytes on the stack\n", - (int)sizeof(box_in_a_box)); - - // Copy the data contained in `boxed_point` into `unboxed_point` - Point unboxed_point = *boxed_point.get; - printf("Unboxed point occupies %d bytes on the stack\n", - (int)sizeof(unboxed_point)); - } -} diff --git a/src/finchlite/codegen/stc/examples/smartpointers/map_box.c b/src/finchlite/codegen/stc/examples/smartpointers/map_box.c deleted file mode 100644 index f3c53c93..00000000 --- a/src/finchlite/codegen/stc/examples/smartpointers/map_box.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include - -#define T IBox, long -#include // unique_ptr alike. - -// hashmap of cstr => IBox (both cstr and box are "pro") -#define T Boxmap, cstr, IBox, (c_keypro | c_valpro) -#include - - -int main(void) -{ - Boxmap map = {0}; - - puts("Map cstr => IBox:"); - Boxmap_insert(&map, cstr_lit("Test1"), IBox_make(1)); - Boxmap_insert(&map, cstr_lit("Test2"), IBox_make(2)); - - // Simpler: emplace() implicitly creates cstr from const char* and IBox from long! - Boxmap_emplace(&map, "Test3", 3); - Boxmap_emplace(&map, "Test4", 4); - - for (c_each_kv(name, number, Boxmap, map)) - printf("%s: %ld\n", cstr_str(name), *number->get); - puts(""); - - Boxmap_drop(&map); -} diff --git a/src/finchlite/codegen/stc/examples/smartpointers/map_ptr.c b/src/finchlite/codegen/stc/examples/smartpointers/map_ptr.c deleted file mode 100644 index c7a9b3c3..00000000 --- a/src/finchlite/codegen/stc/examples/smartpointers/map_ptr.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -// box -#define T boxlong, long //, (c_use_cmp) // add if compare is needed -#include - -// hashmap -#define T Magicmap, cstr, boxlong, (c_keypro | c_valpro) -#include - -int main(void) -{ - // c_make() and emplace() implicitly creates cstr from const char* - // and a "boxed long" from long. - Magicmap map = c_make(Magicmap, { - {"just", 10}, - {"some", 20}, - {"random", 30}, - {"words", 40}, - }); - Magicmap_emplace(&map, "another", 100); - - printf("Lookup \"some\": %ld\n\n", *Magicmap_at(&map, "some")->get); - - for (c_each_kv(name, num, Magicmap, map)) { - printf("%s: %ld\n", cstr_str(name), *num->get); - } - - Magicmap_drop(&map); -} diff --git a/src/finchlite/codegen/stc/examples/smartpointers/meson.build b/src/finchlite/codegen/stc/examples/smartpointers/meson.build deleted file mode 100644 index a00facfa..00000000 --- a/src/finchlite/codegen/stc/examples/smartpointers/meson.build +++ /dev/null @@ -1,21 +0,0 @@ -foreach sample : [ - 'arc_containers', - 'arc_demo', - 'arcvec_erase', - 'box2', - 'box', - 'map_box', - 'map_ptr', - 'music_arc', - 'person_arc', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, install: false, - ), - suite: 'arc', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/smartpointers/music_arc.c b/src/finchlite/codegen/stc/examples/smartpointers/music_arc.c deleted file mode 100644 index ffa5f720..00000000 --- a/src/finchlite/codegen/stc/examples/smartpointers/music_arc.c +++ /dev/null @@ -1,96 +0,0 @@ -// shared_ptr-examples.cpp -// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 - -// Advanced example. - -#include -#include - -typedef struct { - cstr artist; - cstr title; -} Song; - -// Make Song a "class" by defining _clone and _drop "members": -Song Song_init(const char* artist, const char* title) - { return (Song){cstr_from(artist), cstr_from(title)}; } - -Song Song_clone(Song s) { - s.artist = cstr_clone(s.artist); - s.title = cstr_clone(s.title); - return s; -} - -void Song_drop(Song* self) { - printf("drop: %s\n", cstr_str(&self->title)); - c_drop(cstr, &self->artist, &self->title); -} - -// Define a keyraw conversion type, SongView: -typedef struct { - const char* artist; - const char* title; -} SongView; - -inline static bool SongView_cmp(const SongView* xw, const SongView* yw) - { int c = strcmp(xw->artist, yw->artist); return c ? c : strcmp(xw->title, yw->title); } - -inline static size_t SongView_hash(const SongView* xw) - { return c_hash_mix(c_hash_str(xw->artist), c_hash_str(xw->title)); } - - -// Define the shared pointer type SongArc and conversion functions to SongView: -// "keyclass" binds Song_clone(), Song_drop() -// "cmpclass" specifies the type/view to convert to/from and binds _cmp, _eq, _hash functions. -#define T SongArc, Song, (c_keyclass | c_use_cmp) // also enable _cmp/_hash for arc cmpclass (SongView). -#define i_cmpclass SongView -#define i_keytoraw(x) ((SongView){.artist=cstr_str(&x->artist), .title=cstr_str(&x->title)}) -#define i_keyfrom(sw) ((Song){.artist=cstr_from(sw.artist), .title=cstr_from(sw.title)}) -#include - -// Create a set of SongArc -#define T SongSet, SongArc, (c_keypro) // arc-type is "pro" -#include - -void example3(void) -{ - SongSet set1 = c_make(SongSet, { - (SongView){"Bob Dylan", "The Times They Are A Changing"}, - (SongView){"Aretha Franklin", "Bridge Over Troubled Water"}, - (SongView){"Thalia", "Entre El Mar y Una Estrella"}, - }); - - SongSet set2 = {0}; - // Share all entries in set1 with set2. Copy arc => share. - c_copy_to(SongSet, &set2, set1); - - // Add a few more SongArcs to set2. - SongSet_emplace(&set2, (SongView){"Bob Dylan", "The Times They Are A Changing"}); - SongSet_emplace(&set2, (SongView){"Michael Jackson", "Billie Jean"}); - - // The previous line is identical to: - // SongSet_insert(&set2, SongArc_make((Song){cstr_lit("Michael Jackson"), cstr_lit("Billie Jean")})); - - // We now have two sets with some shared, some unique entries. - // Remove "Thalia" from set1. Song is not destroyed, there is still one reference in set2: - SongSet_erase(&set1, (SongView){"Thalia", "Entre El Mar y Una Estrella"}); - - int n = 0; - for (c_items(i, SongSet, {set1, set2})) { - printf("SET%d:\n", ++n); - for (c_each(s, SongSet, *i.ref)) - printf(" %s (%s), REFS: %ld\n", cstr_str(&s.ref->get->title), - cstr_str(&s.ref->get->artist), - SongArc_use_count(*s.ref)); - } - const SongArc* found = SongSet_get(&set2, (SongView){"Aretha Franklin", "Bridge Over Troubled Water"}); - if (found) printf("FOUND: %s\n", cstr_str(&found->get->title)); - - c_drop(SongSet, &set1, &set2); -} - - -int main(void) -{ - example3(); -} diff --git a/src/finchlite/codegen/stc/examples/smartpointers/person_arc.c b/src/finchlite/codegen/stc/examples/smartpointers/person_arc.c deleted file mode 100644 index dfc9939f..00000000 --- a/src/finchlite/codegen/stc/examples/smartpointers/person_arc.c +++ /dev/null @@ -1,75 +0,0 @@ -/* box example: heap allocated smart pointer type */ -#include - -// ===== Person: create a "pro" type: -typedef struct { cstr name, last; } Person; -typedef struct { const char *name, *last; } Person_raw; - -Person Person_from(Person_raw raw) - { return (Person){.name = cstr_from(raw.name), .last = cstr_from(raw.last)}; } - -Person_raw Person_toraw(Person* p) - { return (Person_raw){.name = cstr_str(&p->name), .last = cstr_str(&p->last)}; } - -int Person_raw_cmp(const Person_raw* a, const Person_raw* b) { - int c = strcmp(a->name, b->name); - return c ? c : strcmp(a->last, b->last); -} - -size_t Person_raw_hash(const Person_raw* a) - { return c_hash_str(a->name) ^ c_hash_str(a->last); } - -Person Person_clone(Person p) { - p.name = cstr_clone(p.name); - p.last = cstr_clone(p.last); - return p; -} - -void Person_drop(Person* p) { - printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); - c_drop(cstr, &p->name, &p->last); -} -// ===== - -// binds Person_clone, Person_drop, enable search/sort -// Person is a "pro" type (has Person_raw conversion type): -#define T PersArc, Person, (c_keypro | c_use_cmp) -#include - -// Arcs and Boxes are always "pro" types: -#define T Persons, PersArc, (c_keypro | c_use_cmp) -#include - - -int main(void) -{ - Persons vec = {0}; - PersArc laura = PersArc_from((Person_raw){"Laura", "Palmer"}); - PersArc bobby = PersArc_from((Person_raw){"Bobby", "Briggs"}); - - c_defer( - PersArc_drop(&laura), - PersArc_drop(&bobby), - Persons_drop(&vec) - ){ - // Use Persons_emplace() to implicitly call PersArc_from() on the argument: - Persons_emplace(&vec, (Person_raw){"Audrey", "Home"}); - Persons_emplace(&vec, (Person_raw){"Dale", "Cooper"}); - - Persons_push(&vec, PersArc_clone(laura)); - Persons_push(&vec, PersArc_clone(bobby)); - - for (c_each(i, Persons, vec)) { - Person_raw p = Persons_value_toraw(i.ref); - printf("%s %s (%d)\n", p.name, p.last, (int)PersArc_use_count(*i.ref)); - } - puts(""); - - // Look-up Audrey! - const PersArc *a = Persons_find(&vec, (Person_raw){"Audrey", "Home"}).ref; - if (a) { - Person_raw p = Persons_value_toraw(a); // two-level unwrap! - printf("found: %s %s\n", p.name, p.last); - } - } -} diff --git a/src/finchlite/codegen/stc/examples/sortedmaps/gauss2.c b/src/finchlite/codegen/stc/examples/sortedmaps/gauss2.c deleted file mode 100644 index 4add989a..00000000 --- a/src/finchlite/codegen/stc/examples/sortedmaps/gauss2.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include - -// Declare int -> int sorted map. -#define T SortedMap, int, int -#include - -int main(void) -{ - enum {N = 5000000}; - uint64_t seed = (uint64_t)time(NULL); - crand64_seed(seed); - const double Mean = round(crand64_real()*98.0 - 49.0), - StdDev = crand64_real()*10.0 + 1.0, - Scale = 74.0; - - printf("Demo of gaussian / normal distribution of %d random samples\n", N); - printf("Mean %f, StdDev %f\n", Mean, StdDev); - - // Setup random normal distribution. - crand64_normal_dist d = {.mean=Mean, .stddev=StdDev}; - - // Create and init histogram map with defered destruct - SortedMap hist = {0}; - - for (c_range(N)) { - int index = (int)round(crand64_normal(&d)); - SortedMap_insert(&hist, index, 0).ref->second += 1; - } - - // Print the gaussian bar chart - for (c_each_kv(index, count, SortedMap, hist)) { - int n = (int)round(2.5 * Scale * StdDev * (*count) / (isize)N); - if (n > 0) { - printf("%4d ", *index); - while (n--) printf("*"); - puts(""); - } - } - SortedMap_drop(&hist); -} diff --git a/src/finchlite/codegen/stc/examples/sortedmaps/listmap.c b/src/finchlite/codegen/stc/examples/sortedmaps/listmap.c deleted file mode 100644 index 4435b17d..00000000 --- a/src/finchlite/codegen/stc/examples/sortedmaps/listmap.c +++ /dev/null @@ -1,63 +0,0 @@ -// This implements the multimap c++ example found at: -// https://en.cppreference.com/w/cpp/container/multimap/insert - -// Multimap entries -#include -#define i_keypro cstr -#include - -// Map of int => list_cstr. -// "valclass" bind list_cstr_clone() and list_cstr_drop() -#define T Multimap, int, list_cstr, (c_valclass) -#define i_cmp -c_default_cmp // like std::greater -#include - -void print(const char* lbl, const Multimap mmap) -{ - printf("%s ", lbl); - for (c_each(e, Multimap, mmap)) { - for (c_each(s, list_cstr, e.ref->second)) - printf("{%d,%s} ", e.ref->first, cstr_str(s.ref)); - } - puts(""); -} - -void insert(Multimap* mmap, int key, const char* str) -{ - list_cstr *list = &Multimap_insert(mmap, key, list_cstr_init()).ref->second; - list_cstr_emplace_back(list, str); -} - -int main(void) -{ - Multimap mmap = {0}; - - // list-initialize - struct pair {int a; const char* b;}; - for (c_items(i, struct pair, {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}})) - insert(&mmap, i.ref->a, i.ref->b); - print("#1", mmap); - - // insert using value_type - insert(&mmap, 5, "pqr"); - print("#2", mmap); - - // insert using make_pair - insert(&mmap, 6, "uvw"); - print("#3", mmap); - - insert(&mmap, 7, "xyz"); - print("#4", mmap); - - // insert using initialization_list - for (c_items(i, struct pair, {{5, "one"}, {5, "two"}})) - insert(&mmap, i.ref->a, i.ref->b); - print("#5", mmap); - - // FOLLOWING NOT IN ORIGINAL EXAMPLE: - // erase all entries with key 5 - Multimap_erase(&mmap, 5); - print("+5", mmap); - - Multimap_drop(&mmap); -} diff --git a/src/finchlite/codegen/stc/examples/sortedmaps/meson.build b/src/finchlite/codegen/stc/examples/sortedmaps/meson.build deleted file mode 100644 index 7f189f3f..00000000 --- a/src/finchlite/codegen/stc/examples/sortedmaps/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -foreach sample : [ - 'gauss2', - 'listmap', - 'multimap', - 'new_smap', - 'smap_erase', - 'smap_find', - 'smap_insert', - 'sorted_map', - 'sset_erase', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'hmap', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/sortedmaps/multimap.c b/src/finchlite/codegen/stc/examples/sortedmaps/multimap.c deleted file mode 100644 index dd7774e4..00000000 --- a/src/finchlite/codegen/stc/examples/sortedmaps/multimap.c +++ /dev/null @@ -1,100 +0,0 @@ -#include - -// Olympics multimap example - -struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = { - {2026, "Milan and Cortina d'Ampezzo", "Italy", "February 6-22"}, - {2022, "Beijing", "China", "February 4-20"}, - {2018, "PyeongChang", "South Korea", "February 9-25"}, - {2014, "Sochi", "Russia", "February 7-23"}, - {2010, "Vancouver", "Canada", "February 12-28"}, - {2006, "Torino", "Italy", "February 10-26"}, - {2002, "Salt Lake City", "United States", "February 8-24"}, - {1998, "Nagano", "Japan", "February 7-22"}, - {1994, "Lillehammer", "Norway", "February 12-27"}, - {1992, "Albertville", "France", "February 8-23"}, - {1988, "Calgary", "Canada", "February 13-28"}, - {1984, "Sarajevo", "Yugoslavia", "February 8-19"}, - {1980, "Lake Placid", "United States", "February 13-24"}, - {1976, "Innsbruck", "Austria", "February 4-15"}, - {1972, "Sapporo", "Japan", "February 3-13"}, - {1968, "Grenoble", "France", "February 6-18"}, - {1964, "Innsbruck", "Austria", "January 29-February 9"}, - {1960, "Squaw Valley", "United States", "February 18-28"}, - {1956, "Cortina d'Ampezzo", "Italy", "January 26 - February 5"}, - {1952, "Oslo", "Norway", "February 14 - 25"}, - {1948, "St. Moritz", "Switzerland", "January 30 - February 8"}, - {1944, "canceled", "canceled", "canceled"}, - {1940, "canceled", "canceled", "canceled"}, - {1936, "Garmisch-Partenkirchen", "Germany", "February 6 - 16"}, - {1932, "Lake Placid", "United States", "February 4 - 15"}, - {1928, "St. Moritz", "Switzerland", "February 11 - 19"}, - {1924, "Chamonix", "France", "January 25 - February 5"}, -}; - -typedef struct { int year; cstr city, date; } OlympicLoc; - -int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b); -OlympicLoc OlympicLoc_clone(OlympicLoc loc); -void OlympicLoc_drop(OlympicLoc* self); - -// Create a list, can be sorted by year. -// "class" binds _clone() and _drop(). -#define T list_OL, OlympicLoc, (c_keyclass | c_use_cmp) -#include - -// Create a smap where key is country name -// "valclass" binds list_OL_clone, list_OL_drop -#define T smap_OL, cstr, list_OL, (c_keypro | c_valclass) -#include - -int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b) { - return a->year - b->year; -} - -OlympicLoc OlympicLoc_clone(OlympicLoc loc) { - loc.city = cstr_clone(loc.city); - loc.date = cstr_clone(loc.date); - return loc; -} - -void OlympicLoc_drop(OlympicLoc* self) { - cstr_drop(&self->city); - cstr_drop(&self->date); -} - - -int main(void) -{ - // Define the multimap with destructor defered to when block is completed. - smap_OL multimap = {0}; - const list_OL empty = {0}; - - for (size_t i = 0; i < c_countof(ol_data); ++i) - { - struct OlympicsData* d = &ol_data[i]; - OlympicLoc loc = {.year = d->year, - .city = cstr_from(d->city), - .date = cstr_from(d->date)}; - // Insert an empty list for each new country, and append the entry to the list. - // If country already exist in map, its list is returned from the insert function. - list_OL* list = &smap_OL_emplace(&multimap, d->country, empty).ref->second; - list_OL_push_back(list, loc); - } - - // Sort locations by year for each country. - for (c_each(country, smap_OL, multimap)) - list_OL_sort(&country.ref->second); - - // Print the multimap: - for (c_each(country, smap_OL, multimap)) - { - // Loop the locations for a country sorted by year - for (c_each(loc, list_OL, country.ref->second)) - printf("%s: %d, %s, %s\n", cstr_str(&country.ref->first), - loc.ref->year, - cstr_str(&loc.ref->city), - cstr_str(&loc.ref->date)); - } - smap_OL_drop(&multimap); -} diff --git a/src/finchlite/codegen/stc/examples/sortedmaps/new_smap.c b/src/finchlite/codegen/stc/examples/sortedmaps/new_smap.c deleted file mode 100644 index e77a7c24..00000000 --- a/src/finchlite/codegen/stc/examples/sortedmaps/new_smap.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include - -declare_sortedmap(PntMap, struct Point, int); - -// Use forward declared PntMap in struct -typedef struct { - PntMap pntmap; - cstr name; -} MyStruct; - -// Point => int map -typedef struct Point { int x, y; } Point; -int Point_cmp(const Point* a, const Point* b) { - int c = a->x - b->x; - return c ? c : a->y - b->y; -} - -#define T PntMap, Point, int, (c_cmpclass | c_declared) -#include - -// cstr => cstr map -#define T StrMap, cstr, cstr, (c_keypro | c_valpro) -#include - -// cstr set -#define T StrSet, cstr, (c_keypro) -#include - - -int main(void) -{ - PntMap pmap = c_make(PntMap, { - {{42, 14}, 1}, - {{32, 94}, 2}, - {{62, 81}, 3}, - }); - - StrMap smap = c_make(StrMap, { - {"Hello, friend", "this is the mapped value"}, - {"The brown fox", "jumped"}, - {"This is the time", "for all good things"}, - }); - - for (c_each_kv(p, i, PntMap, pmap)) - printf(" (%d,%d: %d)", p->x, p->y, *i); - puts(""); - - for (c_each_kv(i, j, StrMap, smap)) - printf(" (%s: %s)\n", cstr_str(i), cstr_str(j)); - - StrSet sset = {0}; - StrSet_emplace(&sset, "Hello, friend"); - StrSet_emplace(&sset, "Goodbye, foe"); - printf("Found? %s\n", StrSet_contains(&sset, "Hello, friend") ? "true" : "false"); - - PntMap_drop(&pmap); - StrMap_drop(&smap); - StrSet_drop(&sset); -} diff --git a/src/finchlite/codegen/stc/examples/sortedmaps/smap_erase.c b/src/finchlite/codegen/stc/examples/sortedmaps/smap_erase.c deleted file mode 100644 index a3ca7842..00000000 --- a/src/finchlite/codegen/stc/examples/sortedmaps/smap_erase.c +++ /dev/null @@ -1,79 +0,0 @@ -// map_erase.c -// From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16 -#include -#include - -#define T mymap, int, cstr, (c_valpro) -#include - -void printmap(mymap m) -{ - for (c_each_kv(k, v, mymap, m)) - printf(" [%d, %s]", *k, cstr_str(v)); - printf("\nsize() == %" c_ZI "\n\n", mymap_size(&m)); -} - -int main(void) -{ - mymap m1 = {0}; - - // Fill in some data to test with, one at a time - mymap_insert(&m1, 1, cstr_lit("A")); - mymap_insert(&m1, 2, cstr_lit("B")); - mymap_insert(&m1, 3, cstr_lit("C")); - mymap_insert(&m1, 4, cstr_lit("D")); - mymap_insert(&m1, 5, cstr_lit("E")); - - puts("Starting data of map m1 is:"); - printmap(m1); - // The 1st member function removes an element at a given position - mymap_erase_at(&m1, mymap_advance(mymap_begin(&m1), 1)); - puts("After the 2nd element is deleted, the map m1 is:"); - printmap(m1); - - // Fill in some data to test with - mymap m2 = c_make(mymap, { - {10, "Bob"}, - {11, "Rob"}, - {12, "Robert"}, - {13, "Bert"}, - {14, "Bobby"}, - }); - - puts("Starting data of map m2 is:"); - printmap(m2); - mymap_iter it1 = mymap_advance(mymap_begin(&m2), 1); - mymap_iter it2 = mymap_find(&m2, mymap_back(&m2)->first); - - puts("to remove:"); - for (c_each_kv(k, v, mymap, it1, it2)) - printf(" [%d, %s]", *k, cstr_str(v)); - puts(""); - // The 2nd member function removes elements - // in the range [First, Last) - mymap_erase_range(&m2, it1, it2); - puts("After the middle elements are deleted, the map m2 is:"); - printmap(m2); - - mymap m3 = {0}; - - // Fill in some data to test with, one at a time, using emplace - mymap_emplace(&m3, 1, "red"); - mymap_emplace(&m3, 2, "yellow"); - mymap_emplace(&m3, 3, "blue"); - mymap_emplace(&m3, 4, "green"); - mymap_emplace(&m3, 5, "orange"); - mymap_emplace(&m3, 6, "purple"); - mymap_emplace(&m3, 7, "pink"); - - puts("Starting data of map m3 is:"); - printmap(m3); - // The 3rd member function removes elements with a given Key - int count = mymap_erase(&m3, 2); - // The 3rd member function also returns the number of elements removed - printf("The number of elements removed from m3 is: %d\n", count); - puts("After the element with a key of 2 is deleted, the map m3 is:"); - printmap(m3); - - c_drop(mymap, &m1, &m2, &m3); -} diff --git a/src/finchlite/codegen/stc/examples/sortedmaps/smap_find.c b/src/finchlite/codegen/stc/examples/sortedmaps/smap_find.c deleted file mode 100644 index b0d23368..00000000 --- a/src/finchlite/codegen/stc/examples/sortedmaps/smap_find.c +++ /dev/null @@ -1,69 +0,0 @@ -// This implements the c++ std::map::find example at: -// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17 -#include - -#define T smap_istr, int, cstr, (c_valpro) -#include - -#define T vec_istr, smap_istr_raw -#include - -void print_elem(smap_istr_raw p) { - printf("(%d, %s) ", p.first, p.second); -} - -#define use_print_collection(CX) \ - void print_collection_##CX(const CX* t) { \ - printf("%" c_ZI " elements: ", CX##_size(t)); \ - \ - for (c_each(p, CX, *t)) { \ - print_elem(CX##_value_toraw(p.ref)); \ - } \ - puts(""); \ - } - -use_print_collection(smap_istr) -use_print_collection(vec_istr) - -void findit(smap_istr c, smap_istr_key val) -{ - printf("Trying find() on value %d\n", val); - smap_istr_iter result = smap_istr_find(&c, val); // prefer contains() or get() - if (result.ref) { - printf("Element found: "); print_elem(smap_istr_value_toraw(result.ref)); puts(""); - } else { - puts("Element not found."); - } -} - -int main(void) -{ - smap_istr m1 = c_make(smap_istr, {{40, "Zr"}, {45, "Rh"}}); - vec_istr v = {0}; - - puts("The starting map m1 is (key, value):"); - print_collection_smap_istr(&m1); - - typedef vec_istr_value pair; - vec_istr_push(&v, c_literal(pair){43, "Tc"}); - vec_istr_push(&v, c_literal(pair){41, "Nb"}); - vec_istr_push(&v, c_literal(pair){46, "Pd"}); - vec_istr_push(&v, c_literal(pair){42, "Mo"}); - vec_istr_push(&v, c_literal(pair){44, "Ru"}); - vec_istr_push(&v, c_literal(pair){44, "Ru"}); // attempt a duplicate - - puts("Inserting the following vector data into m1:"); - print_collection_vec_istr(&v); - - for (c_each(i, vec_istr, vec_istr_begin(&v), vec_istr_end(&v))) - smap_istr_emplace(&m1, i.ref->first, i.ref->second); - - puts("The modified map m1 is (key, value):"); - print_collection_smap_istr(&m1); - puts(""); - findit(m1, 45); - findit(m1, 6); - - smap_istr_drop(&m1); - vec_istr_drop(&v); -} diff --git a/src/finchlite/codegen/stc/examples/sortedmaps/smap_insert.c b/src/finchlite/codegen/stc/examples/sortedmaps/smap_insert.c deleted file mode 100644 index 6ca3eea7..00000000 --- a/src/finchlite/codegen/stc/examples/sortedmaps/smap_insert.c +++ /dev/null @@ -1,103 +0,0 @@ -// This implements the std::map insert c++ example at: -// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19 - -#define T smap_ii, int, int -#include - -#define T vec_ii, smap_ii_value -#include - -#include - -#define T smap_istr, int, cstr, (c_valpro) // Map of int => cstr -#include - -void print_ii(smap_ii map) { - for (c_each(e, smap_ii, map)) - printf("(%d, %d) ", e.ref->first, e.ref->second); - puts(""); -} - -void print_istr(smap_istr map) { - for (c_each(e, smap_istr, map)) - printf("(%d, %s) ", e.ref->first, cstr_str(&e.ref->second)); - puts(""); -} - -int main(void) -{ - // insert single values - smap_ii m1 = {0}; - smap_ii_insert(&m1, 1, 10); - smap_ii_push(&m1, c_literal(smap_ii_value){2, 20}); - - puts("The original key and mapped values of m1 are:"); - print_ii(m1); - - // intentionally attempt a duplicate, single element - smap_ii_result ret = smap_ii_insert(&m1, 1, 111); - if (!ret.inserted) { - smap_ii_value pr = *ret.ref; - puts("Insert failed, element with key value 1 already exists."); - printf(" The existing element is (%d, %d)\n", pr.first, pr.second); - } - else { - puts("The modified key and mapped values of m1 are:"); - print_ii(m1); - } - puts(""); - - smap_ii_insert(&m1, 3, 30); - puts("The modified key and mapped values of m1 are:"); - print_ii(m1); - puts(""); - - // The templatized version inserting a jumbled range - smap_ii m2 = {0}; - vec_ii v = {0}; - typedef vec_ii_value ipair; - vec_ii_push(&v, c_literal(ipair){43, 294}); - vec_ii_push(&v, c_literal(ipair){41, 262}); - vec_ii_push(&v, c_literal(ipair){45, 330}); - vec_ii_push(&v, c_literal(ipair){42, 277}); - vec_ii_push(&v, c_literal(ipair){44, 311}); - - puts("Inserting the following vector data into m2:"); - for (c_each(e, vec_ii, v)) - printf("(%d, %d) ", e.ref->first, e.ref->second); - puts(""); - - for (c_each(e, vec_ii, v)) - smap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second); - - puts("The modified key and mapped values of m2 are:"); - for (c_each(e, smap_ii, m2)) - printf("(%d, %d) ", e.ref->first, e.ref->second); - puts("\n"); - - // The templatized versions move-constructing elements - smap_istr m3 = {0}; - smap_istr_value ip1 = {475, cstr_lit("blue")}, ip2 = {510, cstr_lit("green")}; - - // single element - smap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second)); - puts("After the first move insertion, m3 contains:"); - print_istr(m3); - - // single element - smap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second)); - puts("After the second move insertion, m3 contains:"); - print_istr(m3); - puts(""); - - smap_ii m4 = {0}; - // Insert the elements from an initializer_list - m4 = c_make(smap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}}); - puts("After initializer_list insertion, m4 contains:"); - print_ii(m4); - puts(""); - - vec_ii_drop(&v); - smap_istr_drop(&m3); - c_drop(smap_ii, &m1, &m2, &m4); -} diff --git a/src/finchlite/codegen/stc/examples/sortedmaps/sorted_map.c b/src/finchlite/codegen/stc/examples/sortedmaps/sorted_map.c deleted file mode 100644 index 993d65dc..00000000 --- a/src/finchlite/codegen/stc/examples/sortedmaps/sorted_map.c +++ /dev/null @@ -1,64 +0,0 @@ -// https://iq.opengenus.org/containers-cpp-stl/ - -#include -#define T Mymap, int, int -#include - -int main(void) -{ - Mymap gquiz1 = {0}, gquiz2 = {0}; - c_defer( - Mymap_drop(&gquiz1), - Mymap_drop(&gquiz2) - ){ - // insert elements in random order - Mymap_insert(&gquiz1, 2, 30); - Mymap_insert(&gquiz1, 4, 20); - Mymap_insert(&gquiz1, 7, 10); - Mymap_insert(&gquiz1, 5, 50); - Mymap_insert(&gquiz1, 3, 60); - Mymap_insert(&gquiz1, 1, 40); - Mymap_insert(&gquiz1, 6, 50); - - // printing map gquiz1 - printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n"); - for (c_each_kv(k, v, Mymap, gquiz1)) - printf("\t%d\t%d\n", *k, *v); - printf("\n"); - - // assigning the elements from gquiz1 to gquiz2 - for (c_each_kv(k, v, Mymap, gquiz1)) - Mymap_insert(&gquiz2, *k, *v); - - // print all elements of the map gquiz2 - printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n"); - for (c_each_kv(k, v, Mymap, gquiz2)) - printf("\t%d\t%d\n", *k, *v); - printf("\n"); - - // remove all elements up to element with key=3 in gquiz2 - printf("\ngquiz2 after removal of elements less than key=3 :\n"); - printf("\tKEY\tELEMENT\n"); - Mymap_erase_range(&gquiz2, Mymap_begin(&gquiz2), - Mymap_find(&gquiz2, 3)); - for (c_each_kv(k, v, Mymap, gquiz2)) - printf("\t%d\t%d\n", *k, *v); - printf("\n"); - - // remove all elements with key = 4 - int num = Mymap_erase(&gquiz2, 4); - printf("\ngquiz2.erase(4) : %d removed\n", num); - printf("\tKEY\tELEMENT\n"); - for (c_each_kv(k, v, Mymap, gquiz2)) - printf("\t%d\t%d\n", *k, *v); - printf("\n"); - - // lower bound and upper bound for map gquiz1 key = 5 - printf("gquiz1.lower_bound(5) : "); - printf("\tKEY = %d\t", Mymap_lower_bound(&gquiz1, 5).ref->first); - printf("\tELEMENT = %d\n", Mymap_lower_bound(&gquiz1, 5).ref->second); - printf("gquiz1.upper_bound(5) : "); - printf("\tKEY = %d\t", Mymap_lower_bound(&gquiz1, 5+1).ref->first); - printf("\tELEMENT = %d\n", Mymap_lower_bound(&gquiz1, 5+1).ref->second); - } -} diff --git a/src/finchlite/codegen/stc/examples/sortedmaps/sset_erase.c b/src/finchlite/codegen/stc/examples/sortedmaps/sset_erase.c deleted file mode 100644 index 062acae0..00000000 --- a/src/finchlite/codegen/stc/examples/sortedmaps/sset_erase.c +++ /dev/null @@ -1,41 +0,0 @@ -#include - -#define T ISet, int -#include - -int main(void) -{ - ISet set = c_make(ISet, {30, 20, 80, 40, 60, 90, 10, 70, 50}); - - for (c_each(k, ISet, set)) - printf(" %d", *k.ref); - puts(""); - - int val = 64; - ISet_iter it; - printf("Show values >= %d:\n", val); - it = ISet_lower_bound(&set, val); - - for (c_each(k, ISet, it, ISet_end(&set))) - printf(" %d", *k.ref); - puts(""); - - printf("Erase values >= %d:\n", val); - while (it.ref) - it = ISet_erase_at(&set, it); - - for (c_each(k, ISet, set)) - printf(" %d", *k.ref); - puts(""); - - val = 40; - printf("Erase values < %d:\n", val); - it = ISet_lower_bound(&set, val); - ISet_erase_range(&set, ISet_begin(&set), it); - - for (c_each(k, ISet, set)) - printf(" %d", *k.ref); - puts(""); - - ISet_drop(&set); -} diff --git a/src/finchlite/codegen/stc/examples/spans/matmult.c b/src/finchlite/codegen/stc/examples/spans/matmult.c deleted file mode 100644 index f9594973..00000000 --- a/src/finchlite/codegen/stc/examples/spans/matmult.c +++ /dev/null @@ -1,97 +0,0 @@ -// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2642r2.html -// https://vaibhaw-vipul.medium.com/matrix-multiplication-optimizing-the-code-from-6-hours-to-1-sec-70889d33dcfa -// Compile with: gcc -O3 -march=native -fopenmp matmult.c -lstc # Multiplies two 4K matrices in 0.5 seconds on a Ryzen 5700X CPU. -#define NDEBUG -#include -#include -#include - -use_cspan(Mat, float, 2); -typedef Mat OutMat; - -// Default matrix multiplication -void base_case_matrix_product(Mat A, Mat B, OutMat C) { - #ifdef __GNUC__ - #pragma omp parallel for schedule(runtime) - #endif - for (int i = 0; i < A.shape[0]; ++i) { - for (int k = 0; k < A.shape[1]; k++) { - for (int j = 0; j < B.shape[1]; j++) { - *cspan_at(&C, i,j) += *cspan_at(&A, i,k) * *cspan_at(&B, k,j); - } - } - } -} - -// Recursive implementation -typedef struct { Mat r00, r01, r10, r11; } Partition; - -Partition partition(Mat A) { - int m = A.shape[0]; - int n = A.shape[1]; - return (Partition){ - .r00 = cspan_slice(&A, Mat, {0, m/2}, {0, n/2}), - .r01 = cspan_slice(&A, Mat, {0, m/2}, {n/2, n}), - .r10 = cspan_slice(&A, Mat, {m/2, m}, {0, n/2}), - .r11 = cspan_slice(&A, Mat, {m/2, m}, {n/2, n}), - }; -} - -void recursive_matrix_product(Mat A, Mat B, OutMat C) { - // Some hardware-dependent constant - if (C.shape[0]*C.shape[1] <= 2048*2048) { - base_case_matrix_product(A, B, C); - } else { - Partition c = partition(C), - a = partition(A), - b = partition(B); - recursive_matrix_product(a.r00, b.r00, c.r00); - recursive_matrix_product(a.r01, b.r10, c.r00); - recursive_matrix_product(a.r10, b.r00, c.r10); - recursive_matrix_product(a.r11, b.r10, c.r10); - recursive_matrix_product(a.r00, b.r01, c.r01); - recursive_matrix_product(a.r01, b.r11, c.r01); - recursive_matrix_product(a.r10, b.r01, c.r11); - recursive_matrix_product(a.r11, b.r11, c.r11); - } -} - - -#define T Data, float -#include -#include - -int main(int argc, char* argv[]) { - int M = 128, P, N; - if (argc > 1) - M = atoi(argv[1]); - if (argc > 3) { - P = atoi(argv[2]); - N = atoi(argv[3]); - } else - P = N = M; - - printf("Recursive Matrix Multiplication (%dx%d * %dx%d)\n", M, P, P, N); - printf("Usage: %s [m [p n]]\n", argv[0]); - - Data values = Data_with_size(M*P + P*N + M*N, 0); - for (c_each_n(i, Data, values, M*P + P*N)) - *i.ref = (Data_value)((crand64_real() - 0.5)*10.0); - - Mat a = cspan_md(values.data, M, P); - Mat b = cspan_md(values.data + M*P, P, N); - OutMat c = cspan_md(values.data + M*P + P*N, M, N); - - clock_t t = clock(); - - //base_case_matrix_product(a, b, c); - recursive_matrix_product(a, b, c); // > gcc 2x faster - - t = clock() - t; - - puts("an 8x8 sub-matrix of result c"); - cspan_print(Mat, "%.4f", cspan_slice(&c, Mat, {0, 8}, {0, 8})); - - printf("\ntime %f ms\n", (double)t*1000.0/CLOCKS_PER_SEC); - Data_drop(&values); -} diff --git a/src/finchlite/codegen/stc/examples/spans/mdspan.c b/src/finchlite/codegen/stc/examples/spans/mdspan.c deleted file mode 100644 index 5b8f53a3..00000000 --- a/src/finchlite/codegen/stc/examples/spans/mdspan.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include - -use_cspan(DSpan2, double, 2); -use_cspan(DSpan3, double, 3); - -int main(void) { - const int nx=3, ny=4, nz=5; - double* data = c_new_n(double, nx*ny*nz); - - printf("\nMultidim span ms[3, 4, 5], fortran ordered"); - DSpan3 ms = cspan_md_layout(c_COLMAJOR, data, nx, ny, nz); - - int idx = 0; - for (int i = 0; i < ms.shape[0]; ++i) - for (int j = 0; j < ms.shape[1]; ++j) - for (int k = 0; k < ms.shape[2]; ++k) - *cspan_at(&ms, i, j, k) = ++idx; - - cspan_transpose(&ms); - - printf(", transposed:\n\n"); - cspan_print(DSpan3, "%.2f", ms); - - puts("Slicing:"); - printf("ms[0, :, :]\n"); - cspan_print(DSpan2, "%g", cspan_slice(&ms, DSpan2, {0}, {c_ALL}, {c_ALL})); - - printf("ms[:, 0, :]\n"); - cspan_print(DSpan2, "%g", cspan_slice(&ms, DSpan2, {c_ALL}, {0}, {c_ALL})); - - printf("ms[:, :, 0]\n"); - cspan_print(DSpan2, "%g", cspan_slice(&ms, DSpan2, {c_ALL}, {c_ALL}, {0})); - - c_free_n(data, nx*ny*nz); -} diff --git a/src/finchlite/codegen/stc/examples/spans/meson.build b/src/finchlite/codegen/stc/examples/spans/meson.build deleted file mode 100644 index 6673072c..00000000 --- a/src/finchlite/codegen/stc/examples/spans/meson.build +++ /dev/null @@ -1,27 +0,0 @@ -cc = meson.get_compiler('c') - -if cc.get_id() == 'gcc' - span_deps = [example_deps, dependency('openmp')] -else - span_deps = example_deps -endif - -foreach sample : [ - 'matmult', - 'mdspan', - 'multidim', - 'printspan', - 'submdspan', - 'span_demo', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: span_deps, - install: false, - ), - suite: 'cspan', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/spans/multidim.c b/src/finchlite/codegen/stc/examples/spans/multidim.c deleted file mode 100644 index a695a83b..00000000 --- a/src/finchlite/codegen/stc/examples/spans/multidim.c +++ /dev/null @@ -1,58 +0,0 @@ -// Example based on https://en.cppreference.com/w/cpp/container/mdspan -#include -#define T Vec, int -#include -#include - -use_cspan3(ISpan, int); // define ISpan, ISpan2, ISpan3 - -int main(void) -{ - Vec vec = c_make(Vec, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}); - - // Create 1d span from a compatibel container - ISpan ms1 = cspan_from_vec(&vec); - - // Create a 3D mdspan 2 x 3 x 4 - ISpan3 ms3 = cspan_md(vec.data, 2, 3, 4); - - puts("ms3:"); - cspan_print(ISpan3, "%d", ms3); - - // Take a slice of md3 - ISpan3 ss3 = cspan_slice(&ms3, ISpan3, {c_ALL}, {1,3}, {1,3}); - puts("\nss3 = ms3[:, 1:3, 1:3]"); - cspan_print(ISpan3, "%d", ss3); - - puts("\nIterate ss3 flat:"); - for (c_each(i, ISpan3, ss3)) - printf(" %d", *i.ref); - puts(""); - - // submd3 span reduces rank depending on number of arguments - ISpan2 ms2 = cspan_submd3(&ms3, 1); - - // Change data on the 2d subspan - for (int i=0; i != ms2.shape[0]; i++) - for (int j=0; j != ms2.shape[1]; j++) - *cspan_at(&ms2, i, j) = (i + 1)*100 + j; - - puts("\nms2 = ms3[1] with updated data:"); - cspan_print(ISpan2, "%d", ms2); - - puts("\nOriginal s1 span with updated data:"); - for (c_each(i, ISpan, ms1)) - printf(" %d", *i.ref); - puts(""); - - puts("\nOriginal ms3 span with updated data:"); - cspan_print(ISpan3, "%d", ms3); - - puts("\ncol = ms3[1, :, 2]"); - ISpan col = cspan_slice(&ms3, ISpan, {1}, {c_ALL}, {2}); - for (c_each(i, ISpan, col)) - printf(" %d", *i.ref); - puts(""); - - Vec_drop(&vec); -} diff --git a/src/finchlite/codegen/stc/examples/spans/printspan.c b/src/finchlite/codegen/stc/examples/spans/printspan.c deleted file mode 100644 index 87260f61..00000000 --- a/src/finchlite/codegen/stc/examples/spans/printspan.c +++ /dev/null @@ -1,40 +0,0 @@ -// https://www.modernescpp.com/index.php/c-20-std-span/ - -#include -#define i_key int -#include -#define i_key int -#include -#include - -use_cspan(intspan, const int); - - -void printMe(intspan container) { - printf("%d:", (int)cspan_size(&container)); - for (c_each(e, intspan, container)) - printf(" %d", *e.ref); - puts(""); -} - - -int main(void) -{ - printMe( c_make(intspan, {1, 2, 3, 4}) ); - - int arr[] = {1, 2, 3, 4, 5}; - printMe( (intspan)cspan_from_array(arr) ); - - vec_int vec = c_make(vec_int, {1, 2, 3, 4, 5, 6}); - printMe( (intspan)cspan_from_vec(&vec) ); - - stack_int stk = c_make(stack_int, {1, 2, 3, 4, 5, 6, 7}); - printMe( (intspan)cspan_from_vec(&stk) ); - - intspan spn = c_make(intspan, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); - printMe( (intspan)cspan_subspan(&spn, 2, 8) ); - - // cleanup - vec_int_drop(&vec); - stack_int_drop(&stk); -} diff --git a/src/finchlite/codegen/stc/examples/spans/span_demo.c b/src/finchlite/codegen/stc/examples/spans/span_demo.c deleted file mode 100644 index 3c16156f..00000000 --- a/src/finchlite/codegen/stc/examples/spans/span_demo.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -use_cspan3(Span, int); - -int main(void) -{ - Span3 md3 = cspan_md(cspan_zeros(Span, 3*4*5).data, 3, 4, 5); - for (c_range32(i, 3*4*5)) md3.data[i] = i; - - Span2 tmp2 = cspan_submd3(&md3, 2); - cspan_transpose(&tmp2); - Span last_col = cspan_submd2(&tmp2, 4); - - Span2 sliced = cspan_slice(&md3, Span2, {c_ALL}, {c_ALL}, {0}); - - Span2 img = cspan_md(md3.data, 6, 10); - Span2 half = {img.data, cspan_shape(img.shape[0]/2, img.shape[1]/2), - cspan_strides(img.stride.d[0]*2, img.stride.d[1]*2)}; - - Span2 half_tr = Span2_transposed(half); - - puts("\n3D SPAN (md3):"); - cspan_print(Span3, "%d", md3); - - puts("\n3D SPAN LAST 1D COLUMN:"); - cspan_print(Span, "%d", last_col); - - puts("\n3D SPAN SLICED 2D:"); - cspan_print(Span2, "%d", sliced); - - puts("\nROWMAJOR (img):"); - cspan_print(Span2, "%d", img); - - puts("\nSTRIDED (half):"); - cspan_print(Span2, "%d", half); - - puts("\nCOLMAJOR (half):"); - cspan_print(Span2, "%d", half_tr); -} diff --git a/src/finchlite/codegen/stc/examples/spans/submdspan.c b/src/finchlite/codegen/stc/examples/spans/submdspan.c deleted file mode 100644 index c422455f..00000000 --- a/src/finchlite/codegen/stc/examples/spans/submdspan.c +++ /dev/null @@ -1,40 +0,0 @@ -// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2630r0.html -// C99: -#include -#include - -use_cspan(span2, double, 2); -use_cspan(span3, double, 3); - -// Set all elements of a rank-2 mdspan to zero. -void zero_2d(span2 grid2d) { - c_static_assert(cspan_rank(&grid2d) == 2); - for (int i = 0; i < grid2d.shape[0]; ++i) { - for (int j = 0; j < grid2d.shape[1]; ++j) { - *cspan_at(&grid2d, i,j) = 0; - } - } -} - -void zero_surface(span3 grid3d) { - c_static_assert(cspan_rank(&grid3d) == 3); - zero_2d(cspan_slice(&grid3d, span2, {0}, {c_ALL}, {c_ALL})); - zero_2d(cspan_slice(&grid3d, span2, {c_ALL}, {0}, {c_ALL})); - zero_2d(cspan_slice(&grid3d, span2, {c_ALL}, {c_ALL}, {0})); - zero_2d(cspan_slice(&grid3d, span2, {grid3d.shape[0]-1}, {c_ALL}, {c_ALL})); - zero_2d(cspan_slice(&grid3d, span2, {c_ALL}, {grid3d.shape[1]-1}, {c_ALL})); - zero_2d(cspan_slice(&grid3d, span2, {c_ALL}, {c_ALL}, {grid3d.shape[2]-1})); -} - -int main(void) { - double arr[4*4*5]; - for (c_range32(i, c_countof(arr))) - arr[i] = i + i/77.0; - - span3 md = cspan_md(arr, 4, 4, 5); - - zero_surface(md); - - cspan_print(span3, "%.2f", md); - puts("done"); -} diff --git a/src/finchlite/codegen/stc/examples/strings/cstr_match.c b/src/finchlite/codegen/stc/examples/strings/cstr_match.c deleted file mode 100644 index c7838c84..00000000 --- a/src/finchlite/codegen/stc/examples/strings/cstr_match.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include - -int main(void) -{ - cstr str = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"); - - isize pos = cstr_find_at(&str, 0, "brown"); - printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "" : cstr_str(&str) + pos); - printf("equals: %d\n", cstr_equals(&str, "The quick brown fox jumps over the lazy dog.JPG")); - printf("contains 'umps ove': %d\n", cstr_contains(&str, "umps ove")); - printf("starts_with 'The quick brown': %d\n", cstr_starts_with(&str, "The quick brown")); - printf("ends_with '.jpg': %d\n", cstr_ends_with(&str, ".jpg")); - printf("ends_with '.JPG': %d\n", cstr_ends_with(&str, ".JPG")); - - cstr s1 = cstr_lit("hell😀 w😀rl🐨"); - csview ch1 = cstr_u8_at(&s1, 7).chr; - csview ch2 = cstr_u8_at(&s1, 10).chr; - printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); - printf("ch1: " c_svfmt "\n", c_svarg(ch1)); - printf("ch2: " c_svfmt "\n", c_svarg(ch2)); - - c_drop(cstr, &str, &s1); -} diff --git a/src/finchlite/codegen/stc/examples/strings/meson.build b/src/finchlite/codegen/stc/examples/strings/meson.build deleted file mode 100644 index e203af2b..00000000 --- a/src/finchlite/codegen/stc/examples/strings/meson.build +++ /dev/null @@ -1,20 +0,0 @@ -foreach sample : [ - 'cstr_match', - 'replace', - 'splitstr', - 'sso_map', - 'sso_substr', - 'sview_split', - 'utf8replace_c', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'cstr', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/strings/replace.c b/src/finchlite/codegen/stc/examples/strings/replace.c deleted file mode 100644 index 3b4edf79..00000000 --- a/src/finchlite/codegen/stc/examples/strings/replace.c +++ /dev/null @@ -1,35 +0,0 @@ -#include - -int main(void) -{ - const char *base = "this is a test string."; - const char *s2 = "n example"; - const char *s3 = "sample phrase"; - - // replace signatures used in the same order as described above: - - // Ustring positions: 0123456789*123456789*12345 - cstr s = cstr_from(base); // "this is a test string." - cstr m = cstr_clone(s); - - cstr_append(&m, cstr_str(&m)); - cstr_append(&m, cstr_str(&m)); - printf("%s\n", cstr_str(&m)); - - cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) - printf("(1) %s\n", cstr_str(&s)); - - cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) - printf("(2) %s\n", cstr_str(&s)); - - cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) - printf("(3) %s\n", cstr_str(&s)); - - cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) - printf("(4) %s\n", cstr_str(&s)); - - cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) - printf("(5) %s\n", cstr_str(&s)); - - c_drop(cstr, &s, &m); -} diff --git a/src/finchlite/codegen/stc/examples/strings/splitstr.c b/src/finchlite/codegen/stc/examples/strings/splitstr.c deleted file mode 100644 index 3032bdb5..00000000 --- a/src/finchlite/codegen/stc/examples/strings/splitstr.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include -#include - -int main(void) -{ - puts("Split with c_token():"); - - for (c_token(i, " ", "Hello World C99!")) - printf("'" c_svfmt "'\n", c_svarg(i.token)); - - puts("\nSplit with for (c_match(regex)):"); - - cregex re = cregex_from("[^\\s]+"); - for (c_match(i, &re, " Hello \t World \n C99! ")) - printf("'" c_svfmt "'\n", c_svarg(i.match[0])); - - cregex_drop(&re); -} diff --git a/src/finchlite/codegen/stc/examples/strings/sso_map.c b/src/finchlite/codegen/stc/examples/strings/sso_map.c deleted file mode 100644 index 1b501ce4..00000000 --- a/src/finchlite/codegen/stc/examples/strings/sso_map.c +++ /dev/null @@ -1,18 +0,0 @@ -#include -#define i_keypro cstr -#define i_valpro cstr -#include - -int main(void) -{ - hmap_cstr m = {0}; - hmap_cstr_emplace(&m, "Test short", "This is a short string"); - hmap_cstr_emplace(&m, "Test long ", "This is a longer string"); - - for (c_each_kv(k, v, hmap_cstr, m)) - printf("%s: '%s' Len=%d, Is long: %s\n", - cstr_str(k), cstr_str(v), (int)cstr_size(v), - cstr_is_long(v) ? "true" : "false"); - - hmap_cstr_drop(&m); -} diff --git a/src/finchlite/codegen/stc/examples/strings/sso_substr.c b/src/finchlite/codegen/stc/examples/strings/sso_substr.c deleted file mode 100644 index ac34ea57..00000000 --- a/src/finchlite/codegen/stc/examples/strings/sso_substr.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -int main(void) -{ - cstr str = cstr_lit("We think in generalities, but we live in details."); - csview sv = cstr_sv(&str); - csview sv1 = csview_subview(sv, 3, 5); // "think" - isize pos = csview_find(sv, "live"); // position of "live" - csview sv2 = csview_subview(sv, pos, 4); // "live" - csview sv3 = csview_subview_pro(sv, -8, 7); // "details" - printf(c_svfmt ", " c_svfmt ", " c_svfmt "\n", - c_svarg(sv1), c_svarg(sv2), c_svarg(sv3)); - - cstr_assign(&str, "apples are green or red"); - sv = cstr_sv(&str); - cstr s2 = cstr_from_sv(csview_subview_pro(sv, -3, 3)); // "red" - cstr s3 = cstr_from_sv(csview_subview(sv, 0, 6)); // "apples" - printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); - - c_drop(cstr, &str, &s2, &s3); -} diff --git a/src/finchlite/codegen/stc/examples/strings/sview_split.c b/src/finchlite/codegen/stc/examples/strings/sview_split.c deleted file mode 100644 index 4cda492e..00000000 --- a/src/finchlite/codegen/stc/examples/strings/sview_split.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -int main(void) -{ - // No memory allocations or string length calculations! - const csview date = c_sv("2021/03/12"); - isize pos = 0; - const csview year = csview_token(date, "/", &pos); - const csview day = csview_token(date, "/", &pos); - const csview month = csview_token(date, "/", &pos); - - printf(c_svfmt ", " c_svfmt ", " c_svfmt "\n", - c_svarg(year), c_svarg(month), c_svarg(day)); - - cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); - printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); - c_drop(cstr, &y, &m, &d); -} diff --git a/src/finchlite/codegen/stc/examples/strings/utf8replace_c.c b/src/finchlite/codegen/stc/examples/strings/utf8replace_c.c deleted file mode 100644 index 689806af..00000000 --- a/src/finchlite/codegen/stc/examples/strings/utf8replace_c.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -int main(void) -{ - cstr hello = cstr_lit("hell😀 w😀rld"); - printf("%s, %d:%d\n", cstr_str(&hello), (int)cstr_u8_size(&hello), (int)cstr_size(&hello)); - - zsview sub5 = cstr_u8_tail(&hello, 5); - printf("%s, %d:%d\n", sub5.str, (int)zsview_u8_size(sub5), (int)sub5.size); - - /* replace second smiley at utf8 codepoint pos 7 */ - - cstr_u8_insert(&hello, 8, "🐨"); - printf("%s, %d:%d\n", cstr_str(&hello), (int)cstr_u8_size(&hello), (int)cstr_size(&hello)); - - cstr_u8_erase(&hello, 7, 1); - printf("%s, %d:%d\n", cstr_str(&hello), (int)cstr_u8_size(&hello), (int)cstr_size(&hello)); - - cstr_u8_replace(&hello, 9, 1, "😀"); - printf("%s, %d:%d\n", cstr_str(&hello), (int)cstr_u8_size(&hello), (int)cstr_size(&hello)); - - for (c_each(c, cstr, hello)) - printf(c_svfmt ",", c_svarg(c.chr)); - - cstr str = cstr_lit("scooby, dooby doo"); - cstr_replace(&str, "oo", "00"); - printf("\n%s\n", cstr_str(&str)); - - c_drop(cstr, &hello, &str); -} diff --git a/src/finchlite/codegen/stc/examples/strings/utf8replace_rs.rs b/src/finchlite/codegen/stc/examples/strings/utf8replace_rs.rs deleted file mode 100644 index 2cdbe8cf..00000000 --- a/src/finchlite/codegen/stc/examples/strings/utf8replace_rs.rs +++ /dev/null @@ -1,22 +0,0 @@ -pub fn main() { - let mut hello = String::from("hell😀 w😀rld"); - println!("{}", hello); - - /* replace second smiley at utf8 codepoint pos 7 */ - hello.replace_range( - hello - .char_indices() - .nth(7) - .map(|(pos, ch)| (pos..pos + ch.len_utf8())) - .unwrap(), - "🐨", - ); - println!("{}", hello); - - for c in hello.chars() { - print!("{},", c); - } - - let str = "If you find the time, you will find the winner"; - println!("\n{}", str.replace("find", "match")); -} diff --git a/src/finchlite/codegen/stc/examples/vectors/lower_bound.c b/src/finchlite/codegen/stc/examples/vectors/lower_bound.c deleted file mode 100644 index 2b89dc9d..00000000 --- a/src/finchlite/codegen/stc/examples/vectors/lower_bound.c +++ /dev/null @@ -1,65 +0,0 @@ -#include - -#define T IVec, int, (c_use_cmp) -#include - -#define T ISet, int -#include - -int main(void) -{ - // TEST SORTED VECTOR - { - int key; - IVec vec = c_make(IVec, {40, 600, 1, 7000, 2, 500, 30}); - - IVec_sort(&vec); - - key = 100; - isize res = IVec_lower_bound(&vec, key); - if (res != c_NPOS) - printf("Sorted Vec %d: lower bound: %d\n", key, vec.data[res]); // 500 - - key = 10; - isize it1 = IVec_lower_bound(&vec, key); - if (it1 != c_NPOS) - printf("Sorted Vec %3d: lower_bound: %d\n", key, vec.data[it1]); // 30 - - key = 600; - isize it2 = IVec_binary_search(&vec, key); - if (it2 != c_NPOS) - printf("Sorted Vec %d: bin. search: %d\n", key, vec.data[it2]); // 600 - - for (isize i = it1; i != it2; ++i) - printf(" %d\n", vec.data[i]); - - puts(""); - IVec_drop(&vec); - } - - // TEST SORTED SET - { - int key, *res; - ISet set = c_make(ISet, {40, 600, 1, 7000, 2, 500, 30}); - - key = 100; - res = ISet_lower_bound(&set, key).ref; - if (res) - printf("Sorted Set %d: lower bound: %d\n", key, *res); // 500 - - key = 10; - ISet_iter it1 = ISet_lower_bound(&set, key); - if (it1.ref) - printf("Sorted Set %3d: lower bound: %d\n", key, *it1.ref); // 30 - - key = 600; - ISet_iter it2 = ISet_find(&set, key); - if (it2.ref) - printf("Sorted Set %d: find : %d\n", key, *it2.ref); // 600 - - for (c_each(i, ISet, it1, it2)) - printf(" %d\n", *i.ref); - - ISet_drop(&set); - } -} diff --git a/src/finchlite/codegen/stc/examples/vectors/meson.build b/src/finchlite/codegen/stc/examples/vectors/meson.build deleted file mode 100644 index 210b5a53..00000000 --- a/src/finchlite/codegen/stc/examples/vectors/meson.build +++ /dev/null @@ -1,16 +0,0 @@ -foreach sample : [ - 'lower_bound', - 'new_vec', - 'stack', -] - test( - sample, - executable( - sample, - files(f'@sample@.c'), - dependencies: example_deps, - install: false, - ), - suite: 'vec', - ) -endforeach diff --git a/src/finchlite/codegen/stc/examples/vectors/new_vec.c b/src/finchlite/codegen/stc/examples/vectors/new_vec.c deleted file mode 100644 index 3754c35a..00000000 --- a/src/finchlite/codegen/stc/examples/vectors/new_vec.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -declare_vec(vec_i32, int); -declare_vec(vec_pnt, struct Point); - -typedef struct MyStruct { - vec_i32 intvec; - vec_pnt pntvec; -} MyStruct; - -#define T vec_i32, int, (c_declared) -#include - -typedef struct Point { int x, y; } Point; - -#define T vec_pnt, Point, (c_declared) -#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) -#define i_eq(a, b) a->x == b->x && a->y == b->y -#include - -int main(void) -{ - MyStruct my = {0}; - - vec_pnt_push(&my.pntvec, c_literal(Point){42, 14}); - vec_pnt_push(&my.pntvec, c_literal(Point){32, 94}); - vec_pnt_push(&my.pntvec, c_literal(Point){62, 81}); - vec_pnt_push(&my.pntvec, c_literal(Point){32, 91}); - - vec_pnt_sort(&my.pntvec); - - for (c_each_item(e, vec_pnt, my.pntvec)) - printf(" (%d %d)", e->x, e->y); - puts(""); - - vec_i32_drop(&my.intvec); - vec_pnt_drop(&my.pntvec); -} diff --git a/src/finchlite/codegen/stc/examples/vectors/stack.c b/src/finchlite/codegen/stc/examples/vectors/stack.c deleted file mode 100644 index f7fe7f54..00000000 --- a/src/finchlite/codegen/stc/examples/vectors/stack.c +++ /dev/null @@ -1,31 +0,0 @@ - -#include - -#define T IVec, int, 100, (c_use_cmp) -#include - -#define T CVec, char, 100, (0) -#include - -int main(void) { - IVec stack = {0}; - CVec chars = {0}; - - IVec_sort(&stack); - - for (c_range(i, 101)) - IVec_push(&stack, (int)(i*i)); - - printf("%d\n", *IVec_top(&stack)); - - for (c_range(i, 90)) - IVec_pop(&stack); - - for (c_each(i, IVec, stack)) - printf(" %d", *i.ref); - puts(""); - printf("top: %d\n", *IVec_top(&stack)); - - IVec_drop(&stack); - CVec_drop(&chars); -} diff --git a/src/finchlite/codegen/stc/include/c11/fmt.h b/src/finchlite/codegen/stc/include/c11/fmt.h deleted file mode 100644 index 93f8d234..00000000 --- a/src/finchlite/codegen/stc/include/c11/fmt.h +++ /dev/null @@ -1,301 +0,0 @@ -#ifndef FMT_H_INCLUDED -#define FMT_H_INCLUDED -/* -VER 2.4 API: -void fmt_print(fmt, ...); -void fmt_println(fmt, ...); -void fmt_printd(dst, fmt, ...); -const char* fmt_time(fmt, const struct tm* tm, int MAXLEN); -void fmt_close(fmt_stream* ss); - - dst - destination, one of: - FILE* fp Write to a file - char* strbuf Write to a pre-allocated string buffer - fmt_stream* ss Write to a string-stream (auto allocated). - Set ss->overwrite=1 for overwrite-mode. - Call fmt_close(ss) after usage. - - fmt - format string (const char*) - {} Auto-detected format. If :MOD is not specified, - float will use ".8g" format, and double ".16g". - {:MODS} Format modifiers: '<' left align (replaces '-'). Default for char* and char. - '>' right align. Default for numbers. - Other than that MODS can be regular printf() format modifiers. - {{ }} % Print the '{', '}', and '%' characters. - -* C11 or higher required. -* MAX 12 arguments after fmt string. -* Define FMT_IMPLEMENT, STC_IMPLEMENT or i_implement prior to #include in one translation unit. -* (c) operamint, 2022-2025, MIT License. ------------------------------------------------------------------------------------ -#define i_implement -#include "c11/fmt.h" - -int main(void) { - const double pi = 3.141592653589793; - const size_t x = 1234567890; - const char* string = "Hello world"; - const wchar_t* wstr = L"The whole"; - const char z = 'z'; - _Bool flag = 1; - unsigned char r = 123, g = 214, b = 90, w = 110; - char buffer[64]; - - fmt_print("Color: ({} {} {}), {}\n", r, g, b, flag); - fmt_println("Wide: {}, {}", wstr, L"wide world"); - fmt_println("{:10} {:10} {:10.2f}", 42ull, 43, pi); - fmt_println("{:>10} {:>10} {:>10}", z, z, w); - fmt_printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World"); - fmt_printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x); - fmt_printd(buffer, "Precision: {} {:.10} {}", string, pi, x); - fmt_println("{}", buffer); - fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi); - - fmt_stream ss[1] = {0}; - fmt_printd(ss, "{} {}", "Pi is:", pi); - fmt_print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); - fmt_printd(ss, "{} {}", ", Pi squared is:", pi*pi); - fmt_print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); - fmt_close(ss); - - time_t now = time(NULL); - struct tm t1 = *localtime(&now), t2 = t1; - t2.tm_hour += 48; - mktime(&t2); - fmt_print("Dates: {} and {}\n", fmt_time("%Y-%m-%d %X %Z", &t1, 63), - fmt_time("%Y-%m-%d %X %Z", &t2, 63)); -} -*/ -#include // IWYU pragma: keep -#include -#include -#include -#if defined _WIN32 - #include -#elif defined __APPLE__ - #include -#else - #include -#endif -#define fmt_OVERLOAD(name, ...) \ - fmt_JOIN(name ## _,fmt_NUMARGS(__VA_ARGS__))(__VA_ARGS__) -#define fmt_JOIN(a, b) _fmt_JOIN0(a, b) -#define fmt_NUMARGS(...) _fmt_APPLY_ARG_N((__VA_ARGS__, _fmt_RSEQ_N)) -#define _fmt_JOIN0(a, b) a ## b -#define _fmt_APPLY_ARG_N(args) _fmt_ARG_N args -#define _fmt_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -#define _fmt_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,N,...) N - -#if defined FMT_NDEBUG || defined STC_NDEBUG || defined NDEBUG -# define fmt_OK(exp) (void)(exp) -#else -# define fmt_OK(exp) assert(exp) -#endif - -typedef struct { - char* data; - ptrdiff_t cap, len; - _Bool overwrite; -} fmt_stream; - -#if defined FMT_STATIC || defined STC_STATIC || defined i_static - #define FMT_API static - #define FMT_DEF static -#elif defined FMT_IMPLEMENT || defined STC_IMPLEMENT || defined i_implement - #define FMT_API extern - #define FMT_DEF -#else - #define FMT_API -#endif - -struct tm; -FMT_API const char* _fmt_time(const char *fmt, const struct tm* tm, char* buf, int bufsize); -FMT_API void fmt_close(fmt_stream* ss); -FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...); -FMT_API void _fmt_sprint(fmt_stream*, const char* fmt, ...); -#define _fmt_init(_fs, _fmt, fmt, nargs) \ - const char* _fmt = fmt; \ - char* _fs = (char*)alloca(strlen(_fmt) + nargs*3 + 1) // "{}" => "%.16g" => +3 - -#define fmt_print(...) fmt_printd(stdout, __VA_ARGS__) -#define fmt_println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) -#define fmt_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__) -#define fmt_time(fmt, tm, MAXLEN) _fmt_time(fmt, tm, (char[MAXLEN + 1]){0}, MAXLEN + 1) - -#define fmt_sv "{:.*s}" -#define fmt_svarg(sv) (int)(sv).size, (sv).buf - -/* Primary function. */ -#define fmt_printd_2(to, fmt) \ - do { _fmt_init(_fs, _fmt, fmt, 0); int _n = _fmt_parse(_fs, 0, _fmt); \ - fmt_OK(_n == 0); _fmt_fn(to)(to, _fmt); } while (0) -#define fmt_printd_3(to, fmt, a) \ - do { _fmt_init(_fs, _fmt, fmt, 1); int _n = _fmt_parse(_fs, 1, _fmt, _fc(a)); \ - fmt_OK(_n == 1); _fmt_fn(to)(to, _fs, a); } while (0) -#define fmt_printd_4(to, fmt, a, b) \ - do { _fmt_init(_fs, _fmt, fmt, 2); int _n = _fmt_parse(_fs, 2, _fmt, _fc(a), _fc(b)); \ - fmt_OK(_n == 2); _fmt_fn(to)(to, _fs, a, b); } while (0) -#define fmt_printd_5(to, fmt, a, b, c) \ - do { _fmt_init(_fs, _fmt, fmt, 3); int _n = _fmt_parse(_fs, 3, _fmt, _fc(a), _fc(b), _fc(c)); \ - fmt_OK(_n == 3); _fmt_fn(to)(to, _fs, a, b, c); } while (0) -#define fmt_printd_6(to, fmt, a, b, c, d) \ - do { _fmt_init(_fs, _fmt, fmt, 4); int _n = _fmt_parse(_fs, 4, _fmt, _fc(a), _fc(b), _fc(c), _fc(d)); \ - fmt_OK(_n == 4); _fmt_fn(to)(to, _fs, a, b, c, d); } while (0) -#define fmt_printd_7(to, fmt, a, b, c, d, e) \ - do { _fmt_init(_fs, _fmt, fmt, 5); int _n = _fmt_parse(_fs, 5, _fmt, _fc(a), _fc(b), _fc(c), _fc(d), _fc(e)); \ - fmt_OK(_n == 5); _fmt_fn(to)(to, _fs, a, b, c, d, e); } while (0) -#define fmt_printd_8(to, fmt, a, b, c, d, e, f) \ - do { _fmt_init(_fs, _fmt, fmt, 6); int _n = _fmt_parse(_fs, 6, _fmt, _fc(a), _fc(b), _fc(c), _fc(d), _fc(e), _fc(f)); \ - fmt_OK(_n == 6); _fmt_fn(to)(to, _fs, a, b, c, d, e, f); } while (0) -#define fmt_printd_9(to, fmt, a, b, c, d, e, f, g) \ - do { _fmt_init(_fs, _fmt, fmt, 7); int _n = _fmt_parse(_fs, 7, _fmt, _fc(a), _fc(b), _fc(c), _fc(d), _fc(e), _fc(f), _fc(g)); \ - fmt_OK(_n == 7); _fmt_fn(to)(to, _fs, a, b, c, d, e, f, g); } while (0) -#define fmt_printd_10(to, fmt, a, b, c, d, e, f, g, h) \ - do { _fmt_init(_fs, _fmt, fmt, 8); int _n = _fmt_parse(_fs, 8, _fmt, _fc(a), _fc(b), _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h)); \ - fmt_OK(_n == 8); _fmt_fn(to)(to, _fs, a, b, c, d, e, f, g, h); } while (0) -#define fmt_printd_11(to, fmt, a, b, c, d, e, f, g, h, i) \ - do { _fmt_init(_fs, _fmt, fmt, 9); int _n = _fmt_parse(_fs, 9, _fmt, _fc(a), _fc(b), _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i)); \ - fmt_OK(_n == 9); _fmt_fn(to)(to, _fs, a, b, c, d, e, f, g, h, i); } while (0) -#define fmt_printd_12(to, fmt, a, b, c, d, e, f, g, h, i, j) \ - do { _fmt_init(_fs, _fmt, fmt, 10); int _n = _fmt_parse(_fs, 10, _fmt, _fc(a), _fc(b), _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j)); \ - fmt_OK(_n == 10); _fmt_fn(to)(to, _fs, a, b, c, d, e, f, g, h, i, j); } while (0) -#define fmt_printd_13(to, fmt, a, b, c, d, e, f, g, h, i, j, k) \ - do { _fmt_init(_fs, _fmt, fmt, 11); int _n = _fmt_parse(_fs, 11, _fmt, _fc(a), _fc(b), _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k)); \ - fmt_OK(_n == 11); _fmt_fn(to)(to, _fs, a, b, c, d, e, f, g, h, i, j, k); } while (0) -#define fmt_printd_14(to, fmt, a, b, c, d, e, f, g, h, i, j, k, l) \ - do { _fmt_init(_fs, _fmt, fmt, 12); int _n = _fmt_parse(_fs, 12, _fmt, _fc(a), _fc(b), _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k), _fc(l)); \ - fmt_OK(_n == 12); _fmt_fn(to)(to, _fs, a, b, c, d, e, f, g, h, i, j, k, l); } while (0) - -#define _fmt_fn(x) _Generic ((x), \ - FILE*: fprintf, \ - char*: sprintf, \ - fmt_stream*: _fmt_sprint) - -#if defined(_MSC_VER) && !defined(__clang__) - #define _signed_char_hhd -#else - #define _signed_char_hhd signed char: "c", -#endif - -#if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_LLVM_COMPILER) - #define FMT_UNUSED __attribute__((unused)) -#else - #define FMT_UNUSED -#endif - -#define _fc(x) _Generic (x, \ - _Bool: "d", \ - unsigned char: "hhu", \ - _signed_char_hhd \ - char: "c", \ - short: "hd", \ - unsigned short: "hu", \ - int: "d", \ - unsigned: "u", \ - long: "ld", \ - unsigned long: "lu", \ - long long: "lld", \ - unsigned long long: "llu", \ - float: "g", \ - double: "@g", \ - long double: "@Lg", \ - char*: "s", \ - wchar_t*: "ls", \ - void*: "p", \ - const char*: "s", \ - const wchar_t*: "ls", \ - const void*: "p") - -#if defined FMT_DEF - -#include -#include -#include - -FMT_DEF FMT_UNUSED void fmt_close(fmt_stream* ss) { - free(ss->data); -} - -FMT_DEF FMT_UNUSED -const char* _fmt_time(const char *fmt, const struct tm* tm, char* buf, int bufsize) { - strftime(buf, (size_t)bufsize, fmt, tm); - return buf; -} - -FMT_DEF void _fmt_sprint(fmt_stream* ss, const char* fmt, ...) { - va_list args, args2; - va_start(args, fmt); - if (ss == NULL) { - vprintf(fmt, args); putchar('\n'); - goto done1; - } - va_copy(args2, args); - const int n = vsnprintf(NULL, 0U, fmt, args); - if (n < 0) goto done2; - const ptrdiff_t pos = ss->overwrite ? 0 : ss->len; - ss->len = pos + n; - if (ss->len > ss->cap) { - ss->cap = ss->len + ss->cap/2; - ss->data = (char*)realloc(ss->data, (size_t)ss->cap + 1U); - } - vsnprintf(ss->data + pos, (size_t)n+1, fmt, args2); - done2: va_end(args2); - done1: va_end(args); -} - -FMT_DEF int _fmt_parse(char* p, int nargs, const char *fmt, ...) { - char *arg, *p0, ch; - int n = 0, empty; - va_list args; - va_start(args, fmt); - do { - switch ((ch = *fmt)) { - case '%': - *p++ = '%'; - break; - case '}': - if (*++fmt == '}') break; /* ok */ - n = 99; - continue; - case '{': - if (*++fmt == '{') break; /* ok */ - if (++n > nargs) continue; - if (*fmt != ':' && *fmt != '}') n = 99; - fmt += (*fmt == ':'); - empty = *fmt == '}'; - arg = va_arg(args, char *); - *p++ = '%', p0 = p; - while (1) switch (*fmt) { - case '\0': n = 99; /* FALLTHRU */ - case '}': goto done; - case '<': *p++ = '-', ++fmt; break; - case '>': p0 = NULL; /* FALLTHRU */ - case '-': ++fmt; break; - case '*': if (++n <= nargs) arg = va_arg(args, char *); /* FALLTHRU */ - default: *p++ = *fmt++; - } - done: - switch (*arg) { - case 'g': if (empty) memcpy(p, ".8", 2), p += 2; break; - case '@': ++arg; if (empty) memcpy(p, ".16", 3), p += 3; break; - } - if (strchr("csdioxXufFeEaAgGnp", fmt[-1]) == NULL) - while (*arg) *p++ = *arg++; - if (p0 && (p[-1] == 's' || p[-1] == 'c')) /* left-align str */ - memmove(p0 + 1, p0, (size_t)(p++ - p0)), *p0 = '-'; - fmt += *fmt == '}'; - continue; - } - *p++ = *fmt++; - } while (ch); - va_end(args); - return n; -} -#endif -#endif -#undef i_implement -#undef i_static diff --git a/src/finchlite/codegen/stc/include/stc/algorithm.h b/src/finchlite/codegen/stc/include/stc/algorithm.h deleted file mode 100644 index a517a155..00000000 --- a/src/finchlite/codegen/stc/include/stc/algorithm.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef STC_ALGORITHM_H_INCLUDED -#define STC_ALGORITHM_H_INCLUDED - -// IWYU pragma: begin_exports -#include "sys/crange.h" -#include "sys/filter.h" -#include "sys/utility.h" -#include "sys/sumtype.h" -// IWYU pragma: end_exports - -#endif // STC_ALGORITHM_H_INCLUDED diff --git a/src/finchlite/codegen/stc/include/stc/arc.h b/src/finchlite/codegen/stc/include/stc/arc.h deleted file mode 100644 index f703bb67..00000000 --- a/src/finchlite/codegen/stc/include/stc/arc.h +++ /dev/null @@ -1,254 +0,0 @@ -/* 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. - */ -/* arc: atomic reference counted shared_ptr (new implementation) - * - * The difference between arc and arc2 is that arc only takes up one pointer, - * whereas arc2 uses two. arc cannot be constructed from an already allocated pointer, - * which arc2 may. To use arc2, specify the `(c_arc2)` option after the key type, e.g.: - * #define T MyArc, MyType, (c_arc2 | c_no_atomic) - */ -/* -#include - -typedef struct { cstr name, last; } Person; - -Person Person_make(const char* name, const char* last) { - return (Person){.name = cstr_from(name), .last = cstr_from(last)}; -} -Person Person_clone(Person p) { - p.name = cstr_clone(p.name); - p.last = cstr_clone(p.last); - return p; -} -void Person_drop(Person* p) { - printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); - cstr_drop(&p->name); - cstr_drop(&p->last); -} - -#define T ArcPers, Person, (c_keyclass) // clone, drop, cmp, hash -#include - -int main(void) { - ArcPers p = ArcPers_from(Person_make("John", "Smiths")); - ArcPers q = ArcPers_clone(p); // share the pointer - - printf("%s %s. uses: %ld\n", cstr_str(&q.get->name), cstr_str(&q.get->last), ArcPers_use_count(q)); - c_drop(ArcPers, &p, &q); -} -*/ -#include "priv/linkage.h" -#include "types.h" - -#ifndef STC_ARC_H_INCLUDED -#define STC_ARC_H_INCLUDED -#include "common.h" -#include - -#if defined __GNUC__ || defined __clang__ || defined _MSC_VER || defined i_no_atomic - typedef long catomic_long; -#else // try with C11 - typedef _Atomic(long) catomic_long; -#endif -#if defined _MSC_VER - #include - #define c_atomic_inc(v) (void)_InterlockedIncrement(v) - #define c_atomic_dec_and_test(v) !_InterlockedDecrement(v) -#elif defined __GNUC__ || defined __clang__ - #define c_atomic_inc(v) (void)__atomic_add_fetch(v, 1, __ATOMIC_SEQ_CST) - #define c_atomic_dec_and_test(v) !__atomic_sub_fetch(v, 1, __ATOMIC_SEQ_CST) -#else // try with C11 - #include - #define c_atomic_inc(v) (void)atomic_fetch_add(v, 1) - #define c_atomic_dec_and_test(v) (atomic_fetch_sub(v, 1) == 1) -#endif -#endif // STC_ARC_H_INCLUDED - -#ifndef _i_prefix - #define _i_prefix arc_ -#endif -#define _i_is_arc -#include "priv/template.h" -typedef i_keyraw _m_raw; - -#if c_OPTION(c_no_atomic) - #define i_no_atomic -#endif -#if !defined i_no_atomic - #define _i_atomic_inc(v) c_atomic_inc(v) - #define _i_atomic_dec_and_test(v) c_atomic_dec_and_test(v) -#else - #define _i_atomic_inc(v) (void)(++*(v)) - #define _i_atomic_dec_and_test(v) !(--*(v)) -#endif - -#if c_OPTION(c_arc2) - #define i_arc2 -#endif -#if !(defined i_arc2 || defined STC_USE_ARC2) -// ------------ Arc1 size of one pointer (union) ------------- - -#ifndef i_declared -_c_DEFTYPES(declare_arc, Self, i_key); -#endif -struct _c_MEMB(_ctrl) { - _m_value value; - catomic_long counter; -}; - -// c++: std::make_shared<_m_value>(val) -STC_INLINE Self _c_MEMB(_make)(_m_value val) { - Self arc = {.ctrl=_i_new_n(_c_MEMB(_ctrl), 1)}; - arc.ctrl->value = val; - arc.ctrl->counter = 1; - return arc; -} - -STC_INLINE Self _c_MEMB(_toarc)(_m_value* arc_raw) - { Self arc = {.ctrl=(_c_MEMB(_ctrl) *)arc_raw}; return arc; } - -// destructor -STC_INLINE void _c_MEMB(_drop)(const Self* self) { - if (self->ctrl && _i_atomic_dec_and_test(&self->ctrl->counter)) { - i_keydrop(self->get); - i_free(self->ctrl, c_sizeof *self->ctrl); - } -} - -#else // ------------ Arc2 size of two pointers ------------- - -#ifndef i_declared -_c_DEFTYPES(declare_arc2, Self, i_key); -#endif -struct _c_MEMB(_ctrl) { - catomic_long counter; // nb! counter <-> value order is swapped. - _m_value value; -}; -#define ctrl ctrl2 - -// c++: std::make_shared<_m_value>(val) -STC_INLINE Self _c_MEMB(_make)(_m_value val) { - Self out = {.ctrl2=_i_new_n(_c_MEMB(_ctrl), 1)}; - out.ctrl2->counter = 1; - out.get = &out.ctrl2->value; - *out.get = val; - return out; -} - -STC_INLINE Self _c_MEMB(_from_ptr)(_m_value* ptr) { - Self out = {.get=ptr}; - if (ptr) { - enum {OFFSET = offsetof(_c_MEMB(_ctrl), value)}; - // Adds 2 dummy bytes to ensure that the second if-test in _drop() is safe. - catomic_long* _rc = (catomic_long*)i_malloc(OFFSET + 2); - out.ctrl2 = (_c_MEMB(_ctrl)*) _rc; - out.ctrl2->counter = 1; - } - return out; -} - -// destructor -STC_INLINE void _c_MEMB(_drop)(const Self* self) { - if (self->ctrl2 && _i_atomic_dec_and_test(&self->ctrl2->counter)) { - enum {OFFSET = offsetof(_c_MEMB(_ctrl), value)}; - i_keydrop(self->get); - - if ((char*)self->ctrl2 + OFFSET == (char*)self->get) { - i_free((void*)self->ctrl2, c_sizeof *self->ctrl2); // _make() - } else { - i_free((void*)self->ctrl2, OFFSET + 2); // _from_ptr() - i_free(self->get, c_sizeof *self->get); - } - } -} - -// take ownership of pointer p -STC_INLINE void _c_MEMB(_reset_to)(Self* self, _m_value* ptr) { - _c_MEMB(_drop)(self); - *self = _c_MEMB(_from_ptr)(ptr); -} - -#endif // ---------- end Arc2 with two pointers ------------ - -STC_INLINE long _c_MEMB(_use_count)(Self arc) - { return arc.ctrl ? arc.ctrl->counter : 0; } - -STC_INLINE Self _c_MEMB(_init)(void) - { return c_literal(Self){0}; } - -STC_INLINE Self _c_MEMB(_from)(_m_raw raw) - { return _c_MEMB(_make)(i_keyfrom(raw)); } - -STC_INLINE _m_raw _c_MEMB(_toraw)(const Self* self) - { return i_keytoraw(self->get); } - -// move ownership to receiving arc -STC_INLINE Self _c_MEMB(_move)(Self* self) { - Self arc = *self; - *self = (Self){0}; - return arc; // now unowned -} - -// take ownership of unowned arc -STC_INLINE void _c_MEMB(_take)(Self* self, Self unowned) { - _c_MEMB(_drop)(self); - *self = unowned; // now owned -} - -// make shared ownership with owned arc -STC_INLINE void _c_MEMB(_assign)(Self* self, const Self* owned) { - if (owned->ctrl) - _i_atomic_inc(&owned->ctrl->counter); - _c_MEMB(_drop)(self); - *self = *owned; -} - -// clone by sharing. Does not use i_keyclone, so OK to always define. -STC_INLINE Self _c_MEMB(_clone)(Self owned) { - if (owned.ctrl) - _i_atomic_inc(&owned.ctrl->counter); - return owned; -} - -#if defined _i_has_cmp - STC_INLINE int _c_MEMB(_raw_cmp)(const _m_raw* rx, const _m_raw* ry) - { return i_cmp(rx, ry); } -#endif - -#if defined _i_has_eq - STC_INLINE bool _c_MEMB(_raw_eq)(const _m_raw* rx, const _m_raw* ry) - { return i_eq(rx, ry); } -#endif - -#if !defined i_no_hash && defined _i_has_eq - STC_INLINE size_t _c_MEMB(_raw_hash)(const _m_raw* rx) - { return i_hash(rx); } -#endif // i_no_hash - -#undef ctrl -#undef i_no_atomic -#undef i_arc2 -#undef _i_atomic_inc -#undef _i_atomic_dec_and_test -#undef _i_is_arc -#include "sys/finalize.h" diff --git a/src/finchlite/codegen/stc/include/stc/box.h b/src/finchlite/codegen/stc/include/stc/box.h deleted file mode 100644 index 366bda58..00000000 --- a/src/finchlite/codegen/stc/include/stc/box.h +++ /dev/null @@ -1,168 +0,0 @@ - -/* 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. - */ - -/* cbox: heap allocated boxed type -#include - -typedef struct { cstr name, email; } Person; - -Person Person_from(const char* name, const char* email) { - return (Person){.name = cstr_from(name), .email = cstr_from(email)}; -} -Person Person_clone(Person p) { - p.name = cstr_clone(p.name); - p.email = cstr_clone(p.email); - return p; -} -void Person_drop(Person* p) { - printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->email)); - c_drop(cstr, &p->name, &p->email); -} - -#define T PBox, Person, (c_keyclass) // bind Person clone+drop fn's -#include - -int main(void) { - PBox p = PBox_from(Person_from("John Smiths", "josmiths@gmail.com")); - PBox q = PBox_clone(p); - cstr_assign(&q.get->name, "Joe Smiths"); - - printf("%s %s.\n", cstr_str(&p.get->name), cstr_str(&p.get->email)); - printf("%s %s.\n", cstr_str(&q.get->name), cstr_str(&q.get->email)); - - c_drop(PBox, &p, &q); -} -*/ -#include "priv/linkage.h" -#include "types.h" - -#ifndef STC_BOX_H_INCLUDED -#define STC_BOX_H_INCLUDED -#include "common.h" -#include - -#define cbox_null {0} -#endif // STC_BOX_H_INCLUDED - -#ifndef _i_prefix - #define _i_prefix box_ -#endif -#define _i_is_box -#include "priv/template.h" -typedef i_keyraw _m_raw; - -#ifndef i_declared -_c_DEFTYPES(declare_box, Self, i_key); -#endif - -// constructors (take ownership) -STC_INLINE Self _c_MEMB(_init)(void) - { return c_literal(Self){0}; } - -STC_INLINE long _c_MEMB(_use_count)(const Self* self) - { return (long)(self->get != NULL); } - - -// c++: std::make_unique(val) -STC_INLINE Self _c_MEMB(_make)(_m_value val) { - Self box = {_i_new_n(_m_value, 1)}; - *box.get = val; - return box; -} - -STC_INLINE Self _c_MEMB(_from_ptr)(_m_value* p) - { return c_literal(Self){p}; } - -STC_INLINE Self _c_MEMB(_from)(_m_raw raw) - { return _c_MEMB(_make)(i_keyfrom(raw)); } - -STC_INLINE _m_raw _c_MEMB(_toraw)(const Self* self) - { return i_keytoraw(self->get); } - -// destructor -STC_INLINE void _c_MEMB(_drop)(const Self* self) { - if (self->get) { - i_keydrop(self->get); - i_free(self->get, c_sizeof *self->get); - } -} - -// move ownership to receiving box -STC_INLINE Self _c_MEMB(_move)(Self* self) { - Self box = *self; - self->get = NULL; - return box; -} - -// release owned pointer, must be manually freed by receiver -STC_INLINE _m_value* _c_MEMB(_release)(Self* self) - { return _c_MEMB(_move)(self).get; } - -// take ownership of pointer p -STC_INLINE void _c_MEMB(_reset_to)(Self* self, _m_value* p) { - _c_MEMB(_drop)(self); - self->get = p; -} - -// take ownership of unowned box -STC_INLINE void _c_MEMB(_take)(Self* self, Self unowned) { - _c_MEMB(_drop)(self); - *self = unowned; -} - -// transfer ownership from other; set other to NULL -STC_INLINE void _c_MEMB(_assign)(Self* self, Self* owned) { - if (owned->get == self->get) - return; - _c_MEMB(_drop)(self); - *self = *owned; - owned->get = NULL; -} - -#ifndef i_no_clone - STC_INLINE Self _c_MEMB(_clone)(Self other) { - if (other.get == NULL) return other; - Self out = {_i_new_n(_m_value, 1)}; - *out.get = i_keyclone((*other.get)); - return out; - } -#endif // !i_no_clone - - -#if defined _i_has_cmp - STC_INLINE int _c_MEMB(_raw_cmp)(const _m_raw* rx, const _m_raw* ry) - { return i_cmp(rx, ry); } -#endif - -#if defined _i_has_eq - STC_INLINE bool _c_MEMB(_raw_eq)(const _m_raw* rx, const _m_raw* ry) - { return i_eq(rx, ry); } -#endif - -#if !defined i_no_hash && defined _i_has_eq - STC_INLINE size_t _c_MEMB(_raw_hash)(const _m_raw* rx) - { return i_hash(rx); } -#endif // i_no_hash -#undef _i_is_box -#include "sys/finalize.h" diff --git a/src/finchlite/codegen/stc/include/stc/cbits.h b/src/finchlite/codegen/stc/include/stc/cbits.h deleted file mode 100644 index ac424ba4..00000000 --- a/src/finchlite/codegen/stc/include/stc/cbits.h +++ /dev/null @@ -1,336 +0,0 @@ -/* 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. - */ -/* -Similar to boost::dynamic_bitset / std::bitset - -#include -#include "cbits.h" - -int main(void) { - cbits bset = cbits_with_size(23, true); - cbits_reset(&bset, 9); - cbits_resize(&bset, 43, false); - - printf("%4d: ", (int)cbits_size(&bset)); - for (c_range(i, cbits_size(&bset))) - printf("%d", cbits_at(&bset, i)); - puts(""); - cbits_set(&bset, 28); - cbits_resize(&bset, 77, true); - cbits_resize(&bset, 93, false); - cbits_resize(&bset, 102, true); - cbits_set_value(&bset, 99, false); - - printf("%4d: ", (int)cbits_size(&bset)); - for (c_range(i, cbits_size(&bset))) - printf("%d", cbits_at(&bset, i)); - puts(""); - - cbits_drop(&bset); -} -*/ -#include "priv/linkage.h" -#ifndef STC_CBITS_H_INCLUDED -#define STC_CBITS_H_INCLUDED -#include "common.h" -#include - -#if INTPTR_MAX == INT64_MAX -#define _gnu_popc(x) __builtin_popcountll(x) -#define _msc_popc(x) (int)__popcnt64(x) -#else -#define _gnu_popc(x) __builtin_popcount(x) -#define _msc_popc(x) (int)__popcnt(x) -#endif -#define _cbits_WS c_sizeof(uintptr_t) -#define _cbits_WB (8*_cbits_WS) -#define _cbits_bit(i) ((uintptr_t)1 << ((i) & (_cbits_WB - 1))) -#define _cbits_words(n) (isize)(((n) + (_cbits_WB - 1))/_cbits_WB) -#define _cbits_bytes(n) (_cbits_words(n)*_cbits_WS) - -#if defined _MSC_VER - #include - STC_INLINE int c_popcount(uintptr_t x) { return _msc_popc(x); } -#elif defined __GNUC__ || defined __clang__ - STC_INLINE int c_popcount(uintptr_t x) { return _gnu_popc(x); } -#else - STC_INLINE int c_popcount(uintptr_t x) { /* http://en.wikipedia.org/wiki/Hamming_weight */ - x -= (x >> 1) & (uintptr_t)0x5555555555555555; - x = (x & (uintptr_t)0x3333333333333333) + ((x >> 2) & (uintptr_t)0x3333333333333333); - x = (x + (x >> 4)) & (uintptr_t)0x0f0f0f0f0f0f0f0f; - return (int)((x*(uintptr_t)0x0101010101010101) >> (_cbits_WB - 8)); - } -#endif -#if defined __GNUC__ && !defined __clang__ && !defined __cplusplus -#pragma GCC diagnostic ignored "-Walloc-size-larger-than=" // gcc 11.4 -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // gcc 11.4 -#endif - -#define cbits_print(...) c_MACRO_OVERLOAD(cbits_print, __VA_ARGS__) -#define cbits_print_1(self) cbits_print_4(self, stdout, 0, -1) -#define cbits_print_2(self, stream) cbits_print_4(self, stream, 0, -1) -#define cbits_print_4(self, stream, start, end) cbits_print_5(cbits, self, stream, start, end) -#define cbits_print_3(SetType, self, stream) cbits_print_5(SetType, self, stream, 0, -1) -#define cbits_print_5(SetType, self, stream, start, end) do { \ - const SetType* _cb_set = self; \ - isize _cb_start = start, _cb_end = end; \ - if (_cb_end == -1) _cb_end = SetType##_size(_cb_set); \ - for (c_range_3(_cb_i, _cb_start, _cb_end)) \ - fputc(SetType##_test(_cb_set, _cb_i) ? '1' : '0', stream); \ -} while (0) - -STC_INLINE isize _cbits_count(const uintptr_t* set, const isize sz) { - const isize n = sz/_cbits_WB; - isize count = 0; - for (isize i = 0; i < n; ++i) - count += c_popcount(set[i]); - if (sz & (_cbits_WB - 1)) - count += c_popcount(set[n] & (_cbits_bit(sz) - 1)); - return count; -} - -STC_INLINE char* _cbits_to_str(const uintptr_t* set, const isize sz, - char* out, isize start, isize stop) { - if (stop > sz) stop = sz; - c_assert(start <= stop); - - c_memset(out, '0', stop - start); - for (isize i = start; i < stop; ++i) - if ((set[i/_cbits_WB] & _cbits_bit(i)) != 0) - out[i - start] = '1'; - out[stop - start] = '\0'; - return out; -} - -#define _cbits_OPR(OPR, VAL) \ - const isize n = sz/_cbits_WB; \ - for (isize i = 0; i < n; ++i) \ - if ((set[i] OPR other[i]) != VAL) \ - return false; \ - if ((sz & (_cbits_WB - 1)) == 0) \ - return true; \ - const uintptr_t i = (uintptr_t)n, m = _cbits_bit(sz) - 1; \ - return ((set[i] OPR other[i]) & m) == (VAL & m) - -STC_INLINE bool _cbits_subset_of(const uintptr_t* set, const uintptr_t* other, const isize sz) - { _cbits_OPR(|, set[i]); } - -STC_INLINE bool _cbits_disjoint(const uintptr_t* set, const uintptr_t* other, const isize sz) - { _cbits_OPR(&, 0); } - -#endif // STC_CBITS_H_INCLUDED - -#if defined T && !defined i_type - #define i_type T -#endif -#if defined i_type - #define Self c_GETARG(1, i_type) - #define _i_length c_GETARG(2, i_type) -#else - #define Self cbits -#endif -#ifndef i_allocator - #define i_allocator c -#endif -#define _i_MEMB(name) c_JOIN(Self, name) - - -#if !defined _i_length // DYNAMIC SIZE BITARRAY - -typedef struct { uintptr_t *buffer; isize _size; } Self; -#define _i_assert(x) c_assert(x) - -STC_INLINE void cbits_drop(cbits* self) { i_free(self->buffer, _cbits_bytes(self->_size)); } -STC_INLINE isize cbits_size(const cbits* self) { return self->_size; } - -STC_INLINE cbits* cbits_take(cbits* self, cbits other) { - if (self->buffer != other.buffer) { - cbits_drop(self); - *self = other; - } - return self; -} - -STC_INLINE cbits cbits_clone(cbits other) { - cbits set = other; - const isize bytes = _cbits_bytes(other._size); - set.buffer = (uintptr_t *)c_safe_memcpy(i_malloc(bytes), other.buffer, bytes); - return set; -} - -STC_INLINE cbits* cbits_copy(cbits* self, const cbits* other) { - if (self->buffer == other->buffer) - return self; - if (self->_size != other->_size) - return cbits_take(self, cbits_clone(*other)); - c_memcpy(self->buffer, other->buffer, _cbits_bytes(other->_size)); - return self; -} - -STC_INLINE bool cbits_resize(cbits* self, const isize size, const bool value) { - const isize new_w = _cbits_words(size), osize = self->_size, old_w = _cbits_words(osize); - uintptr_t* b = (uintptr_t *)i_realloc(self->buffer, old_w*_cbits_WS, new_w*_cbits_WS); - if (b == NULL) return false; - self->buffer = b; self->_size = size; - if (size > osize) { - c_memset(self->buffer + old_w, -(int)value, (new_w - old_w)*_cbits_WS); - if (osize & (_cbits_WB - 1)) { - uintptr_t mask = _cbits_bit(osize) - 1; - if (value) self->buffer[old_w - 1] |= ~mask; - else self->buffer[old_w - 1] &= mask; - } - } - return true; -} - -STC_INLINE void cbits_set_all(cbits *self, const bool value); -STC_INLINE void cbits_set_pattern(cbits *self, const uintptr_t pattern); - -STC_INLINE cbits cbits_move(cbits* self) { - cbits tmp = *self; - self->buffer = NULL, self->_size = 0; - return tmp; -} - -STC_INLINE cbits cbits_with_size(const isize size, const bool value) { - cbits set = {(uintptr_t *)i_malloc(_cbits_bytes(size)), size}; - cbits_set_all(&set, value); - return set; -} - -STC_INLINE cbits cbits_with_pattern(const isize size, const uintptr_t pattern) { - cbits set = {(uintptr_t *)i_malloc(_cbits_bytes(size)), size}; - cbits_set_pattern(&set, pattern); - return set; -} - -#else // _i_length: FIXED SIZE BITARRAY - -#define _i_assert(x) (void)0 - -typedef struct { uintptr_t buffer[(_i_length - 1)/_cbits_WB + 1]; } Self; - -STC_INLINE void _i_MEMB(_drop)(Self* self) { (void)self; } -STC_INLINE isize _i_MEMB(_size)(const Self* self) { (void)self; return _i_length; } -STC_INLINE Self _i_MEMB(_move)(Self* self) { return *self; } -STC_INLINE Self* _i_MEMB(_take)(Self* self, Self other) { *self = other; return self; } -STC_INLINE Self _i_MEMB(_clone)(Self other) { return other; } -STC_INLINE void _i_MEMB(_copy)(Self* self, const Self* other) { *self = *other; } -STC_INLINE void _i_MEMB(_set_all)(Self *self, const bool value); -STC_INLINE void _i_MEMB(_set_pattern)(Self *self, const uintptr_t pattern); - -STC_INLINE Self _i_MEMB(_with_size)(const isize size, const bool value) { - c_assert(size <= _i_length); - Self set; _i_MEMB(_set_all)(&set, value); - return set; -} - -STC_INLINE Self _i_MEMB(_with_pattern)(const isize size, const uintptr_t pattern) { - c_assert(size <= _i_length); - Self set; _i_MEMB(_set_pattern)(&set, pattern); - return set; -} -#endif // _i_length - -// COMMON: - -STC_INLINE void _i_MEMB(_set_all)(Self *self, const bool value) - { c_memset(self->buffer, -(int)value, _cbits_bytes(_i_MEMB(_size)(self))); } - -STC_INLINE void _i_MEMB(_set_pattern)(Self *self, const uintptr_t pattern) { - isize n = _cbits_words(_i_MEMB(_size)(self)); - while (n--) self->buffer[n] = pattern; -} - -STC_INLINE bool _i_MEMB(_test)(const Self* self, const isize i) - { return (self->buffer[i/_cbits_WB] & _cbits_bit(i)) != 0; } - -STC_INLINE bool _i_MEMB(_at)(const Self* self, const isize i) - { c_assert(c_uless(i, _i_MEMB(_size)(self))); return _i_MEMB(_test)(self, i); } - -STC_INLINE void _i_MEMB(_set)(Self *self, const isize i) - { self->buffer[i/_cbits_WB] |= _cbits_bit(i); } - -STC_INLINE void _i_MEMB(_reset)(Self *self, const isize i) - { self->buffer[i/_cbits_WB] &= ~_cbits_bit(i); } - -STC_INLINE void _i_MEMB(_set_value)(Self *self, const isize i, const bool b) { - self->buffer[i/_cbits_WB] ^= ((uintptr_t)-(int)b ^ self->buffer[i/_cbits_WB]) & _cbits_bit(i); -} - -STC_INLINE void _i_MEMB(_flip)(Self *self, const isize i) - { self->buffer[i/_cbits_WB] ^= _cbits_bit(i); } - -STC_INLINE void _i_MEMB(_flip_all)(Self *self) { - isize n = _cbits_words(_i_MEMB(_size)(self)); - while (n--) self->buffer[n] ^= ~(uintptr_t)0; -} - -STC_INLINE Self _i_MEMB(_from)(const char* str) { - isize n = c_strlen(str); - Self set = _i_MEMB(_with_size)(n, false); - while (n--) if (str[n] == '1') _i_MEMB(_set)(&set, n); - return set; -} - -/* Intersection */ -STC_INLINE void _i_MEMB(_intersect)(Self *self, const Self* other) { - _i_assert(self->_size == other->_size); - isize n = _cbits_words(_i_MEMB(_size)(self)); - while (n--) self->buffer[n] &= other->buffer[n]; -} -/* Union */ -STC_INLINE void _i_MEMB(_union)(Self *self, const Self* other) { - _i_assert(self->_size == other->_size); - isize n = _cbits_words(_i_MEMB(_size)(self)); - while (n--) self->buffer[n] |= other->buffer[n]; -} -/* Exclusive disjunction */ -STC_INLINE void _i_MEMB(_xor)(Self *self, const Self* other) { - _i_assert(self->_size == other->_size); - isize n = _cbits_words(_i_MEMB(_size)(self)); - while (n--) self->buffer[n] ^= other->buffer[n]; -} - -STC_INLINE isize _i_MEMB(_count)(const Self* self) - { return _cbits_count(self->buffer, _i_MEMB(_size)(self)); } - -STC_INLINE char* _i_MEMB(_to_str)(const Self* self, char* out, isize start, isize stop) - { return _cbits_to_str(self->buffer, _i_MEMB(_size)(self), out, start, stop); } - -STC_INLINE bool _i_MEMB(_subset_of)(const Self* self, const Self* other) { - _i_assert(self->_size == other->_size); - return _cbits_subset_of(self->buffer, other->buffer, _i_MEMB(_size)(self)); -} - -STC_INLINE bool _i_MEMB(_disjoint)(const Self* self, const Self* other) { - _i_assert(self->_size == other->_size); - return _cbits_disjoint(self->buffer, other->buffer, _i_MEMB(_size)(self)); -} - -#include "priv/linkage2.h" -#undef i_type -#undef _i_length -#undef _i_MEMB -#undef _i_assert -#undef Self diff --git a/src/finchlite/codegen/stc/include/stc/common.h b/src/finchlite/codegen/stc/include/stc/common.h deleted file mode 100644 index fce1829d..00000000 --- a/src/finchlite/codegen/stc/include/stc/common.h +++ /dev/null @@ -1,359 +0,0 @@ -/* 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_item(v, C, cnt) \ - C##_value* v = (C##_value*)&v; v; ) \ - for (C##_iter v##_it = C##_begin(&cnt); (v = v##_it.ref); C##_next(&v##_it) - -#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 diff --git a/src/finchlite/codegen/stc/include/stc/coption.h b/src/finchlite/codegen/stc/include/stc/coption.h deleted file mode 100644 index 67650645..00000000 --- a/src/finchlite/codegen/stc/include/stc/coption.h +++ /dev/null @@ -1,180 +0,0 @@ -/* 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. - */ -/* -Inspired by https://attractivechaos.wordpress.com/2018/08/31/a-survey-of-argument-parsing-libraries-in-c-c -Fixed major bugs with optional arguments (both long and short). -Added arg->optstr output field, more consistent API. - -coption_get() is similar to GNU's getopt_long(). Each call parses one option and -returns the option name. opt->arg points to the option argument if present. -The function returns -1 when all command-line arguments are parsed. In this case, -opt->ind is the index of the first non-option argument. - -#include -#include - -int main(int argc, char *argv[]) -{ - coption_long longopts[] = { - {"foo", coption_no_argument, 'f'}, - {"bar", coption_required_argument, 'b'}, - {"opt", coption_optional_argument, 'o'}, - {0} - }; - const char* optstr = "xy:z::123"; - printf("program -x -y ARG -z [ARG] -1 -2 -3 --foo --bar ARG --opt [ARG] [ARGUMENTS]\n"); - int c; - coption opt = coption_init(); - while ((c = coption_get(&opt, argc, argv, optstr, longopts)) != -1) { - switch (c) { - case '?': printf("error: unknown option: %s\n", opt.optstr); return 1; - case ':': printf("error: missing argument for %s (%c)\n", opt.optstr, opt.opt); return 2; - default: printf("option: %c [%s]\n", opt.opt, opt.arg ? opt.arg : ""); break; - } - } - printf("\nNon-option arguments:"); - for (int i = opt.ind; i < argc; ++i) - printf(" %s", argv[i]); - putchar('\n'); - return 0; -} -*/ -#ifndef STC_COPTION_H_INCLUDED -#define STC_COPTION_H_INCLUDED - -#include -#include - -typedef enum { - coption_no_argument, - coption_required_argument, - coption_optional_argument -} coption_type; - -typedef struct { - const char *name; - coption_type type; - int val; -} coption_long; - -typedef struct { - int ind; /* equivalent to optind */ - int opt; /* equivalent to optopt */ - const char *optstr; /* points to the option string */ - const char *arg; /* equivalent to optarg */ - int _i, _pos, _nargs; - char _optstr[4]; -} coption; - -static inline coption coption_init(void) { - coption opt = {1, 0, NULL, NULL, 1, 0, 0, {'-', '?', '\0'}}; - return opt; -} - -/* move argv[j] over n elements to the left */ -static void coption_permute_(char *argv[], int j, int n) { - int k; - char *p = argv[j]; - for (k = 0; k < n; ++k) - argv[j - k] = argv[j - k - 1]; - argv[j - k] = p; -} - -/* @param opt output; must be initialized to coption_init() on first call - * @return ASCII val for a short option; longopt.val for a long option; - * -1 if argv[] is fully processed; '?' for an unknown option or - * an ambiguous long option; ':' if an option argument is missing - */ -static int coption_get(coption *opt, int argc, char *argv[], - const char *shortopts, const coption_long *longopts) { - int optc = -1, i0, j, posixly_correct = (shortopts && shortopts[0] == '+'); - if (!posixly_correct) { - while (opt->_i < argc && (argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0')) - ++opt->_i, ++opt->_nargs; - } - opt->opt = 0, opt->optstr = NULL, opt->arg = NULL, i0 = opt->_i; - if (opt->_i >= argc || argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0') { - opt->ind = opt->_i - opt->_nargs; - return -1; - } - if (argv[opt->_i][0] == '-' && argv[opt->_i][1] == '-') { /* "--" or a long option */ - if (argv[opt->_i][2] == '\0') { /* a bare "--" */ - coption_permute_(argv, opt->_i, opt->_nargs); - ++opt->_i, opt->ind = opt->_i - opt->_nargs; - return -1; - } - optc = '?', opt->_pos = -1; - if (longopts) { /* parse long options */ - int k, n_exact = 0, n_partial = 0; - const coption_long *o = 0, *o_exact = 0, *o_partial = 0; - for (j = 2; argv[opt->_i][j] != '\0' && argv[opt->_i][j] != '='; ++j) {} /* find the end of the option name */ - for (k = 0; longopts[k].name != 0; ++k) - if (strncmp(&argv[opt->_i][2], longopts[k].name, (size_t)(j - 2)) == 0) { - if (longopts[k].name[j - 2] == 0) ++n_exact, o_exact = &longopts[k]; - else ++n_partial, o_partial = &longopts[k]; - } - opt->optstr = argv[opt->_i]; - if (n_exact > 1 || (n_exact == 0 && n_partial > 1)) return '?'; - o = n_exact == 1? o_exact : n_partial == 1? o_partial : 0; - if (o) { - opt->opt = optc = o->val; - if (o->type != coption_no_argument) { - if (argv[opt->_i][j] == '=') - opt->arg = &argv[opt->_i][j + 1]; - else if (argv[opt->_i][j] == '\0' && opt->_i < argc - 1 && (o->type == coption_required_argument || - argv[opt->_i + 1][0] != '-')) - opt->arg = argv[++opt->_i]; - else if (o->type == coption_required_argument) - optc = ':'; /* missing option argument */ - } - } - } - } else if (shortopts) { /* a short option */ - const char *p; - if (opt->_pos == 0) opt->_pos = 1; - optc = opt->opt = argv[opt->_i][opt->_pos++]; - opt->_optstr[1] = optc, opt->optstr = opt->_optstr; - p = strchr(shortopts, optc); - if (p == 0) { - optc = '?'; /* unknown option */ - } else if (p[1] == ':') { - if (argv[opt->_i][opt->_pos] != '\0') - opt->arg = &argv[opt->_i][opt->_pos]; - else if (opt->_i < argc - 1 && (p[2] != ':' || argv[opt->_i + 1][0] != '-')) - opt->arg = argv[++opt->_i]; - else if (p[2] != ':') - optc = ':'; - opt->_pos = -1; - } - } - if (opt->_pos < 0 || argv[opt->_i][opt->_pos] == 0) { - ++opt->_i, opt->_pos = 0; - if (opt->_nargs > 0) /* permute */ - for (j = i0; j < opt->_i; ++j) - coption_permute_(argv, j, opt->_nargs); - } - opt->ind = opt->_i - opt->_nargs; - return optc; -} - -#endif // STC_COPTION_H_INCLUDED diff --git a/src/finchlite/codegen/stc/include/stc/coroutine.h b/src/finchlite/codegen/stc/include/stc/coroutine.h deleted file mode 100644 index b7a7163b..00000000 --- a/src/finchlite/codegen/stc/include/stc/coroutine.h +++ /dev/null @@ -1,584 +0,0 @@ -/* 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_COROUTINE_H_INCLUDED -#define STC_COROUTINE_H_INCLUDED -/* -#include -#include - -struct iterpair { - cco_base base; // required member - int max_x, max_y; - int x, y; -}; - -int iterpair(struct iterpair* I) { - cco_async (I) { - for (I->x = 0; I->x < I->max_x; I->x++) - for (I->y = 0; I->y < I->max_y; I->y++) - cco_yield; // suspend - } - - puts("done"); - return 0; // CCO_DONE -} - -int main(void) { - struct iterpair it = {.max_x=3, .max_y=3}; - int n = 0; - while (iterpair(&it)) - { - printf("%d %d\n", it.x, it.y); - // example of early stop: - if (++n == 7) cco_stop(&it); // signal to stop/finalize in next - } - return 0; -} -*/ -#include -#include "common.h" - -enum { - CCO_STATE_INIT = 0, - CCO_STATE_DONE = -1, - CCO_STATE_DROP = -2, -}; -enum cco_status { - CCO_DONE = 0, - CCO_YIELD = 1<<12, - CCO_SUSPEND = 1<<13, - CCO_AWAIT = 1<<14, -}; -#define CCO_CANCEL (1U<<30) - -typedef struct { - int spawn_count; - int await_count; -} cco_group; // waitgroup - -#define cco_state_struct(Prefix) \ - struct Prefix##_state { \ - int32_t pos:24; \ - bool drop; \ - struct Prefix##_fiber* fb; \ - cco_group* wg; \ - } - -#define cco_is_initial(co) ((co)->base.state.pos == CCO_STATE_INIT) -#define cco_is_done(co) ((co)->base.state.pos == CCO_STATE_DONE) -#define cco_is_active(co) ((co)->base.state.pos != CCO_STATE_DONE) - -#if defined STC_HAS_TYPEOF && STC_HAS_TYPEOF - #define _cco_state(co) __typeof__((co)->base.state) - #define _cco_validate_task_struct(co) \ - c_static_assert(/* error: co->base not first member in task struct */ \ - sizeof((co)->base) == sizeof(cco_base) || \ - offsetof(__typeof__(*(co)), base) == 0) -#else - #define _cco_state(co) cco_state - #define _cco_validate_task_struct(co) (void)0 -#endif - -#define cco_async(co) \ - if (0) goto _resume_lbl; \ - else for (_cco_state(co)* _state = (_cco_validate_task_struct(co), (_cco_state(co)*) &(co)->base.state) \ - ; _state->pos != CCO_STATE_DONE \ - ; _state->pos = CCO_STATE_DONE, \ - (void)(sizeof((co)->base) > sizeof(cco_base) && _state->wg ? --_state->wg->spawn_count : 0)) \ - _resume_lbl: switch (_state->pos) case CCO_STATE_INIT: // thanks, @liigo! - -#define cco_finalize /* label */ \ - _state->drop = true; /* FALLTHRU */ \ - case CCO_STATE_DROP - -#define cco_drop cco_finalize // [deprecated] -#define cco_cleanup [fix: use cco_finalize:] -#define cco_routine [fix: use cco_async] - -#define cco_stop(co) \ - do { \ - cco_state* _s = (cco_state*)&(co)->base.state; \ - if (!_s->drop) { _s->pos = CCO_STATE_DROP; _s->drop = true; } \ - } while (0) - -#define cco_reset_state(co) \ - do { \ - cco_state* _s = (cco_state*)&(co)->base.state; \ - _s->pos = CCO_STATE_INIT, _s->drop = false; \ - } while (0) - -#define cco_return \ - do { \ - _state->pos = (_state->drop ? CCO_STATE_DONE : CCO_STATE_DROP); \ - _state->drop = true; \ - goto _resume_lbl; \ - } while (0) - -#define cco_exit() \ - do { \ - _state->pos = CCO_STATE_DONE; \ - goto _resume_lbl; \ - } while (0) - -#define cco_yield_v(status) \ - do { \ - _state->pos = __LINE__; return status; \ - case __LINE__:; \ - } while (0) - -#define cco_yield \ - cco_yield_v(CCO_YIELD) - -#define cco_suspend \ - cco_yield_v(CCO_SUSPEND) - -#define cco_await(until) \ - do { \ - _state->pos = __LINE__; /* FALLTHRU */ \ - case __LINE__: if (!(until)) return CCO_AWAIT; \ - } while (0) - -/* cco_await_coroutine(): assumes coroutine returns a status value (int) */ -#define cco_await_coroutine(...) c_MACRO_OVERLOAD(cco_await_coroutine, __VA_ARGS__) -#define cco_await_coroutine_1(corocall) cco_await_coroutine_2(corocall, CCO_DONE) -#define cco_await_coroutine_2(corocall, awaitbits) \ - do { \ - _state->pos = __LINE__; /* FALLTHRU */ \ - case __LINE__: { \ - int _res = corocall; \ - if (_res & ~(awaitbits)) return _res; \ - } \ - } while (0) - -/* cco_run_coroutine(): assumes coroutine returns a status value (int) */ -#define cco_run_coroutine(corocall) \ - while ((1 ? (corocall) : -1) != CCO_DONE) - - -/* - * Tasks and Fibers - */ -struct cco_error { - int32_t code, line; - const char* file; -}; - -#define cco_fiber_struct(Prefix, Env) \ - typedef Env Prefix##_env; \ - struct Prefix##_fiber { \ - struct cco_task* task; \ - Prefix##_env* env; \ - cco_group* wgcurr; \ - struct cco_task* parent_task; \ - struct cco_task_fiber* next; \ - struct cco_task_state recover_state; \ - struct cco_error err; \ - int awaitbits, status; \ - cco_base base; /* is a coroutine object itself */ \ - } - -/* Define a Task struct */ -#define cco_task_struct(...) c_MACRO_OVERLOAD(cco_task_struct, __VA_ARGS__) -#define cco_task_struct_1(Task) \ - cco_task_struct_2(Task, void) - -#define cco_task_struct_2(Task, Env) \ - cco_fiber_struct(Task, Env); \ - cco_state_struct(Task); \ - _cco_task_struct(Task) - -#define _cco_task_struct(Task) \ - struct Task; \ - typedef struct { \ - int (*func)(struct Task*); \ - int awaitbits; \ - struct Task##_state state; \ - struct cco_task* parent_task; \ - } Task##_base; \ - struct Task - -/* Base cco_task type */ -typedef cco_state_struct(cco_task) cco_state; -typedef struct { cco_state state; } cco_base; -cco_fiber_struct(cco_task, void); -_cco_task_struct(cco_task) { cco_task_base base; }; -typedef struct cco_task_fiber cco_fiber; -typedef struct cco_task cco_task; - -#define cco_err() (&_state->fb->err) -#define cco_status() (_state->fb->status + 0) -#define cco_fb(task) ((cco_fiber*)(task)->base.state.fb + 0) -#define cco_env(task) (task)->base.state.fb->env -#define cco_set_env(task, the_env) ((task)->base.state.fb->env = the_env) - -#define cco_cast_task(...) \ - ((void)sizeof((__VA_ARGS__)->base.func(__VA_ARGS__)), (cco_task *)(__VA_ARGS__)) - -/* Return with error and unwind await stack; must be recovered in cco_finalize section */ -#define cco_throw(error_code) \ - do { \ - cco_fiber* _fb = (cco_fiber*)_state->fb; \ - _fb->err.code = error_code; \ - _fb->err.line = __LINE__; \ - _fb->err.file = __FILE__; \ - cco_return; \ - } while (0) - -#define cco_cancel_fiber(a_fiber) \ - do { \ - cco_fiber* _fb1 = a_fiber; \ - _fb1->err.code = CCO_CANCEL; \ - _fb1->err.line = __LINE__; \ - _fb1->err.file = __FILE__; \ - cco_stop(_fb1->task); \ - } while (0) - -/* Cancel job/task and unwind await stack; MAY be stopped (recovered) in cco_finalize section */ -/* Equals cco_throw(CCO_CANCEL) if a_task is in current fiber. */ -#define cco_cancel_task(a_task) \ - do { \ - cco_task* _tsk1 = cco_cast_task(a_task); \ - cco_cancel_fiber(_tsk1->base.state.fb); \ - cco_stop(_tsk1); \ - if (_tsk1 == _state->fb->task) goto _resume_lbl; \ - } while (0) - -#define cco_await_cancel_task(a_task) do { \ - cco_cancel_task(a_task); \ - cco_await_task(a_task); \ -} while (0) - - -#define cco_cancel_group(waitgroup) \ - _cco_cancel_group((cco_fiber*)_state->fb, waitgroup) - -#define cco_cancel_all() \ - for (cco_fiber *_fbi = _state->fb->next; _fbi != (cco_fiber*)_state->fb; _fbi = _fbi->next) \ - cco_cancel_fiber(_fbi) \ - -/* Recover the thrown error; to be used in cco_finalize section upon handling cco_err()->code */ -#define cco_recover \ - do { \ - cco_fiber* _fb = (cco_fiber*)_state->fb; \ - c_assert(_fb->err.code); \ - _fb->task->base.state = _fb->recover_state; \ - _fb->err.code = 0; \ - goto _resume_lbl; \ - } while (0) - -/* Asymmetric coroutine await/call */ -#define cco_await_task(...) c_MACRO_OVERLOAD(cco_await_task, __VA_ARGS__) -#define cco_await_task_1(a_task) cco_await_task_2(a_task, CCO_DONE) -#define cco_await_task_2(a_task, _awaitbits) do { \ - { cco_task* _await_task = cco_cast_task(a_task); \ - (void)sizeof(cco_env(a_task) == _state->fb->env); \ - cco_fiber* _fb = (cco_fiber*)_state->fb; \ - _await_task->base.awaitbits = (_awaitbits); \ - _await_task->base.parent_task = _fb->task; \ - _fb->task = _await_task; \ - _await_task->base.state.fb = _fb; \ - } \ - cco_suspend; \ -} while (0) - -/* Symmetric coroutine flow of control transfer */ -#define cco_yield_to(a_task) do { \ - { cco_task* _to_task = cco_cast_task(a_task); \ - (void)sizeof(cco_env(a_task) == _state->fb->env); \ - cco_fiber* _fb = (cco_fiber*)_state->fb; \ - _to_task->base.awaitbits = _fb->task->base.awaitbits; \ - _to_task->base.parent_task = NULL; \ - _fb->task = _to_task; \ - _to_task->base.state.fb = _fb; \ - } \ - cco_suspend; \ -} while (0) - -#define cco_resume(a_task) \ - _cco_resume_task(cco_cast_task(a_task)) - -static inline int _cco_resume_task(cco_task* task) - { return task->base.func(task); } - -/* - * cco_run_fiber()/cco_run_task(): Run fibers/tasks in parallel - */ -#define cco_new_fiber(...) c_MACRO_OVERLOAD(cco_new_fiber, __VA_ARGS__) -#define cco_new_fiber_1(task) \ - _cco_new_fiber(cco_cast_task(task), NULL, NULL) -#define cco_new_fiber_2(task, env) \ - _cco_new_fiber(cco_cast_task(task), ((void)sizeof((env) == cco_env(task)), env), NULL) - -#define cco_reset_group(wg) ((wg)->spawn_count = 0) -#define cco_spawn(...) c_MACRO_OVERLOAD(cco_spawn, __VA_ARGS__) -#define cco_spawn_1(task) cco_spawn_4(task, NULL, NULL, _state->fb) -#define cco_spawn_2(task, wg) cco_spawn_4(task, wg, NULL, _state->fb) -#define cco_spawn_3(task, wg, env) cco_spawn_4(task, wg, env, _state->fb) -#define cco_spawn_4(task, wg, env, fiber) \ - _cco_spawn(cco_cast_task(task), wg, ((void)sizeof((env) == cco_env(task)), env), \ - (cco_fiber*)((void)sizeof((fiber)->parent_task), fiber)) - -#define cco_await_group(waitgroup) do { \ - cco_task* top = _state->fb->task; \ - while (top->base.parent_task) \ - top = top->base.parent_task; \ - _state->fb->wgcurr = waitgroup; \ - /* wait until spawn_count = 1 to not wait for itself to finish, else until it is 0 */ \ - _state->fb->wgcurr->await_count = (top->base.state.wg == _state->fb->wgcurr); \ - cco_await(_state->fb->wgcurr->spawn_count == _state->fb->wgcurr->await_count); \ -} while (0) - -#define cco_await_n(waitgroup, n) do { \ - _state->fb->wgcurr = waitgroup; \ - _state->fb->wgcurr->await_count = _state->fb->wgcurr->spawn_count - (n); \ - cco_await(_state->fb->wgcurr->spawn_count == _state->fb->wgcurr->await_count); \ -} while (0) - -#define cco_await_cancel_group(waitgroup) do { \ - cco_group* wg = waitgroup; \ - cco_cancel_group(wg); \ - cco_await_group(wg); \ -} while (0) - -#define cco_await_any(waitgroup) do { \ - cco_await_n(waitgroup, 1); \ - cco_cancel_group(_state->fb->wgcurr); \ - cco_await_group(_state->fb->wgcurr); \ -} while (0) - -#define cco_run_fiber(...) c_MACRO_OVERLOAD(cco_run_fiber, __VA_ARGS__) -#define cco_run_fiber_1(fiber_ref) \ - for (cco_fiber** _it_ref = (cco_fiber**)((void)sizeof((fiber_ref)[0]->env), fiber_ref) \ - ; (*_it_ref = cco_execute_next(*_it_ref)) != NULL; ) -#define cco_run_fiber_2(it, fiber) \ - for (cco_fiber* it = (cco_fiber*)((void)sizeof((fiber)->env), fiber) \ - ; (it = cco_execute_next(it)) != NULL; ) - -#define cco_run_task(...) c_MACRO_OVERLOAD(cco_run_task, __VA_ARGS__) -#define cco_run_task_1(task) cco_run_fiber_2(_it_fb, cco_new_fiber_1(task)) -#define cco_run_task_2(task, env) cco_run_fiber_2(_it_fb, cco_new_fiber_2(task, env)) -#define cco_run_task_3(it, task, env) cco_run_fiber_2(it, cco_new_fiber_2(task, env)) - -#define cco_joined() \ - ((cco_fiber*)_state->fb == _state->fb->next) - -extern int cco_execute(cco_fiber* fb); // is a coroutine itself -extern cco_fiber* cco_execute_next(cco_fiber* fb); // resume and return the next fiber - -extern cco_fiber* _cco_new_fiber(cco_task* task, void* env, cco_group* wg); -extern cco_fiber* _cco_spawn(cco_task* task, cco_group* wg, void* env, cco_fiber* fb); -extern void _cco_cancel_group(cco_fiber* fb, cco_group* waitgroup); - -/* - * Iterate containers with already defined iterator (prefer to use in coroutines only): - */ -#define cco_each(existing_it, C, cnt) \ - existing_it = C##_begin(&cnt); (existing_it).ref; C##_next(&existing_it) - -#define cco_each_reverse(existing_it, C, cnt) \ - existing_it = C##_rbegin(&cnt); (existing_it).ref; C##_rnext(&existing_it) - -/* - * Using c_filter with coroutine iterators: - */ -#define cco_flt_take(n) \ - (c_flt_take(n), fltbase.done ? (_it.base.state.pos = CCO_STATE_DROP, _it.base.state.drop = 1) : 1) - -#define cco_flt_takewhile(pred) \ - (c_flt_takewhile(pred), fltbase.done ? (_it.base.state.pos = CCO_STATE_DROP, _it.base.state.drop = 1) : 1) - - -/* - * Semaphore - */ - -typedef struct { ptrdiff_t acq_count; } cco_semaphore; - -#define cco_make_semaphore(value) (c_literal(cco_semaphore){value}) -#define cco_set_semaphore(sem, value) ((sem)->acq_count = value) -#define cco_acquire_semaphore(sem) (--(sem)->acq_count) -#define cco_release_semaphore(sem) (++(sem)->acq_count) - -#define cco_await_semaphore(sem) \ - do { \ - cco_await((sem)->acq_count > 0); \ - cco_acquire_semaphore(sem); \ - } while (0) - - -/* - * Timer - */ - -#ifdef _WIN32 - #ifdef __cplusplus - #define _c_LINKC extern "C" __declspec(dllimport) - #else - #define _c_LINKC __declspec(dllimport) - #endif - #ifndef _WINDOWS_ // windows.h - typedef long long LARGE_INTEGER; - _c_LINKC int __stdcall QueryPerformanceCounter(LARGE_INTEGER*); - //_c_LINKC int __stdcall QueryPerformanceFrequency(LARGE_INTEGER*); - #endif - #define cco_timer_freq() 10000000LL /* 1/10th microseconds */ - //static inline long long cco_timer_freq(void) { - // long long quad; - // QueryPerformanceFrequency((LARGE_INTEGER*)&quad); - // return quad; - //} - - static inline long long cco_timer_ticks(void) { - long long quad; - QueryPerformanceCounter((LARGE_INTEGER*)&quad); - return quad; - } -#else - #include - #define cco_timer_freq() 1000000LL - - static inline long long cco_timer_ticks(void) { /* microseconds */ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec*cco_timer_freq() + tv.tv_usec; - } -#endif - -typedef struct { double duration; long long start_time; } cco_timer; - -static inline cco_timer cco_make_timer(double sec) { - cco_timer tm = {.duration=sec, .start_time=cco_timer_ticks()}; - return tm; -} - -static inline void cco_start_timer(cco_timer* tm, double sec) { - tm->duration = sec; - tm->start_time = cco_timer_ticks(); -} - -static inline void cco_restart_timer(cco_timer* tm) { - tm->start_time = cco_timer_ticks(); -} - -static inline double cco_timer_elapsed(cco_timer* tm) { - return (double)(cco_timer_ticks() - tm->start_time)*(1.0/cco_timer_freq()); -} - -static inline bool cco_timer_expired(cco_timer* tm) { - return cco_timer_elapsed(tm) >= tm->duration; -} - -static inline double cco_timer_remaining(cco_timer* tm) { - return tm->duration - cco_timer_elapsed(tm); -} - -#define cco_await_timer(tm, sec) \ - do { \ - cco_start_timer(tm, sec); \ - cco_await(cco_timer_expired(tm)); \ - } while (0) - -#endif // STC_COROUTINE_H_INCLUDED - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if (defined i_implement || defined STC_IMPLEMENT) && !defined STC_COROUTINE_IMPLEMENT -#define STC_COROUTINE_IMPLEMENT -#include - -cco_fiber* _cco_spawn(cco_task* _task, cco_group* wg, void* env, cco_fiber* fb) { - cco_fiber* new_fb; - new_fb = fb->next = (fb->next ? c_new(cco_fiber, {.next=fb->next}) : fb); - new_fb->task = _task; - new_fb->env = (env ? env : fb->env); - _task->base.state.fb = new_fb; - if (wg) wg->spawn_count += 1; - _task->base.state.wg = wg; - return new_fb; -} - -cco_fiber* _cco_new_fiber(cco_task* _task, void* env, cco_group* wg) { - cco_fiber* new_fb = c_new(cco_fiber, {.task=_task, .env=env}); - _task->base.state.fb = new_fb; - _task->base.state.wg = wg; - return (new_fb->next = new_fb); -} - -void _cco_cancel_group(cco_fiber* fb, cco_group* waitgroup) { - for (cco_fiber *fbi = fb->next; fbi != fb; fbi = fbi->next) { - cco_task* top = fbi->task; - while (top->base.parent_task) - top = top->base.parent_task; - if (top->base.state.wg == waitgroup) - cco_cancel_fiber(fbi); - } -} - -cco_fiber* cco_execute_next(cco_fiber* fb) { - cco_fiber *_next = fb->next, *unlinked; - int ret = cco_execute(_next); - - if (ret == CCO_DONE) { - unlinked = _next; - _next = (_next == fb ? NULL : _next->next); - fb->next = _next; - c_free_n(unlinked, 1); - } - return _next; -} - -int cco_execute(cco_fiber* fb) { - cco_async (fb) { - while (1) { - fb->parent_task = fb->task->base.parent_task; - fb->awaitbits = fb->task->base.awaitbits; - fb->status = cco_resume(fb->task); - if (fb->err.code) { - // Note: if fb->status == CCO_DONE, fb->task may already be destructed. - if (fb->status == CCO_DONE) { - fb->task = fb->parent_task; - if (fb->task == NULL) - break; - fb->recover_state = fb->task->base.state; - } - cco_stop(fb->task); - cco_suspend; - continue; - } - if (!((fb->status & ~fb->awaitbits) || (fb->task = fb->parent_task) != NULL)) - break; - cco_suspend; - } - } - - if ((uint32_t)fb->err.code & ~CCO_CANCEL) { // Allow CCO_CANCEL not to trigger error. - fprintf(stderr, __FILE__ ": error: unhandled coroutine error '%d'\n" - "%s:%d: cco_throw(%d);\n", - fb->err.code, fb->err.file, fb->err.line, fb->err.code); - exit(fb->err.code); - } - return CCO_DONE; -} -#endif // IMPLEMENT -#undef i_implement -#undef i_static -#undef i_header diff --git a/src/finchlite/codegen/stc/include/stc/cregex.h b/src/finchlite/codegen/stc/include/stc/cregex.h deleted file mode 100644 index 0a1ab03f..00000000 --- a/src/finchlite/codegen/stc/include/stc/cregex.h +++ /dev/null @@ -1,168 +0,0 @@ -/* -This is a Unix port of the Plan 9 regular expression library, by Rob Pike. - -Copyright © 2021 Plan 9 Foundation -Copyright © 2022 Tyge Løvset, for additions made in 2022. - -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_CREGEX_H_INCLUDED -#define STC_CREGEX_H_INCLUDED -/* - * cregex.h - * - * This is a extended version of regexp9, supporting UTF8 input, common - * shorthand character classes, ++. - */ -#include "common.h" -#include "types.h" // csview, cstr types - -enum { - CREG_DEFAULT = 0, - - /* compile-flags */ - CREG_DOTALL = 1<<0, /* dot matches newline too */ - CREG_ICASE = 1<<1, /* ignore case */ - - /* match-flags */ - CREG_FULLMATCH = 1<<2, /* like start-, end-of-line anchors were in pattern: "^ ... $" */ - CREG_NEXT = 1<<3, /* use end of previous match[0] as start of input */ - - /* replace-flags */ - CREG_STRIP = 1<<5, /* only keep the matched strings, strip rest */ - - /* limits */ - CREG_MAX_CLASSES = 16, - CREG_MAX_CAPTURES = 32, -}; - -typedef enum { - CREG_OK = 0, - CREG_NOMATCH = -1, - CREG_MATCHERROR = -2, - CREG_OUTOFMEMORY = -3, - CREG_UNMATCHEDLEFTPARENTHESIS = -4, - CREG_UNMATCHEDRIGHTPARENTHESIS = -5, - CREG_TOOMANYSUBEXPRESSIONS = -6, - CREG_TOOMANYCHARACTERCLASSES = -7, - CREG_MALFORMEDCHARACTERCLASS = -8, - CREG_MISSINGOPERAND = -9, - CREG_UNKNOWNOPERATOR = -10, - CREG_OPERANDSTACKOVERFLOW = -11, - CREG_OPERATORSTACKOVERFLOW = -12, - CREG_OPERATORSTACKUNDERFLOW = -13, -} cregex_result; - -typedef struct { - struct _Reprog* prog; - int error; -} cregex; - -typedef struct { - const cregex* regex; - csview input; - csview match[CREG_MAX_CAPTURES]; -} cregex_iter; - -#define c_match(it, re, str) \ - cregex_iter it = {.regex=re, .input={str}, .match={{0}}}; \ - cregex_match(it.regex, it.input.buf, it.match, CREG_NEXT) == CREG_OK && it.match[0].size; - -#define c_match_sv(it, re, strview) \ - cregex_iter it = {.regex=re, .input=strview, .match={{0}}}; \ - cregex_match_sv(it.regex, it.input, it.match, CREG_NEXT) == CREG_OK && it.match[0].size; - -/* compile a regex from a pattern. return CREG_OK, or negative error code on failure. */ -extern int cregex_compile_pro(cregex *re, const char* pattern, int cflags); - -#define cregex_compile(...) \ - c_ARG_4(__VA_ARGS__, cregex_compile_pro(__VA_ARGS__), cregex_compile_pro(__VA_ARGS__, CREG_DEFAULT), _too_few_args_) - -/* construct and return a regex from a pattern. return CREG_OK, or negative error code on failure. */ -STC_INLINE cregex cregex_make(const char* pattern, int cflags) { - cregex re = {0}; - cregex_compile_pro(&re, pattern, cflags); - return re; -} -STC_INLINE cregex cregex_from(const char* pattern) - { return cregex_make(pattern, CREG_DEFAULT); } - -/* destroy regex */ -extern void cregex_drop(cregex* re); - -/* number of capture groups in a regex pattern, excluding the full match capture (0) */ -extern int cregex_captures(const cregex* re); - -/* ----- Private ----- */ - -struct cregex_match_opt { csview* match; int flags; int _dummy; }; -struct cregex_replace_opt { int count; bool(*xform)(int group, csview match, cstr* out); int flags; int _dummy; }; - -extern int cregex_match_opt(const cregex* re, const char* input, const char* input_end, struct cregex_match_opt opt); -extern int cregex_match_aio_opt(const char* pattern, const char* input, const char* input_end, struct cregex_match_opt opt); -extern cstr cregex_replace_opt(const cregex* re, const char* input, const char* input_end, const char* replace, struct cregex_replace_opt opt); -extern cstr cregex_replace_aio_opt(const char* pattern, const char* input, const char* input_end, const char* replace, struct cregex_replace_opt opt); - -static inline int cregex_match_sv_opt(const cregex* re, csview sv, struct cregex_match_opt opt) - { return cregex_match_opt(re, sv.buf, sv.buf+sv.size, opt); } -static inline int cregex_match_aio_sv_opt(const char* pattern, csview sv, struct cregex_match_opt opt) - { return cregex_match_aio_opt(pattern, sv.buf, sv.buf+sv.size, opt); } -static inline cstr cregex_replace_sv_opt(const cregex* re, csview sv, const char* replace, struct cregex_replace_opt opt) - { return cregex_replace_opt(re, sv.buf, sv.buf+sv.size, replace, opt); } -static inline cstr cregex_replace_aio_sv_opt(const char* pattern, csview sv, const char* replace, struct cregex_replace_opt opt) - { return cregex_replace_aio_opt(pattern, sv.buf, sv.buf+sv.size, replace, opt); } - -/* match: return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */ -#define _cregex_match(re, str, ...) cregex_match_opt(re, str, NULL, (struct cregex_match_opt){__VA_ARGS__}) -#define _cregex_match_sv(re, sv, ...) cregex_match_sv_opt(re, sv, (struct cregex_match_opt){__VA_ARGS__}) -/* all-in-one: compile RE pattern + match + free */ -#define _cregex_match_aio(pattern, str, ...) cregex_match_aio_opt(pattern, str, NULL, (struct cregex_match_opt){__VA_ARGS__}) -#define _cregex_match_aio_sv(pattern, sv, ...) cregex_match_aio_sv_opt(pattern, sv, (struct cregex_match_opt){__VA_ARGS__}) - -/* replace input with a string using regular expression */ -#define _cregex_replace(re, str, replace, ...) cregex_replace_opt(re, str, NULL, replace, (struct cregex_replace_opt){__VA_ARGS__}) -#define _cregex_replace_sv(re, sv, replace, ...) cregex_replace_sv_opt(re, sv, replace, (struct cregex_replace_opt){__VA_ARGS__}) -/* all-in-one: compile RE string pattern + match + replace + free */ -#define _cregex_replace_aio(pattern, str, replace, ...) cregex_replace_aio_opt(pattern, str, NULL, replace, (struct cregex_replace_opt){__VA_ARGS__}) -#define _cregex_replace_aio_sv(pattern, sv, replace, ...) cregex_replace_aio_sv_opt(pattern, sv, replace, (struct cregex_replace_opt){__VA_ARGS__}) - -/* ----- API functions ---- */ - -#define cregex_match(...) _cregex_match(__VA_ARGS__, ._dummy=0) -#define cregex_match_sv(...) _cregex_match_sv(__VA_ARGS__, ._dummy=0) -#define cregex_match_aio(...) _cregex_match_aio(__VA_ARGS__, ._dummy=0) -#define cregex_match_aio_sv(...) _cregex_match_aio_sv(__VA_ARGS__, ._dummy=0) -#define cregex_is_match(re, str) (_cregex_match(re, str, 0) == CREG_OK) - -#define cregex_replace(...) _cregex_replace(__VA_ARGS__, ._dummy=0) -#define cregex_replace_sv(...) _cregex_replace_sv(__VA_ARGS__, ._dummy=0) -#define cregex_replace_aio(...) _cregex_replace_aio(__VA_ARGS__, ._dummy=0) -#define cregex_replace_aio_sv(...) _cregex_replace_aio_sv(__VA_ARGS__, ._dummy=0) - -#endif // STC_CREGEX_H_INCLUDED - -#if defined STC_IMPLEMENT || defined i_implement || defined i_import - #include "priv/linkage.h" - #include "priv/cregex_prv.c" - #if defined i_import - #include "priv/utf8_prv.c" - #include "priv/cstr_prv.c" - #endif - #include "priv/linkage2.h" -#endif diff --git a/src/finchlite/codegen/stc/include/stc/cspan.h b/src/finchlite/codegen/stc/include/stc/cspan.h deleted file mode 100644 index 6f5f16c0..00000000 --- a/src/finchlite/codegen/stc/include/stc/cspan.h +++ /dev/null @@ -1,480 +0,0 @@ -/* - 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. - */ -/* -#include -#include -#include -use_cspan(Span2f, float, 2); -use_cspan(Intspan, int); - -int demo1() { - float raw[4*5]; - Span2f ms = cspan_md(raw, 4, 5); - - for (int i=0; ishape[0]==0 ? NULL : self->data, ._s=self}; \ - } \ - STC_INLINE Self##_iter Self##_end(const Self* self) { \ - (void)self; \ - return c_literal(Self##_iter){0}; \ - } \ - STC_INLINE void Self##_next(Self##_iter* it) { \ - isize off = it->_s->stride.d[RANK - 1]; \ - bool done = _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, &off); \ - if (done) it->ref = NULL; else it->ref += off; \ - } \ - STC_INLINE isize Self##_size(const Self* self) \ - { return cspan_size(self); } \ - STC_INLINE Self Self##_transposed(Self sp) \ - { _cspan_transpose(sp.shape, sp.stride.d, cspan_rank(&sp)); return sp; } \ - STC_INLINE Self Self##_swapped_axes(Self sp, int ax1, int ax2) \ - { _cspan_swap_axes(sp.shape, sp.stride.d, cspan_rank(&sp), ax1, ax2); return sp; } \ - struct stc_nostruct - -#define use_cspan_with_eq_4(Self, T, i_eq, RANK) \ - use_cspan_3(Self, T, RANK); \ - STC_INLINE bool Self##_eq(const Self* x, const Self* y) { \ - if (memcmp(x->shape, y->shape, sizeof x->shape) != 0) \ - return false; \ - for (Self##_iter _i = Self##_begin(x), _j = Self##_begin(y); \ - _i.ref != NULL; Self##_next(&_i), Self##_next(&_j)) \ - { if (!(i_eq(_i.ref, _j.ref))) return false; } \ - return true; \ - } \ - STC_INLINE bool Self##_equals(Self sp1, Self sp2) \ - { return Self##_eq(&sp1, &sp2); } \ - struct stc_nostruct - -#define use_cspan2(Self, T) use_cspan_2(Self, T); use_cspan_3(Self##2, T, 2) -#define use_cspan3(Self, T) use_cspan2(Self, T); use_cspan_3(Self##3, T, 3) -#define use_cspan2_with_eq(Self, T, eq) use_cspan_with_eq_3(Self, T, eq); \ - use_cspan_with_eq_4(Self##2, T, eq, 2) -#define use_cspan3_with_eq(Self, T, eq) use_cspan2_with_eq(Self, T, eq); \ - use_cspan_with_eq_4(Self##3, T, eq, 3) -#define use_cspan_tuple(N) typedef struct { _istride d[N]; } cspan_tuple##N -use_cspan_tuple(1); use_cspan_tuple(2); -use_cspan_tuple(3); use_cspan_tuple(4); -use_cspan_tuple(5); use_cspan_tuple(6); -use_cspan_tuple(7); use_cspan_tuple(8); - - -// Construct a cspan from a pointer+size -#define cspan_from_n(dataptr, n) \ - {.data=dataptr, \ - .shape={(_istride)(n)}, \ - .stride=c_literal(cspan_tuple1){.d={1}}} - -// Create a 1d-span in the local lexical scope. N must be a compile-time constant. -#define cspan_by_copy(dataptr, N) \ - cspan_from_n(memcpy((char[(N)*sizeof *(dataptr)]){0}, dataptr, (N)*sizeof *(dataptr)), N) - -// Create a zeroed out 1d-span in the local lexical scope. N must be a compile-time constant. -#define cspan_zeros(Span, N) \ - ((Span)cspan_from_n((Span##_value[N]){0}, N)) - -// Create a global scope 1d-span from constant initializer list, otherwise like c_make(Span, ...). -#define cspan_make(Span, ...) \ - ((Span)cspan_from_n(c_make_array(Span##_value, __VA_ARGS__), \ - sizeof((Span##_value[])__VA_ARGS__)/sizeof(Span##_value))) - -// Make 1d-span from a c-array. -#define cspan_from_array(array) \ - cspan_from_n(array, c_arraylen(array)) - -// Make 1d-span from a vec or stack container. -#define cspan_from_vec(container) \ - cspan_from_n((container)->data, (container)->size) - -// Make a 1d-sub-span from a 1d-span -#define cspan_subspan(self, offset, count) \ - {.data=cspan_at(self, offset), \ - .shape={(_istride)(count)}, \ - .stride=(self)->stride} - -// Accessors -// -#define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) -#define cspan_rank(self) c_arraylen((self)->shape) // constexpr -#define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__)) -#define cspan_front(self) ((self)->data) -#define cspan_back(self) ((self)->data + cspan_size(self) - 1) - -#define cspan_index(...) cspan_index_fn(__VA_ARGS__, c_COMMA_N(cspan_index_3d), c_COMMA_N(cspan_index_2d), \ - c_COMMA_N(cspan_index_1d),)(__VA_ARGS__) -#define cspan_index_fn(self, i,j,k,n, ...) c_TUPLE_AT_1(n, cspan_index_nd,) -#define cspan_index_1d(self, i) (c_static_assert(cspan_rank(self) == 1), \ - c_assert((i) < (self)->shape[0]), \ - (i)*(self)->stride.d[0]) -#define cspan_index_2d(self, i,j) (c_static_assert(cspan_rank(self) == 2), \ - c_assert((i) < (self)->shape[0] && (j) < (self)->shape[1]), \ - (i)*(self)->stride.d[0] + (j)*(self)->stride.d[1]) -#define cspan_index_3d(self, i,j,k) (c_static_assert(cspan_rank(self) == 3), \ - c_assert((i) < (self)->shape[0] && (j) < (self)->shape[1] && (k) < (self)->shape[2]), \ - (i)*(self)->stride.d[0] + (j)*(self)->stride.d[1] + (k)*(self)->stride.d[2]) -#define cspan_index_nd(self, ...) _cspan_index((self)->shape, (self)->stride.d, c_make_array(isize, {__VA_ARGS__}), \ - (c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__)), cspan_rank(self))) - - -// Multi-dimensional span constructors -// -typedef enum {c_ROWMAJOR, c_COLMAJOR, c_STRIDED} cspan_layout; - -#define cspan_is_colmajor(self) \ - _cspan_is_layout(c_COLMAJOR, (self)->shape, (self)->stride.d, cspan_rank(self)) -#define cspan_is_rowmajor(self) \ - _cspan_is_layout(c_ROWMAJOR, (self)->shape, (self)->stride.d, cspan_rank(self)) -#define cspan_get_layout(self) \ - (cspan_is_rowmajor(self) ? c_ROWMAJOR : cspan_is_colmajor(self) ? c_COLMAJOR : c_STRIDED) - -#define cspan_md(dataptr, ...) \ - cspan_md_layout(c_ROWMAJOR, dataptr, __VA_ARGS__) - -// Span2 sp1 = cspan_md(data, 30, 50); -// Span2 sp2 = {data, cspan_shape(15, 25), cspan_strides(50*2, 2)}; // every second in each dim -#define cspan_shape(...) {__VA_ARGS__} -#define cspan_strides(...) {.d={__VA_ARGS__}} - -#define cspan_md_layout(layout, dataptr, ...) \ - {.data=dataptr, \ - .shape={__VA_ARGS__}, \ - .stride=*(c_JOIN(cspan_tuple,c_NUMARGS(__VA_ARGS__))*) \ - _cspan_shape2stride(layout, c_make_array(_istride, {__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} - -// Transpose matrix -#define cspan_transpose(self) \ - _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self)) - -// Swap two matrix axes -#define cspan_swap_axes(self, ax1, ax2) \ - _cspan_swap_axes((self)->shape, (self)->stride.d, cspan_rank(self), ax1, ax2) - -// Set all span elements to value. -#define cspan_set_all(Span, self, value) do { \ - Span##_value _v = value; \ - for (c_each_3(_it, Span, *(self))) *_it.ref = _v; \ -} while (0) - -// General slicing function. -// -#define c_END (_istride)(((size_t)1 << (sizeof(_istride)*8 - 1)) - 1) -#define c_ALL 0,c_END - -#define cspan_slice(self, Outspan, ...) \ - Outspan##_slice_((self)->data, (self)->shape, (self)->stride.d, \ - c_make_array2d(const isize, 3, {__VA_ARGS__}), \ - (c_static_assert(cspan_rank(self) == sizeof((isize[][3]){__VA_ARGS__})/sizeof(isize[3])), cspan_rank(self))) - -// submd#(): Reduces rank, fully typesafe + range checked by default -// int ms3[N1][N2][N3]; -// int (*ms2)[N3] = ms3[1]; // traditional, lose range test/info. VLA. -// Span3 ms3 = cspan_md(data, N1,N2,N3); // Uses cspan_md instead. -// *cspan_at(&ms3, 1,1,1) = 42; -// Span2 ms2 = cspan_slice(&ms3, Span2, {1}, {c_ALL}, {c_ALL}); -// Span2 ms2 = cspan_submd3(&ms3, 1); // Same as line above, optimized. -#define cspan_submd2(self, x) \ - {.data=cspan_at(self, x, 0), \ - .shape={(self)->shape[1]}, \ - .stride=c_literal(cspan_tuple1){.d={(self)->stride.d[1]}}} - -#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__) -#define cspan_submd3_2(self, x) \ - {.data=cspan_at(self, x, 0, 0), \ - .shape={(self)->shape[1], (self)->shape[2]}, \ - .stride=c_literal(cspan_tuple2){.d={(self)->stride.d[1], (self)->stride.d[2]}}} -#define cspan_submd3_3(self, x, y) \ - {.data=cspan_at(self, x, y, 0), \ - .shape={(self)->shape[2]}, \ - .stride=c_literal(cspan_tuple1){.d={(self)->stride.d[2]}}} - -#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__) -#define cspan_submd4_2(self, x) \ - {.data=cspan_at(self, x, 0, 0, 0), \ - .shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \ - .stride=c_literal(cspan_tuple3){.d={(self)->stride.d[1], (self)->stride.d[2], (self)->stride.d[3]}}} -#define cspan_submd4_3(self, x, y) \ - {.data=cspan_at(self, x, y, 0, 0), \ - .shape={(self)->shape[2], (self)->shape[3]}, \ - .stride=c_literal(cspan_tuple2){.d={(self)->stride.d[2], (self)->stride.d[3]}}} -#define cspan_submd4_4(self, x, y, z) \ - {.data=cspan_at(self, x, y, z, 0), \ - .shape={(self)->shape[3]}, \ - .stride=c_literal(cspan_tuple1){.d={(self)->stride.d[3]}}} - -#define cspan_print(...) c_MACRO_OVERLOAD(cspan_print, __VA_ARGS__) -#define cspan_print_3(Span, fmt, span) \ - cspan_print_4(Span, fmt, span, stdout) -#define cspan_print_4(Span, fmt, span, fp) \ - cspan_print_5(Span, fmt, span, fp, "[]") -#define cspan_print_5(Span, fmt, span, fp, brackets) \ - cspan_print_6(Span, fmt, span, fp, brackets, c_EXPAND) -#define cspan_print_complex(Span, prec, span, fp) \ - cspan_print_6(Span, "%." #prec "f%+." #prec "fi", span, fp, "[]", cspan_CMPLX_FLD) -#define cspan_CMPLX_FLD(x) creal(x), cimag(x) - -#define cspan_print_6(Span, fmt, span, fp, brackets, field) do { \ - const Span _s = span; \ - const char *_f = fmt, *_b = brackets; \ - FILE* _fp = fp; \ - int _w, _max = 0; \ - char _res[2][20], _fld[64]; \ - for (c_each_3(_it, Span, _s)) { \ - _w = snprintf(NULL, 0ULL, _f, field(_it.ref[0])); \ - if (_w > _max) _max = _w; \ - } \ - for (c_each_3(_it, Span, _s)) { \ - _cspan_print_assist(_it.pos, _s.shape, cspan_rank(&_s), _b, _res); \ - _w = _max + (_it.pos[cspan_rank(&_s) - 1] > 0); \ - snprintf(_fld, sizeof _fld, _f, field(_it.ref[0])); \ - fprintf(_fp, "%s%*s%s", _res[0], _w, _fld, _res[1]); \ - } \ -} while (0) - -/* ----- PRIVATE ----- */ - -STC_INLINE isize _cspan_size(const _istride shape[], int rank) { - isize size = shape[0]; - while (--rank) size *= shape[rank]; - return size; -} - -STC_INLINE void _cspan_swap_axes(_istride shape[], _istride stride[], - int rank, int ax1, int ax2) { - (void)rank; - c_assert(c_uless(ax1, rank) & c_uless(ax2, rank)); - c_swap(shape + ax1, shape + ax2); - c_swap(stride + ax1, stride + ax2); -} - -STC_INLINE void _cspan_transpose(_istride shape[], _istride stride[], int rank) { - for (int i = 0; i < --rank; ++i) { - c_swap(shape + i, shape + rank); - c_swap(stride + i, stride + rank); - } -} - -STC_INLINE isize _cspan_index(const _istride shape[], const _istride stride[], - const isize args[], int rank) { - isize off = 0; - (void)shape; - while (rank-- != 0) { - c_assert(args[rank] < shape[rank]); - off += args[rank]*stride[rank]; - } - return off; -} - -STC_API void _cspan_print_assist(_istride pos[], const _istride shape[], const int rank, - const char* brackets, char result[2][20]); - -STC_API bool _cspan_nextN(_istride pos[], const _istride shape[], const _istride stride[], - int rank, isize* off); -#define _cspan_next1(pos, shape, stride, rank, off) (++pos[0] == shape[0]) -#define _cspan_next2(pos, shape, stride, rank, off) (++pos[1] == shape[1] && \ - (pos[1] = 0, *off += stride[0] - (isize)shape[1]*stride[1], ++pos[0] == shape[0])) -#define _cspan_next3(pos, shape, stride, rank, off) (++pos[2] == shape[2] && \ - (pos[2] = 0, *off += stride[1] - (isize)shape[2]*stride[2], ++pos[1] == shape[1]) && \ - (pos[1] = 0, *off += stride[0] - (isize)shape[1]*stride[1], ++pos[0] == shape[0])) -#define _cspan_next4 _cspan_nextN -#define _cspan_next5 _cspan_nextN -#define _cspan_next6 _cspan_nextN -#define _cspan_next7 _cspan_nextN -#define _cspan_next8 _cspan_nextN - -STC_API isize _cspan_slice(_istride oshape[], _istride ostride[], int* orank, - const _istride shape[], const _istride stride[], - const isize args[][3], int rank); -STC_API _istride* _cspan_shape2stride(cspan_layout layout, _istride shape[], int rank); -STC_API bool _cspan_is_layout(cspan_layout layout, const _istride shape[], const _istride strides[], int rank); - -#endif // STC_CSPAN_H_INCLUDED - -/* --------------------- IMPLEMENTATION --------------------- */ -#if defined i_implement && !defined STC_CSPAN_IMPLEMENT -#define STC_CSPAN_IMPLEMENT - -STC_DEF bool _cspan_is_layout(cspan_layout layout, const _istride shape[], const _istride strides[], int rank) { - _istride tmpshape[16]; // 16 = "max" rank - size_t sz = (size_t)rank*sizeof(_istride); - memcpy(tmpshape, shape, sz); - return memcmp(strides, _cspan_shape2stride(layout, tmpshape, rank), sz) == 0; -} - -STC_DEF void _cspan_print_assist(_istride pos[], const _istride shape[], const int rank, - const char* brackets, char result[2][20]) { - int n = 0, j = 0, r = rank - 1; - memset(result, 0, 32); - - // left braces: - while (n <= r && pos[r - n] == 0) - ++n; - if (n) for (; j < rank; ++j) - result[0][j] = j < rank - n ? ' ' : brackets[0]; - - // right braces: - for (j = 0; r >= 0 && pos[r] + 1 == shape[r]; --r, ++j) - result[1][j] = brackets[1]; - - // comma and newlines: - n = (j > 0) + ((j > 1) & (j < rank)); - if (brackets[2] && j < rank) - result[1][j++] = brackets[2]; // comma - while (n--) - result[1][j++] = '\n'; -} - -STC_DEF bool _cspan_nextN(_istride pos[], const _istride shape[], const _istride stride[], - int rank, isize* off) { - ++pos[--rank]; - for (; rank && pos[rank] == shape[rank]; --rank) { - pos[rank] = 0; ++pos[rank - 1]; - *off += stride[rank - 1] - (isize)shape[rank]*stride[rank]; - } - return pos[rank] == shape[rank]; -} - -STC_DEF _istride* _cspan_shape2stride(cspan_layout layout, _istride shpstri[], int rank) { - int i, inc; - if (layout == c_COLMAJOR) i = 0, inc = 1; - else i = rank - 1, inc = -1; - _istride k = 1, s1 = shpstri[i], s2; - - shpstri[i] = 1; - while (--rank) { - i += inc; - s2 = shpstri[i]; - shpstri[i] = (k *= s1); - s1 = s2; - } - return shpstri; -} - -STC_DEF isize _cspan_slice(_istride oshape[], _istride ostride[], int* orank, - const _istride shape[], const _istride stride[], - const isize args[][3], int rank) { - isize end, off = 0; - int i = 0, oi = 0; - - for (; i < rank; ++i) { - off += args[i][0]*stride[i]; - switch (args[i][1]) { - case 0: c_assert(c_uless(args[i][0], shape[i])); continue; - case c_END: end = shape[i]; break; - default: end = args[i][1]; - } - oshape[oi] = (_istride)(end - args[i][0]); - ostride[oi] = stride[i]; - c_assert((oshape[oi] > 0) & !c_uless(shape[i], end)); - if (args[i][2] > 0) { - ostride[oi] *= (_istride)args[i][2]; - oshape[oi] = (oshape[oi] - 1)/(_istride)args[i][2] + 1; - } - ++oi; - } - *orank = oi; - return off; -} -#endif // IMPLEMENT -#include "priv/linkage2.h" diff --git a/src/finchlite/codegen/stc/include/stc/cstr.h b/src/finchlite/codegen/stc/include/stc/cstr.h deleted file mode 100644 index d7c3556d..00000000 --- a/src/finchlite/codegen/stc/include/stc/cstr.h +++ /dev/null @@ -1,51 +0,0 @@ -/* 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. - */ - -/* 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_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" diff --git a/src/finchlite/codegen/stc/include/stc/csview.h b/src/finchlite/codegen/stc/include/stc/csview.h deleted file mode 100644 index c9e71df7..00000000 --- a/src/finchlite/codegen/stc/include/stc/csview.h +++ /dev/null @@ -1,243 +0,0 @@ -/* 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. - */ -// csview is a non-zero-terminated string view. - -#ifndef STC_CSVIEW_H_INCLUDED -#define STC_CSVIEW_H_INCLUDED - -#include "common.h" -#include "types.h" -#include "priv/utf8_prv.h" - -#define csview_init() c_sv_1("") -#define csview_drop(p) c_default_drop(p) -#define csview_clone(sv) c_default_clone(sv) - -csview_iter csview_advance(csview_iter it, isize u8pos); -csview csview_subview_pro(csview sv, isize pos, isize n); -csview csview_token(csview sv, const char* sep, isize* pos); -csview csview_u8_subview(csview sv, isize u8pos, isize u8len); -csview csview_u8_tail(csview sv, isize u8len); -csview_iter csview_u8_at(csview sv, isize u8pos); - -STC_INLINE csview csview_from(const char* str) - { return c_literal(csview){str, c_strlen(str)}; } -STC_INLINE csview csview_from_n(const char* str, isize n) - { return c_literal(csview){str, n}; } - -STC_INLINE void csview_clear(csview* self) { *self = csview_init(); } -STC_INLINE isize csview_size(csview sv) { return sv.size; } -STC_INLINE bool csview_is_empty(csview sv) { return sv.size == 0; } - -STC_INLINE bool csview_equals_sv(csview sv1, csview sv2) - { return sv1.size == sv2.size && !c_memcmp(sv1.buf, sv2.buf, sv1.size); } - -STC_INLINE bool csview_equals(csview sv, const char* str) - { return csview_equals_sv(sv, c_sv_2(str, c_strlen(str))); } - -STC_INLINE size_t csview_hash(const csview *self) - { return c_basehash_n(self->buf, self->size); } - -STC_INLINE isize csview_find_sv(csview sv, csview search) { - char* res = c_strnstrn(sv.buf, sv.size, search.buf, search.size); - return res ? (res - sv.buf) : c_NPOS; -} - -STC_INLINE isize csview_find(csview sv, const char* str) - { return csview_find_sv(sv, c_sv_2(str, c_strlen(str))); } - -STC_INLINE bool csview_contains(csview sv, const char* str) - { return csview_find(sv, str) != c_NPOS; } - -STC_INLINE bool csview_starts_with(csview sv, const char* str) { - isize n = c_strlen(str); - return n <= sv.size && !c_memcmp(sv.buf, str, n); -} - -STC_INLINE bool csview_ends_with(csview sv, const char* str) { - isize n = c_strlen(str); - return n <= sv.size && !c_memcmp(sv.buf + sv.size - n, str, n); -} - -STC_INLINE csview csview_subview(csview sv, isize pos, isize len) { - c_assert(((size_t)pos <= (size_t)sv.size) & (len >= 0)); - if (pos + len > sv.size) len = sv.size - pos; - sv.buf += pos, sv.size = len; - return sv; -} - -STC_INLINE csview csview_slice(csview sv, isize p1, isize p2) { - c_assert(((size_t)p1 <= (size_t)p2) & ((size_t)p1 <= (size_t)sv.size)); - if (p2 > sv.size) p2 = sv.size; - sv.buf += p1, sv.size = p2 - p1; - return sv; -} - -STC_INLINE csview csview_trim_start(csview sv) - { while (sv.size && *sv.buf <= ' ') ++sv.buf, --sv.size; return sv; } - -STC_INLINE csview csview_trim_end(csview sv) - { while (sv.size && sv.buf[sv.size - 1] <= ' ') --sv.size; return sv; } - -STC_INLINE csview csview_trim(csview sv) - { return csview_trim_end(csview_trim_start(sv)); } - -STC_INLINE csview csview_tail(csview sv, isize len) - { return csview_subview(sv, sv.size - len, len); } - -/* utf8 iterator */ -STC_INLINE csview_iter csview_begin(const csview* self) { - csview_iter it = {.u8 = {{self->buf, utf8_chr_size(self->buf)}, - self->buf + self->size}}; - return it; -} -STC_INLINE csview_iter csview_end(const csview* self) { - (void)self; csview_iter it = {0}; return it; -} -STC_INLINE void csview_next(csview_iter* it) { - it->ref += it->chr.size; - it->chr.size = utf8_chr_size(it->ref); - if (it->ref == it->u8.end) it->ref = NULL; -} - -/* utf8 */ -STC_INLINE csview csview_u8_from(const char* str, isize u8pos, isize u8len) - { return utf8_subview(str, u8pos, u8len); } - -STC_INLINE isize csview_u8_size(csview sv) - { return utf8_count_n(sv.buf, sv.size); } - -STC_INLINE bool csview_u8_valid(csview sv) // requires linking with utf8 symbols - { return utf8_valid_n(sv.buf, sv.size); } - -#define c_fortoken(...) for (c_token(__VA_ARGS__)) // [deprecated] - -#define c_token_sv(it, separator, sv) \ - struct { csview input, token; const char* sep; isize pos; } \ - it = {.input=sv, .sep=separator} ; \ - it.pos <= it.input.size && (it.token = csview_token(it.input, it.sep, &it.pos)).buf ; - -#define c_token(it, separator, str) \ - c_token_sv(it, separator, csview_from(str)) - -/* ---- Container helper functions ---- */ - -STC_INLINE int csview_cmp(const csview* x, const csview* y) { - isize n = x->size < y->size ? x->size : y->size; - int c = c_memcmp(x->buf, y->buf, n); - return c ? c : c_default_cmp(&x->size, &y->size); -} - -STC_INLINE bool csview_eq(const csview* x, const csview* y) - { return x->size == y->size && !c_memcmp(x->buf, y->buf, x->size); } - -/* ---- case insensitive ---- */ - -STC_INLINE bool csview_iequals_sv(csview sv1, csview sv2) - { return sv1.size == sv2.size && !utf8_icompare(sv1, sv2); } - -STC_INLINE bool csview_iequals(csview sv, const char* str) - { return csview_iequals_sv(sv, c_sv(str, c_strlen(str))); } - -STC_INLINE bool csview_ieq(const csview* x, const csview* y) - { return csview_iequals_sv(*x, *y); } - -STC_INLINE int csview_icmp(const csview* x, const csview* y) - { return utf8_icompare(*x, *y); } - -STC_INLINE bool csview_istarts_with(csview sv, const char* str) { - isize n = c_strlen(str); - return n <= sv.size && !utf8_icompare(sv, c_sv(str, n)); -} - -STC_INLINE bool csview_iends_with(csview sv, const char* str) { - isize n = c_strlen(str); - return n <= sv.size && !utf8_icmp(sv.buf + sv.size - n, str); -} -#endif // STC_CSVIEW_H_INCLUDED - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if (defined STC_IMPLEMENT || defined i_implement) && !defined STC_CSVIEW_IMPLEMENT -#define STC_CSVIEW_IMPLEMENT - -csview_iter csview_advance(csview_iter it, isize u8pos) { - int inc = 1; - if (u8pos < 0) u8pos = -u8pos, inc = -1; - while (u8pos && it.ref != it.u8.end) - u8pos -= (*(it.ref += inc) & 0xC0) != 0x80; - if (it.ref == it.u8.end) it.ref = NULL; - else it.chr.size = utf8_chr_size(it.ref); - return it; -} - -csview csview_subview_pro(csview sv, isize pos, isize len) { - if (pos < 0) { - pos += sv.size; - if (pos < 0) pos = 0; - } - if (pos > sv.size) pos = sv.size; - if (pos + len > sv.size) len = sv.size - pos; - sv.buf += pos, sv.size = len; - return sv; -} - -csview csview_token(csview sv, const char* sep, isize* pos) { - isize sep_size = c_strlen(sep); - csview slice = {sv.buf + *pos, sv.size - *pos}; - const char* res = c_strnstrn(slice.buf, slice.size, sep, sep_size); - csview tok = {slice.buf, res ? (res - slice.buf) : slice.size}; - *pos += tok.size + sep_size; - return tok; -} - -csview csview_u8_subview(csview sv, isize u8pos, isize u8len) { - const char* s, *end = &sv.buf[sv.size]; - while ((u8pos > 0) & (sv.buf != end)) - u8pos -= (*++sv.buf & 0xC0) != 0x80; - s = sv.buf; - while ((u8len > 0) & (s != end)) - u8len -= (*++s & 0xC0) != 0x80; - sv.size = s - sv.buf; return sv; -} - -csview csview_u8_tail(csview sv, isize u8len) { - const char* p = &sv.buf[sv.size]; - while (u8len && p != sv.buf) - u8len -= (*--p & 0xC0) != 0x80; - sv.size -= p - sv.buf, sv.buf = p; - return sv; -} - -csview_iter csview_u8_at(csview sv, isize u8pos) { - const char *end = &sv.buf[sv.size]; - while ((u8pos > 0) & (sv.buf != end)) - u8pos -= (*++sv.buf & 0xC0) != 0x80; - sv.size = utf8_chr_size(sv.buf); - c_assert(sv.buf != end); - return c_literal(csview_iter){.u8 = {sv, end}}; -} -#endif // IMPLEMENT - -#if defined i_import -#include "priv/utf8_prv.c" -#endif diff --git a/src/finchlite/codegen/stc/include/stc/deque.h b/src/finchlite/codegen/stc/include/stc/deque.h deleted file mode 100644 index dd00206f..00000000 --- a/src/finchlite/codegen/stc/include/stc/deque.h +++ /dev/null @@ -1,205 +0,0 @@ -/* 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. - */ -// Deque - double ended queue. Implemented as a ring buffer, extension of queue. - -#include "priv/linkage.h" -#include "types.h" - -#ifndef STC_DEQUE_H_INCLUDED -#define STC_DEQUE_H_INCLUDED -#include "common.h" -#include -#endif // STC_DEQUE_H_INCLUDED - -#ifndef _i_prefix - #define _i_prefix deque_ -#endif -#define _pop _pop_front -#define _pull _pull_front -#include "priv/template.h" -#include "priv/queue_prv.h" -#undef _pop -#undef _pull - -STC_API _m_value* _c_MEMB(_push_front)(Self* self, _m_value value); -STC_API _m_iter _c_MEMB(_insert_n)(Self* self, isize idx, const _m_value* arr, isize n); -STC_API _m_iter _c_MEMB(_insert_uninit)(Self* self, isize idx, isize n); -STC_API void _c_MEMB(_erase_n)(Self* self, isize idx, isize n); - -STC_INLINE const _m_value* -_c_MEMB(_at)(const Self* self, isize idx) { - c_assert(c_uless(idx, _c_MEMB(_size)(self))); - return self->cbuf + _cbuf_topos(self, idx); -} - -STC_INLINE _m_value* -_c_MEMB(_at_mut)(Self* self, isize idx) - { return (_m_value*)_c_MEMB(_at)(self, idx); } - -STC_INLINE _m_value* -_c_MEMB(_push_back)(Self* self, _m_value val) - { return _c_MEMB(_push)(self, val); } - -STC_INLINE void -_c_MEMB(_pop_back)(Self* self) { - c_assert(!_c_MEMB(_is_empty)(self)); - self->end = (self->end - 1) & self->capmask; - i_keydrop((self->cbuf + self->end)); -} - -STC_INLINE _m_value _c_MEMB(_pull_back)(Self* self) { // move back out of deque - c_assert(!_c_MEMB(_is_empty)(self)); - self->end = (self->end - 1) & self->capmask; - return self->cbuf[self->end]; -} - -STC_INLINE _m_iter -_c_MEMB(_insert_at)(Self* self, _m_iter it, const _m_value val) { - isize idx = _cbuf_toidx(self, it.pos); - return _c_MEMB(_insert_n)(self, idx, &val, 1); -} - -STC_INLINE _m_iter -_c_MEMB(_erase_at)(Self* self, _m_iter it) { - _c_MEMB(_erase_n)(self, _cbuf_toidx(self, it.pos), 1); - if (it.pos == self->end) it.ref = NULL; - return it; -} - -STC_INLINE _m_iter -_c_MEMB(_erase_range)(Self* self, _m_iter it1, _m_iter it2) { - isize idx1 = _cbuf_toidx(self, it1.pos); - isize idx2 = _cbuf_toidx(self, it2.pos); - _c_MEMB(_erase_n)(self, idx1, idx2 - idx1); - if (it1.pos == self->end) it1.ref = NULL; - return it1; -} - -#ifndef i_no_emplace -STC_API _m_iter -_c_MEMB(_emplace_n)(Self* self, isize idx, const _m_raw* raw, isize n); - -STC_INLINE _m_value* -_c_MEMB(_emplace_front)(Self* self, const _m_raw raw) - { return _c_MEMB(_push_front)(self, i_keyfrom(raw)); } - -STC_INLINE _m_value* -_c_MEMB(_emplace_back)(Self* self, const _m_raw raw) - { return _c_MEMB(_push)(self, i_keyfrom(raw)); } - -STC_INLINE _m_iter -_c_MEMB(_emplace_at)(Self* self, _m_iter it, const _m_raw raw) - { return _c_MEMB(_insert_at)(self, it, i_keyfrom(raw)); } -#endif - -#if defined _i_has_eq -STC_API _m_iter _c_MEMB(_find_in)(const Self* self, _m_iter p1, _m_iter p2, _m_raw raw); - -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); -} -#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 _m_value* -_c_MEMB(_push_front)(Self* self, _m_value value) { - isize start = (self->start - 1) & self->capmask; - if (start == self->end) { // full - if (!_c_MEMB(_reserve)(self, self->capmask + 3)) // => 2x expand - return NULL; - start = (self->start - 1) & self->capmask; - } - _m_value *v = self->cbuf + start; - self->start = start; - *v = value; - return v; -} - -STC_DEF void -_c_MEMB(_erase_n)(Self* self, const isize idx, const isize n) { - const isize len = _c_MEMB(_size)(self); - c_assert(idx + n <= len); - for (isize i = idx + n - 1; i >= idx; --i) - i_keydrop(_c_MEMB(_at_mut)(self, i)); - for (isize i = idx, j = i + n; j < len; ++i, ++j) - *_c_MEMB(_at_mut)(self, i) = *_c_MEMB(_at)(self, j); - self->end = (self->end - n) & self->capmask; -} - -STC_DEF _m_iter -_c_MEMB(_insert_uninit)(Self* self, const isize idx, const isize n) { - const isize len = _c_MEMB(_size)(self); - _m_iter it = {._s=self}; - if (len + n >= self->capmask) - if (!_c_MEMB(_reserve)(self, len + n)) // minimum 2x expand - return it; - it.pos = _cbuf_topos(self, idx); - it.ref = self->cbuf + it.pos; - self->end = (self->end + n) & self->capmask; - - if (it.pos < self->end) // common case because of reserve policy - c_memmove(it.ref + n, it.ref, (len - idx)*c_sizeof *it.ref); - else for (isize i = len - 1, j = i + n; i >= idx; --i, --j) - *_c_MEMB(_at_mut)(self, j) = *_c_MEMB(_at)(self, i); - return it; -} - -STC_DEF _m_iter -_c_MEMB(_insert_n)(Self* self, const isize idx, const _m_value* arr, const isize n) { - _m_iter it = _c_MEMB(_insert_uninit)(self, idx, n); - for (isize i = idx, j = 0; j < n; ++i, ++j) - *_c_MEMB(_at_mut)(self, i) = arr[j]; - return it; -} - -#ifndef i_no_emplace -STC_DEF _m_iter -_c_MEMB(_emplace_n)(Self* self, const isize idx, const _m_raw* raw, const isize n) { - _m_iter it = _c_MEMB(_insert_uninit)(self, idx, n); - for (isize i = idx, j = 0; j < n; ++i, ++j) - *_c_MEMB(_at_mut)(self, i) = i_keyfrom(raw[j]); - return it; -} -#endif - -#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; - for (; i1.ref != i2.ref; _c_MEMB(_next)(&i1)) { - const _m_raw r = i_keytoraw(i1.ref); - if (i_eq((&raw), (&r))) - break; - } - return i1; -} -#endif -#endif // IMPLEMENTATION -#include "sys/finalize.h" diff --git a/src/finchlite/codegen/stc/include/stc/hashmap.h b/src/finchlite/codegen/stc/include/stc/hashmap.h deleted file mode 100644 index 5eaaf9df..00000000 --- a/src/finchlite/codegen/stc/include/stc/hashmap.h +++ /dev/null @@ -1,43 +0,0 @@ -/* MIT License - * - * Copyright (c) 2025 Tyge Løvmap - * - * 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. - */ - -// Unordered map - implemented with the robin-hood hashing scheme. -/* -#define T IMap, int, int -#include -#include - -int main(void) { - IMap map = c_make(IMap, {{12, 32}, {42, 54}}); - IMap_insert(&map, 5, 15); - IMap_insert(&map, 8, 18); - - for (c_each_kv(k, v, IMap, map)) - printf(" %d -> %d\n", *k, *v); - - IMap_drop(&map); -} -*/ - -#define _i_prefix hmap_ -#include "hmap.h" diff --git a/src/finchlite/codegen/stc/include/stc/hashset.h b/src/finchlite/codegen/stc/include/stc/hashset.h deleted file mode 100644 index 76a858d7..00000000 --- a/src/finchlite/codegen/stc/include/stc/hashset.h +++ /dev/null @@ -1,44 +0,0 @@ -/* 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. - */ - -// Unordered set - implemented with the robin-hood hashing scheme. -/* -#define T ISet, int -#include -#include - -int main(void) { - ISet set = {0}; - ISet_insert(&set, 5); - ISet_insert(&set, 8); - - for (c_each(i, ISet, set)) - printf(" %d\n", *i.ref); - - ISet_drop(&set); -} -*/ - -#define _i_prefix hset_ -#define _i_is_set -#include "hmap.h" diff --git a/src/finchlite/codegen/stc/include/stc/hmap.h b/src/finchlite/codegen/stc/include/stc/hmap.h deleted file mode 100644 index b6988c32..00000000 --- a/src/finchlite/codegen/stc/include/stc/hmap.h +++ /dev/null @@ -1,517 +0,0 @@ -/* 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. - */ - -// Unordered set/map - implemented with the robin-hood hashing scheme. -/* -#include - -#define T icmap, int, char -#include - -int main(void) { - icmap m = {0}; - icmap_emplace(&m, 5, 'a'); - icmap_emplace(&m, 8, 'b'); - icmap_emplace(&m, 12, 'c'); - - icmap_value* v = icmap_get(&m, 10); // NULL - char val = *icmap_at(&m, 5); // 'a' - icmap_emplace_or_assign(&m, 5, 'd'); // update - icmap_erase(&m, 8); - - for (c_each(i, icmap, m)) - printf("map %d: %c\n", i.ref->first, i.ref->second); - - icmap_drop(&m); -} -*/ -#include "priv/linkage.h" -#include "types.h" - -#ifndef STC_HMAP_H_INCLUDED -#define STC_HMAP_H_INCLUDED -#include "common.h" -#include -#define _hashmask 0x3fU -#define _distmask 0x3ffU -struct hmap_meta { uint16_t hashx:6, dist:10; }; // dist: 0=empty, 1=PSL 0, 2=PSL 1, ... -#endif // STC_HMAP_H_INCLUDED - -#ifndef _i_prefix - #define _i_prefix hmap_ -#endif -#ifndef _i_is_set - #define _i_is_map - #define _i_MAP_ONLY c_true - #define _i_SET_ONLY c_false - #define _i_keyref(vp) (&(vp)->first) -#else - #define _i_MAP_ONLY c_false - #define _i_SET_ONLY c_true - #define _i_keyref(vp) (vp) -#endif -#define _i_is_hash -#include "priv/template.h" -#ifndef i_declared - _c_DEFTYPES(_declare_htable, Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY, _i_aux_def); -#endif - -_i_MAP_ONLY( struct _m_value { - _m_key first; - _m_mapped second; -}; ) - -typedef i_keyraw _m_keyraw; -typedef i_valraw _m_rmapped; -typedef _i_SET_ONLY( i_keyraw ) - _i_MAP_ONLY( struct { _m_keyraw first; - _m_rmapped second; } ) -_m_raw; - -#ifndef i_no_clone -STC_API Self _c_MEMB(_clone)(Self map); -#endif -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 capacity); -STC_API void _c_MEMB(_erase_entry)(Self* self, _m_value* val); -STC_API float _c_MEMB(_max_load_factor)(const Self* self); -STC_API isize _c_MEMB(_capacity)(const Self* map); -STC_API _m_result _c_MEMB(_bucket_lookup_)(const Self* self, const _m_keyraw* rkeyptr); -STC_API _m_result _c_MEMB(_bucket_insert_)(const Self* self, const _m_keyraw* rkeyptr); - -STC_INLINE bool _c_MEMB(_is_empty)(const Self* map) { return !map->size; } -STC_INLINE isize _c_MEMB(_size)(const Self* map) { return (isize)map->size; } -STC_INLINE isize _c_MEMB(_bucket_count)(Self* map) { return map->bucket_count; } -STC_INLINE bool _c_MEMB(_contains)(const Self* self, _m_keyraw rkey) - { return self->size && _c_MEMB(_bucket_lookup_)(self, &rkey).ref; } -STC_INLINE void _c_MEMB(_shrink_to_fit)(Self* self) - { _c_MEMB(_reserve)(self, (isize)self->size); } - -#ifndef i_max_load_factor - #define i_max_load_factor 0.80f -#endif - -STC_INLINE _m_result -_c_MEMB(_insert_entry_)(Self* self, _m_keyraw rkey) { - if (self->size >= (isize)((float)self->bucket_count * (i_max_load_factor))) - if (!_c_MEMB(_reserve)(self, (isize)(self->size*3/2 + 2))) - return c_literal(_m_result){0}; - - _m_result res = _c_MEMB(_bucket_insert_)(self, &rkey); - self->size += res.inserted; - return res; -} - -#ifdef _i_is_map - STC_API _m_result _c_MEMB(_insert_or_assign)(Self* self, _m_key key, _m_mapped mapped); - #ifndef i_no_emplace - STC_API _m_result _c_MEMB(_emplace_or_assign)(Self* self, _m_keyraw rkey, _m_rmapped rmapped); - #endif - - STC_INLINE const _m_mapped* _c_MEMB(_at)(const Self* self, _m_keyraw rkey) { - _m_result res = _c_MEMB(_bucket_lookup_)(self, &rkey); - c_assert(res.ref); - return &res.ref->second; - } - - STC_INLINE _m_mapped* _c_MEMB(_at_mut)(Self* self, _m_keyraw rkey) - { return (_m_mapped*)_c_MEMB(_at)(self, rkey); } -#endif // _i_is_map - -#ifndef i_no_clone - STC_INLINE void _c_MEMB(_copy)(Self *self, const Self* other) { - if (self == other) - return; - _c_MEMB(_drop)(self); - *self = _c_MEMB(_clone)(*other); - } - - STC_INLINE _m_value _c_MEMB(_value_clone)(const Self* self, _m_value _val) { - (void)self; - *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val))); - _i_MAP_ONLY( _val.second = i_valclone(_val.second); ) - return _val; - } -#endif // !i_no_clone - -#ifndef i_no_emplace - STC_INLINE _m_result - _c_MEMB(_emplace)(Self* self, _m_keyraw rkey _i_MAP_ONLY(, _m_rmapped rmapped)) { - _m_result _res = _c_MEMB(_insert_entry_)(self, rkey); - if (_res.inserted) { - *_i_keyref(_res.ref) = i_keyfrom(rkey); - _i_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); ) - } - return _res; - } -#endif // !i_no_emplace - -STC_INLINE _m_raw _c_MEMB(_value_toraw)(const _m_value* val) { - return _i_SET_ONLY( i_keytoraw(val) ) - _i_MAP_ONLY( c_literal(_m_raw){i_keytoraw((&val->first)), i_valtoraw((&val->second))} ); -} - -STC_INLINE void _c_MEMB(_value_drop)(const Self* self, _m_value* _val) { - (void)self; - i_keydrop(_i_keyref(_val)); - _i_MAP_ONLY( i_valdrop((&_val->second)); ) -} - -STC_INLINE Self _c_MEMB(_move)(Self *self) { - Self m = *self; - self->bucket_count = self->size = 0; - self->meta = NULL; self->table = NULL; - return m; -} - -STC_INLINE void _c_MEMB(_take)(Self *self, Self unowned) { - _c_MEMB(_drop)(self); - *self = unowned; -} - -STC_INLINE _m_result -_c_MEMB(_insert)(Self* self, _m_key _key _i_MAP_ONLY(, _m_mapped _mapped)) { - _m_result _res = _c_MEMB(_insert_entry_)(self, i_keytoraw((&_key))); - if (_res.inserted) - { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} - else - { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )} - return _res; -} - -STC_INLINE _m_value* _c_MEMB(_push)(Self* self, _m_value _val) { - _m_result _res = _c_MEMB(_insert_entry_)(self, i_keytoraw(_i_keyref(&_val))); - if (_res.inserted) - *_res.ref = _val; - else - _c_MEMB(_value_drop)(self, &_val); - return _res.ref; -} - -#if defined _i_is_map && !defined _i_no_put -STC_INLINE _m_result _c_MEMB(_put)(Self* self, _m_keyraw rkey, _m_rmapped rmapped) { - #ifdef i_no_emplace - return _c_MEMB(_insert_or_assign)(self, rkey, rmapped); - #else - return _c_MEMB(_emplace_or_assign)(self, rkey, rmapped); - #endif -} -#endif - -#ifndef _i_no_put -STC_INLINE void _c_MEMB(_put_n)(Self* self, const _m_raw* raw, isize n) { - while (n--) - #if defined _i_is_set && defined i_no_emplace - _c_MEMB(_insert)(self, *raw++); - #elif defined _i_is_set - _c_MEMB(_emplace)(self, *raw++); - #else - _c_MEMB(_put)(self, raw->first, raw->second), ++raw; - #endif -} -#endif - -#ifndef _i_aux_alloc -STC_INLINE Self _c_MEMB(_init)(void) - { Self cx = {0}; return cx; } - -#ifndef _i_no_put -STC_INLINE Self _c_MEMB(_from_n)(const _m_raw* raw, isize n) - { Self cx = {0}; _c_MEMB(_put_n)(&cx, raw, n); return cx; } -#endif - -STC_INLINE Self _c_MEMB(_with_capacity)(const isize cap) - { Self cx = {0}; _c_MEMB(_reserve)(&cx, cap); return cx; } -#endif - -STC_API _m_iter _c_MEMB(_begin)(const Self* self); - -STC_INLINE _m_iter _c_MEMB(_end)(const Self* self) - { (void)self; return c_literal(_m_iter){0}; } - -STC_INLINE void _c_MEMB(_next)(_m_iter* it) { - while ((++it->ref, (++it->_mref)->dist == 0)) ; - if (it->ref == it->_end) it->ref = NULL; -} - -STC_INLINE _m_iter _c_MEMB(_advance)(_m_iter it, size_t n) { - while (n-- && it.ref) _c_MEMB(_next)(&it); - return it; -} - -STC_INLINE _m_iter -_c_MEMB(_find)(const Self* self, _m_keyraw rkey) { - _m_value* ref; - if (self->size != 0 && (ref = _c_MEMB(_bucket_lookup_)(self, &rkey).ref) != NULL) - return c_literal(_m_iter){ref, - &self->table[self->bucket_count], - &self->meta[ref - self->table]}; - return _c_MEMB(_end)(self); -} - -STC_INLINE const _m_value* -_c_MEMB(_get)(const Self* self, _m_keyraw rkey) { - return self->size ? _c_MEMB(_bucket_lookup_)(self, &rkey).ref : NULL; -} - -STC_INLINE _m_value* -_c_MEMB(_get_mut)(Self* self, _m_keyraw rkey) - { return (_m_value*)_c_MEMB(_get)(self, rkey); } - -STC_INLINE int -_c_MEMB(_erase)(Self* self, _m_keyraw rkey) { - _m_value* ref; - if (self->size != 0 && (ref = _c_MEMB(_bucket_lookup_)(self, &rkey).ref) != NULL) - { _c_MEMB(_erase_entry)(self, ref); return 1; } - return 0; -} - -STC_INLINE _m_iter -_c_MEMB(_erase_at)(Self* self, _m_iter it) { - _c_MEMB(_erase_entry)(self, it.ref); - if (it._mref->dist == 0) - _c_MEMB(_next)(&it); - return it; -} - -STC_INLINE bool -_c_MEMB(_eq)(const Self* self, const Self* other) { - if (_c_MEMB(_size)(self) != _c_MEMB(_size)(other)) return false; - for (_m_iter i = _c_MEMB(_begin)(self); i.ref; _c_MEMB(_next)(&i)) { - const _m_keyraw _raw = i_keytoraw(_i_keyref(i.ref)); - if (!_c_MEMB(_contains)(other, _raw)) return false; - } - return true; -} - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement - -STC_DEF _m_iter _c_MEMB(_begin)(const Self* self) { - _m_iter it = {self->table, self->table, self->meta}; - if (it.ref == NULL) return it; - it._end += self->bucket_count; - while (it._mref->dist == 0) - ++it.ref, ++it._mref; - if (it.ref == it._end) it.ref = NULL; - return it; -} - -STC_DEF float _c_MEMB(_max_load_factor)(const Self* self) { - (void)self; return (float)(i_max_load_factor); -} - -STC_DEF isize _c_MEMB(_capacity)(const Self* map) { - return (isize)((float)map->bucket_count * (i_max_load_factor)); -} - -static void _c_MEMB(_wipe_)(Self* self) { - if (self->size == 0) - return; - _m_value* d = self->table, *_end = &d[self->bucket_count]; - struct hmap_meta* m = self->meta; - for (; d != _end; ++d) - if ((m++)->dist) - _c_MEMB(_value_drop)(self, d); -} - -STC_DEF void _c_MEMB(_drop)(const Self* cself) { - Self* self = (Self*)cself; - if (self->bucket_count > 0) { - _c_MEMB(_wipe_)(self); - _i_free_n(self->meta, self->bucket_count + 1); - _i_free_n(self->table, self->bucket_count); - } -} - -STC_DEF void _c_MEMB(_clear)(Self* self) { - _c_MEMB(_wipe_)(self); - self->size = 0; - c_memset(self->meta, 0, c_sizeof(struct hmap_meta)*self->bucket_count); -} - -#ifdef _i_is_map - STC_DEF _m_result - _c_MEMB(_insert_or_assign)(Self* self, _m_key _key, _m_mapped _mapped) { - _m_result _res = _c_MEMB(_insert_entry_)(self, i_keytoraw((&_key))); - _m_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped; - if (_res.inserted) - _res.ref->first = _key; - else - { i_keydrop((&_key)); i_valdrop(_mp); } - *_mp = _mapped; - return _res; - } - - #ifndef i_no_emplace - STC_DEF _m_result - _c_MEMB(_emplace_or_assign)(Self* self, _m_keyraw rkey, _m_rmapped rmapped) { - _m_result _res = _c_MEMB(_insert_entry_)(self, rkey); - if (_res.inserted) - _res.ref->first = i_keyfrom(rkey); - else { - if (_res.ref == NULL) return _res; - i_valdrop((&_res.ref->second)); - } - _res.ref->second = i_valfrom(rmapped); - return _res; - } - #endif // !i_no_emplace -#endif // _i_is_map - -STC_DEF _m_result -_c_MEMB(_bucket_lookup_)(const Self* self, const _m_keyraw* rkeyptr) { - const size_t _hash = i_hash(rkeyptr); - const size_t _idxmask = (size_t)self->bucket_count - 1; - _m_result _res = {.idx=_hash & _idxmask, .hashx=(uint8_t)((_hash >> 24) & _hashmask), .dist=1}; - - while (_res.dist <= self->meta[_res.idx].dist) { - if (self->meta[_res.idx].hashx == _res.hashx) { - const _m_keyraw _raw = i_keytoraw(_i_keyref(&self->table[_res.idx])); - if (i_eq((&_raw), rkeyptr)) { - _res.ref = &self->table[_res.idx]; - break; - } - } - _res.idx = (_res.idx + 1) & _idxmask; - ++_res.dist; - } - return _res; -} - -STC_DEF _m_result -_c_MEMB(_bucket_insert_)(const Self* self, const _m_keyraw* rkeyptr) { - _m_result res = _c_MEMB(_bucket_lookup_)(self, rkeyptr); - if (res.ref) // bucket exists - return res; - res.ref = &self->table[res.idx]; - res.inserted = true; - struct hmap_meta mnew = {.hashx=(uint16_t)(res.hashx & _hashmask), - .dist=(uint16_t)(res.dist & _distmask)}; - struct hmap_meta mcur = self->meta[res.idx]; - self->meta[res.idx] = mnew; - - if (mcur.dist != 0) { // collision, reorder buckets - size_t mask = (size_t)self->bucket_count - 1; - _m_value dcur = *res.ref; - for (;;) { - res.idx = (res.idx + 1) & mask; - ++mcur.dist; - if (self->meta[res.idx].dist == 0) - break; - if (self->meta[res.idx].dist < mcur.dist) { - c_swap(&mcur, &self->meta[res.idx]); - c_swap(&dcur, &self->table[res.idx]); - } - } - self->meta[res.idx] = mcur; - self->table[res.idx] = dcur; - } - return res; -} - - -#ifndef i_no_clone - STC_DEF Self - _c_MEMB(_clone)(Self map) { - if (map.bucket_count == 0) - return c_literal(Self){0}; - Self out = map, *self = &out; // _i_new_n may refer self via i_aux - const isize _mbytes = (map.bucket_count + 1)*c_sizeof *map.meta; - out.table = (_m_value *)i_malloc(map.bucket_count*c_sizeof *out.table); - out.meta = (struct hmap_meta *)i_malloc(_mbytes); - - if (out.table && out.meta) { - c_memcpy(out.meta, map.meta, _mbytes); - for (isize i = 0; i < map.bucket_count; ++i) - if (map.meta[i].dist) - out.table[i] = _c_MEMB(_value_clone)(self, map.table[i]); - return out; - } else { - if (out.meta) i_free(out.meta, _mbytes); - if (out.table) _i_free_n(out.table, map.bucket_count); - return c_literal(Self){0}; - } - } -#endif - -STC_DEF bool -_c_MEMB(_reserve)(Self* _self, const isize _newcap) { - isize _newbucks = (isize)((float)_newcap / (i_max_load_factor)) + 4; - _newbucks = c_next_pow2(_newbucks); - - if (_newcap < _self->size || _newbucks == _self->bucket_count) - return true; - Self map = *_self, *self = ↦ (void)self; - map.table = _i_new_n(_m_value, _newbucks); - map.meta = _i_new_zeros(struct hmap_meta, _newbucks + 1); - map.bucket_count = _newbucks; - - bool ok = map.table && map.meta; - if (ok) { // Rehash: - map.meta[_newbucks].dist = _distmask; // end-mark for iter - const _m_value* d = _self->table; - const struct hmap_meta* m = _self->meta; - - for (isize i = 0; i < _self->bucket_count; ++i, ++d) if (m[i].dist != 0) { - _m_keyraw r = i_keytoraw(_i_keyref(d)); - *_c_MEMB(_bucket_insert_)(&map, &r).ref = *d; // move element - } - c_swap(_self, &map); - } - _i_free_n(map.meta, map.bucket_count + (int)(map.meta != NULL)); - _i_free_n(map.table, map.bucket_count); - return ok; -} - -STC_DEF void -_c_MEMB(_erase_entry)(Self* self, _m_value* _val) { - _m_value* d = self->table; - struct hmap_meta *m = self->meta; - size_t i = (size_t)(_val - d), j = i; - size_t mask = (size_t)self->bucket_count - 1; - - _c_MEMB(_value_drop)(self, _val); - for (;;) { - j = (j + 1) & mask; - if (m[j].dist < 2) // 0 => empty, 1 => PSL 0 - break; - d[i] = d[j]; - m[i] = m[j]; - --m[i].dist; - i = j; - } - m[i].dist = 0; - --self->size; -} - -#endif // i_implement -#undef i_max_load_factor -#undef _i_is_set -#undef _i_is_map -#undef _i_is_hash -#undef _i_keyref -#undef _i_MAP_ONLY -#undef _i_SET_ONLY -#include "sys/finalize.h" diff --git a/src/finchlite/codegen/stc/include/stc/hset.h b/src/finchlite/codegen/stc/include/stc/hset.h deleted file mode 100644 index d8a7d990..00000000 --- a/src/finchlite/codegen/stc/include/stc/hset.h +++ /dev/null @@ -1,43 +0,0 @@ -/* 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. - */ - -// Unordered set - implemented with the robin-hood hashing scheme. -/* -#define T iset, int -#include -#include - -int main(void) { - iset set = {0}; - iset_insert(&set, 5); - iset_insert(&set, 8); - - for (c_each(i, iset, set)) - printf("set %d\n", *i.ref); - iset_drop(&set); -} -*/ - -#define _i_prefix hset_ -#define _i_is_set -#include "hmap.h" diff --git a/src/finchlite/codegen/stc/include/stc/list.h b/src/finchlite/codegen/stc/include/stc/list.h deleted file mode 100644 index bf85b3c5..00000000 --- a/src/finchlite/codegen/stc/include/stc/list.h +++ /dev/null @@ -1,431 +0,0 @@ -/* 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. - */ - -/* Circular Singly-linked Lists. - This implements a std::forward_list-like class in C. Because it is circular, - it also support both push_back() and push_front(), unlike std::forward_list: - - #include - #include - - #define T List, long, (c_use_cmp) // enable sorting, uses default *x < *y. - #include - - int main(void) - { - List list = {0}; - - for (int i = 0; i < 5000000; ++i) // five million - List_push_back(&list, crand64_uint() & (1<<24) - 1; - - int n = 0; - for (c_each(i, List, list)) - if (++n % 100000 == 0) printf("%8d: %10zu\n", n, *i.ref); - - // Sort them... - List_sort(&list); // sort.h quicksort - - n = 0; - puts("sorted"); - for (c_each(i, List, list)) - if (++n % 100000 == 0) printf("%8d: %10zu\n", n, *i.ref); - - List_drop(&list); - } -*/ -#include "priv/linkage.h" -#include "types.h" - -#ifndef STC_LIST_H_INCLUDED -#define STC_LIST_H_INCLUDED -#include "common.h" -#include - -#define _c_list_complete_types(SELF, dummy) \ - struct SELF##_node { \ - SELF##_value value; /* must be first! */ \ - struct SELF##_node *next; \ - } - -#define _clist_tonode(vp) c_safe_cast(_m_node*, _m_value*, vp) - -#define _c_list_insert_entry_after(ref, val) \ - _m_node *entry = _i_new_n(_m_node, 1); entry->value = val; \ - _c_list_insert_after_node(ref, entry) - -#define _c_list_insert_after_node(ref, entry) \ - if (ref) entry->next = ref->next, ref->next = entry; \ - else entry->next = entry - // +: set self->last based on node - -#endif // STC_LIST_H_INCLUDED - -#ifndef _i_prefix - #define _i_prefix list_ -#endif -#include "priv/template.h" - -#define _i_is_list -#ifndef i_declared - _c_DEFTYPES(_declare_list, Self, i_key, _i_aux_def); -#endif -_c_DEFTYPES(_c_list_complete_types, Self, dummy); -typedef i_keyraw _m_raw; - -STC_API void _c_MEMB(_drop)(const Self* cself); -STC_API _m_value* _c_MEMB(_push_back)(Self* self, _m_value value); -STC_API _m_value* _c_MEMB(_push_front)(Self* self, _m_value value); -STC_API _m_iter _c_MEMB(_insert_at)(Self* self, _m_iter it, _m_value value); -STC_API _m_iter _c_MEMB(_erase_at)(Self* self, _m_iter it); -STC_API _m_iter _c_MEMB(_erase_range)(Self* self, _m_iter it1, _m_iter it2); -#if defined _i_has_eq -STC_API _m_iter _c_MEMB(_find_in)(const Self* self, _m_iter it1, _m_iter it2, _m_raw val); -STC_API isize _c_MEMB(_remove)(Self* self, _m_raw val); -#endif -#if defined _i_has_cmp -STC_API bool _c_MEMB(_sort)(Self* self); -#endif -STC_API void _c_MEMB(_reverse)(Self* self); -STC_API _m_iter _c_MEMB(_splice)(Self* self, _m_iter it, Self* other); -STC_API Self _c_MEMB(_split_off)(Self* self, _m_iter it1, _m_iter it2); -STC_API _m_value* _c_MEMB(_push_back_node)(Self* self, _m_node* node); -STC_API _m_value* _c_MEMB(_insert_after_node)(Self* self, _m_node* ref, _m_node* node); -STC_API _m_node* _c_MEMB(_unlink_after_node)(Self* self, _m_node* ref); -STC_API void _c_MEMB(_erase_after_node)(Self* self, _m_node* ref); -STC_INLINE _m_node* _c_MEMB(_get_node)(_m_value* pval) { return _clist_tonode(pval); } -STC_INLINE _m_node* _c_MEMB(_unlink_front_node)(Self* self) - { return _c_MEMB(_unlink_after_node)(self, self->last); } -#ifndef i_no_clone -STC_API Self _c_MEMB(_clone)(Self cx); -STC_INLINE _m_value _c_MEMB(_value_clone)(const Self* self, _m_value val) - { (void)self; return i_keyclone(val); } - -STC_INLINE void -_c_MEMB(_copy)(Self *self, const Self* other) { - if (self->last == other->last) return; - _c_MEMB(_drop)(self); - *self = _c_MEMB(_clone)(*other); -} -#endif // !i_no_clone - -#ifndef i_no_emplace -STC_INLINE _m_value* _c_MEMB(_emplace_back)(Self* self, _m_raw raw) - { return _c_MEMB(_push_back)(self, i_keyfrom(raw)); } -STC_INLINE _m_value* _c_MEMB(_emplace_front)(Self* self, _m_raw raw) - { return _c_MEMB(_push_front)(self, i_keyfrom(raw)); } -STC_INLINE _m_iter _c_MEMB(_emplace_at)(Self* self, _m_iter it, _m_raw raw) - { return _c_MEMB(_insert_at)(self, it, i_keyfrom(raw)); } -STC_INLINE _m_value* _c_MEMB(_emplace)(Self* self, _m_raw raw) - { return _c_MEMB(_push_back)(self, i_keyfrom(raw)); } -#endif // !i_no_emplace - -#ifndef _i_no_put -STC_INLINE void _c_MEMB(_put_n)(Self* self, const _m_raw* raw, isize n) - { while (n--) _c_MEMB(_push_back)(self, i_keyfrom((*raw))), ++raw; } -#endif - -#ifndef _i_aux_alloc - STC_INLINE Self _c_MEMB(_init)(void) { return c_literal(Self){0}; } - #ifndef _i_no_put - STC_INLINE Self _c_MEMB(_from_n)(const _m_raw* raw, isize n) - { Self cx = {0}; _c_MEMB(_put_n)(&cx, raw, n); return cx; } - #endif -#endif - -STC_INLINE bool _c_MEMB(_reserve)(Self* self, isize n) { (void)(self + n); return true; } -STC_INLINE bool _c_MEMB(_is_empty)(const Self* self) { return self->last == NULL; } -STC_INLINE void _c_MEMB(_clear)(Self* self) { _c_MEMB(_drop)(self); } -STC_INLINE _m_value* _c_MEMB(_push)(Self* self, _m_value value) - { return _c_MEMB(_push_back)(self, value); } -STC_INLINE void _c_MEMB(_pop_front)(Self* self) - { c_assert(!_c_MEMB(_is_empty)(self)); _c_MEMB(_erase_after_node)(self, self->last); } -STC_INLINE const _m_value* _c_MEMB(_front)(const Self* self) { return &self->last->next->value; } -STC_INLINE _m_value* _c_MEMB(_front_mut)(Self* self) { return &self->last->next->value; } -STC_INLINE const _m_value* _c_MEMB(_back)(const Self* self) { return &self->last->value; } -STC_INLINE _m_value* _c_MEMB(_back_mut)(Self* self) { return &self->last->value; } -STC_INLINE _m_raw _c_MEMB(_value_toraw)(const _m_value* pval) { return i_keytoraw(pval); } -STC_INLINE void _c_MEMB(_value_drop)(const Self* self, _m_value* pval) { (void)self; i_keydrop(pval); } - -STC_INLINE Self _c_MEMB(_move)(Self *self) { - Self m = *self; - self->last = NULL; - return m; -} - -STC_INLINE void _c_MEMB(_take)(Self *self, Self unowned) { - _c_MEMB(_drop)(self); - *self = unowned; -} - -STC_INLINE isize -_c_MEMB(_count)(const Self* self) { - isize n = 1; const _m_node *node = self->last; - if (node == NULL) return 0; - while ((node = node->next) != self->last) ++n; - return n; -} - -STC_INLINE _m_iter -_c_MEMB(_begin)(const Self* self) { - _m_value* head = self->last ? &self->last->next->value : NULL; - return c_literal(_m_iter){head, &self->last, self->last}; -} - -STC_INLINE _m_iter -_c_MEMB(_end)(const Self* self) - { (void)self; return c_literal(_m_iter){0}; } - -STC_INLINE void -_c_MEMB(_next)(_m_iter* it) { - _m_node* node = it->prev = _clist_tonode(it->ref); - it->ref = (node == *it->_last ? NULL : &node->next->value); -} - -STC_INLINE _m_iter -_c_MEMB(_advance)(_m_iter it, size_t n) { - while (n-- && it.ref) _c_MEMB(_next)(&it); - return it; -} - -STC_INLINE _m_iter -_c_MEMB(_splice_range)(Self* self, _m_iter it, - Self* other, _m_iter it1, _m_iter it2) { - Self tmp = _c_MEMB(_split_off)(other, it1, it2); - return _c_MEMB(_splice)(self, it, &tmp); -} - -#if defined _i_has_eq -STC_INLINE _m_iter -_c_MEMB(_find)(const Self* self, _m_raw val) { - return _c_MEMB(_find_in)(self, _c_MEMB(_begin)(self), _c_MEMB(_end)(self), val); -} - -STC_INLINE bool _c_MEMB(_eq)(const Self* self, const Self* other) { - _m_iter i = _c_MEMB(_begin)(self), j = _c_MEMB(_begin)(other); - for (; i.ref && j.ref; _c_MEMB(_next)(&i), _c_MEMB(_next)(&j)) { - const _m_raw _rx = i_keytoraw(i.ref), _ry = i_keytoraw(j.ref); - if (!(i_eq((&_rx), (&_ry)))) return false; - } - return !(i.ref || j.ref); -} -#endif - -// -------------------------- IMPLEMENTATION ------------------------- -#if defined i_implement - -#ifndef i_no_clone -STC_DEF Self -_c_MEMB(_clone)(Self lst) { - Self out = lst, *self = &out; (void)self; // may be used by i_keyclone via i_aux - out.last = NULL; - for (c_each(it, Self, lst)) - _c_MEMB(_push_back)(&out, i_keyclone((*it.ref))); - return out; -} -#endif - -STC_DEF void -_c_MEMB(_drop)(const Self* cself) { - Self* self = (Self*)cself; - while (self->last) - _c_MEMB(_erase_after_node)(self, self->last); -} - -STC_DEF _m_value* -_c_MEMB(_push_back)(Self* self, _m_value value) { - _c_list_insert_entry_after(self->last, value); - self->last = entry; - return &entry->value; -} - -STC_DEF _m_value* -_c_MEMB(_push_front)(Self* self, _m_value value) { - _c_list_insert_entry_after(self->last, value); - if (self->last == NULL) - self->last = entry; - return &entry->value; -} - -STC_DEF _m_value* -_c_MEMB(_push_back_node)(Self* self, _m_node* node) { - _c_list_insert_after_node(self->last, node); - self->last = node; - return &node->value; -} - -STC_DEF _m_value* -_c_MEMB(_insert_after_node)(Self* self, _m_node* ref, _m_node* node) { - _c_list_insert_after_node(ref, node); - if (self->last == NULL) - self->last = node; - return &node->value; -} - -STC_DEF _m_iter -_c_MEMB(_insert_at)(Self* self, _m_iter it, _m_value value) { - _m_node* node = it.ref ? it.prev : self->last; - _c_list_insert_entry_after(node, value); - if (self->last == NULL || it.ref == NULL) { - it.prev = self->last ? self->last : entry; - self->last = entry; - } - it.ref = &entry->value; - return it; -} - -STC_DEF _m_iter -_c_MEMB(_erase_at)(Self* self, _m_iter it) { - _m_node *node = _clist_tonode(it.ref); - it.ref = (node == self->last) ? NULL : &node->next->value; - _c_MEMB(_erase_after_node)(self, it.prev); - return it; -} - -STC_DEF _m_iter -_c_MEMB(_erase_range)(Self* self, _m_iter it1, _m_iter it2) { - _m_node *end = it2.ref ? _clist_tonode(it2.ref) : self->last->next; - if (it1.ref != it2.ref) do { - _c_MEMB(_erase_after_node)(self, it1.prev); - if (self->last == NULL) break; - } while (it1.prev->next != end); - return it2; -} - -STC_DEF void -_c_MEMB(_erase_after_node)(Self* self, _m_node* ref) { - _m_node* node = _c_MEMB(_unlink_after_node)(self, ref); - i_keydrop((&node->value)); - _i_free_n(node, 1); -} - -STC_DEF _m_node* -_c_MEMB(_unlink_after_node)(Self* self, _m_node* ref) { - _m_node* node = ref->next, *next = node->next; - ref->next = next; - if (node == next) - self->last = NULL; - else if (node == self->last) - self->last = ref; - return node; -} - -STC_DEF void -_c_MEMB(_reverse)(Self* self) { - Self rev = *self; - rev.last = NULL; - while (self->last) { - _m_node* node = _c_MEMB(_unlink_after_node)(self, self->last); - _c_MEMB(_insert_after_node)(&rev, rev.last, node); - } - *self = rev; -} - -STC_DEF _m_iter -_c_MEMB(_splice)(Self* self, _m_iter it, Self* other) { - if (self->last == NULL) - self->last = other->last; - else if (other->last) { - _m_node *p = it.ref ? it.prev : self->last, *next = p->next; - it.prev = other->last; - p->next = it.prev->next; - it.prev->next = next; - if (it.ref == NULL) self->last = it.prev; - } - other->last = NULL; - return it; -} - -STC_DEF Self -_c_MEMB(_split_off)(Self* self, _m_iter it1, _m_iter it2) { - Self lst = *self; - lst.last = NULL; - if (it1.ref == it2.ref) - return lst; - _m_node *p1 = it1.prev, - *p2 = it2.ref ? it2.prev : self->last; - p1->next = p2->next; - p2->next = _clist_tonode(it1.ref); - if (self->last == p2) - self->last = (p1 == p2) ? NULL : p1; - lst.last = p2; - return lst; -} - -#if defined _i_has_eq -STC_DEF _m_iter -_c_MEMB(_find_in)(const Self* self, _m_iter it1, _m_iter it2, _m_raw val) { - (void)self; - for (c_each(it, Self, it1, it2)) { - _m_raw r = i_keytoraw(it.ref); - if (i_eq((&r), (&val))) - return it; - } - it2.ref = NULL; return it2; -} - -STC_DEF isize -_c_MEMB(_remove)(Self* self, _m_raw val) { - isize n = 0; - _m_node *prev = self->last, *node; - if (prev) do { - node = prev->next; - _m_raw r = i_keytoraw((&node->value)); - if (i_eq((&r), (&val))) { - _c_MEMB(_erase_after_node)(self, prev), ++n; - if (self->last == NULL) break; - } else - prev = node; - } while (node != self->last); - return n; -} -#endif - -#if defined _i_has_cmp -#include "priv/sort_prv.h" - -STC_DEF bool _c_MEMB(_sort)(Self* self) { - isize len = 0, cap = 0; - _m_value *arr = NULL, *p = NULL; - _m_node* keep; - for (c_each(i, Self, *self)) { - if (len == cap) { - isize cap_n = cap + cap/2 + 8; - if ((p = (_m_value *)_i_realloc_n(arr, cap, cap_n)) == NULL) - goto done; - arr = p, cap = cap_n; - } - arr[len++] = *i.ref; - } - keep = self->last; - self->last = (_m_node *)arr; - _c_MEMB(_sort_lowhigh)(self, 0, len - 1); - self->last = keep; - for (c_each(i, Self, *self)) - *i.ref = *p++; - done: _i_free_n(arr, cap); - return p != NULL; -} -#endif // _i_has_cmp -#endif // i_implement -#undef _i_is_list -#include "sys/finalize.h" diff --git a/src/finchlite/codegen/stc/include/stc/pqueue.h b/src/finchlite/codegen/stc/include/stc/pqueue.h deleted file mode 100644 index dc952416..00000000 --- a/src/finchlite/codegen/stc/include/stc/pqueue.h +++ /dev/null @@ -1,185 +0,0 @@ -/* 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. - */ -#include "priv/linkage.h" -#include "types.h" - -#ifndef STC_PQUEUE_H_INCLUDED -#define STC_PQUEUE_H_INCLUDED -#include "common.h" -#include -#endif // STC_PQUEUIE_H_INCLUDED - -#ifndef _i_prefix - #define _i_prefix pqueue_ -#endif -#define _i_sorted -#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(_make_heap)(Self* self); -STC_API void _c_MEMB(_erase_at)(Self* self, isize idx); -STC_API _m_value* _c_MEMB(_push)(Self* self, _m_value value); - -#ifndef _i_no_put -STC_INLINE void _c_MEMB(_put_n)(Self* self, const _m_raw* raw, isize n) - { while (n--) _c_MEMB(_push)(self, i_keyfrom((*raw))), ++raw; } -#endif - -STC_INLINE bool _c_MEMB(_reserve)(Self* self, const isize cap) { - if (cap != self->size && cap <= self->capacity) return true; - _m_value *d = (_m_value *)_i_realloc_n(self->data, self->capacity, cap); - return d ? (self->data = d, self->capacity = cap, true) : false; -} - -STC_INLINE void _c_MEMB(_shrink_to_fit)(Self* self) - { _c_MEMB(_reserve)(self, self->size); } - -#ifndef _i_aux_alloc -STC_INLINE Self _c_MEMB(_init)(void) - { return c_literal(Self){0}; } - -#ifndef _i_no_put -STC_INLINE Self _c_MEMB(_from_n)(const _m_raw* raw, isize n) - { Self cx = {0}; _c_MEMB(_put_n)(&cx, raw, n); return cx; } -#endif - -STC_INLINE Self _c_MEMB(_with_capacity)(const isize cap) - { Self cx = {0}; _c_MEMB(_reserve)(&cx, cap); return cx; } -#endif - -STC_INLINE void _c_MEMB(_clear)(Self* self) { - isize i = self->size; self->size = 0; - while (i--) { i_keydrop((self->data + i)); } -} - -STC_INLINE void _c_MEMB(_drop)(const Self* cself) { - Self* self = (Self*)cself; - _c_MEMB(_clear)(self); - _i_free_n(self->data, self->capacity); -} - -STC_INLINE Self _c_MEMB(_move)(Self *self) { - Self m = *self; - self->size = self->capacity = 0; - self->data = NULL; - return m; -} - -STC_INLINE void _c_MEMB(_take)(Self *self, Self unowned) { - _c_MEMB(_drop)(self); - *self = unowned; -} - -STC_INLINE isize _c_MEMB(_size)(const Self* q) - { return q->size; } - -STC_INLINE bool _c_MEMB(_is_empty)(const Self* q) - { return !q->size; } - -STC_INLINE isize _c_MEMB(_capacity)(const Self* q) - { return q->capacity; } - -STC_INLINE const _m_value* _c_MEMB(_top)(const Self* self) - { return &self->data[0]; } - -STC_INLINE void _c_MEMB(_pop)(Self* self) - { c_assert(!_c_MEMB(_is_empty)(self)); _c_MEMB(_erase_at)(self, 0); } - -STC_INLINE _m_value _c_MEMB(_pull)(Self* self) - { _m_value v = self->data[0]; _c_MEMB(_erase_at)(self, 0); return v; } - -#ifndef i_no_clone -STC_API Self _c_MEMB(_clone)(Self q); - -STC_INLINE void _c_MEMB(_copy)(Self *self, const Self* other) { - if (self == other) return; - _c_MEMB(_drop)(self); - *self = _c_MEMB(_clone)(*other); -} -STC_INLINE _m_value _c_MEMB(_value_clone)(const Self* self, _m_value val) - { (void)self; return i_keyclone(val); } -#endif // !i_no_clone - -#ifndef i_no_emplace -STC_INLINE void _c_MEMB(_emplace)(Self* self, _m_raw raw) - { _c_MEMB(_push)(self, i_keyfrom(raw)); } -#endif // !i_no_emplace - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement - -STC_DEF void -_c_MEMB(_sift_down_)(Self* self, const isize idx, const isize n) { - _m_value t, *arr = self->data - 1; - for (isize r = idx, c = idx*2; c <= n; c *= 2) { - c += i_less((&arr[c]), (&arr[c + (c < n)])); - if (!(i_less((&arr[r]), (&arr[c])))) return; - t = arr[r], arr[r] = arr[c], arr[r = c] = t; - } -} - -STC_DEF void -_c_MEMB(_make_heap)(Self* self) { - isize n = self->size; - for (isize k = n/2; k != 0; --k) - _c_MEMB(_sift_down_)(self, k, n); -} - -#ifndef i_no_clone -STC_DEF Self _c_MEMB(_clone)(Self q) { - Self out = q, *self = &out; (void)self; - out.capacity = out.size = 0; out.data = NULL; - _c_MEMB(_reserve)(&out, q.size); - out.size = q.size; - for (c_range(i, q.size)) - out.data[i] = i_keyclone(q.data[i]); - return out; -} -#endif - -STC_DEF void -_c_MEMB(_erase_at)(Self* self, const isize idx) { - i_keydrop((self->data + idx)); - const isize n = --self->size; - self->data[idx] = self->data[n]; - _c_MEMB(_sift_down_)(self, idx + 1, n); -} - -STC_DEF _m_value* -_c_MEMB(_push)(Self* self, _m_value value) { - if (self->size == self->capacity) - _c_MEMB(_reserve)(self, self->size*3/2 + 4); - _m_value *arr = self->data - 1; /* base 1 */ - isize c = ++self->size; - for (; c > 1 && (i_less((&arr[c/2]), (&value))); c /= 2) - arr[c] = arr[c/2]; - arr[c] = value; - return arr + c; -} -#endif - -#undef _i_sorted -#include "sys/finalize.h" diff --git a/src/finchlite/codegen/stc/include/stc/priv/cregex_prv.c b/src/finchlite/codegen/stc/include/stc/priv/cregex_prv.c deleted file mode 100644 index 1829bb57..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/cregex_prv.c +++ /dev/null @@ -1,1355 +0,0 @@ -/* -This is a Unix port of the Plan 9 regular expression library, by Rob Pike. -Please send comments about the packaging to Russ Cox . - -Copyright © 2021 Plan 9 Foundation -Copyright © 2023 Tyge Løvset, for additions. - -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_CREGEX_PRV_C_INCLUDED -#define STC_CREGEX_PRV_C_INCLUDED - -#include -#include "utf8_prv.h" -#include "cstr_prv.h" -#include "ucd_prv.c" - -typedef uint32_t _Rune; /* Utf8 code point */ -typedef int32_t _Token; -/* max character classes per program */ -#define _NCLASS CREG_MAX_CLASSES -/* max subexpressions */ -#define _NSUBEXP CREG_MAX_CAPTURES -/* max rune ranges per character class */ -#define _NCCRUNE (_NSUBEXP * 2) - -/* - * character class, each pair of rune's defines a range - */ -typedef struct -{ - _Rune *end; - _Rune spans[_NCCRUNE]; -} _Reclass; - -/* - * Machine instructions - */ -typedef struct _Reinst -{ - _Token type; - union { - _Reclass *classp; /* class pointer */ - _Rune rune; /* character */ - int subid; /* sub-expression id for TOK_RBRA and TOK_LBRA */ - struct _Reinst *right; /* right child of TOK_OR */ - } r; - union { /* regexp relies on these two being in the same union */ - struct _Reinst *left; /* left child of TOK_OR */ - struct _Reinst *next; /* next instruction for TOK_CAT & TOK_LBRA */ - } l; -} _Reinst; - -typedef struct { - bool icase; - bool dotall; -} _Reflags; - -/* - * Reprogram definition - */ -typedef struct _Reprog -{ - _Reinst *startinst; /* start pc */ - _Reflags flags; - int nsubids; - isize allocsize; - _Reclass cclass[_NCLASS]; /* .data */ - _Reinst firstinst[]; /* .text : originally 5 elements? */ -} _Reprog; - -/* - * Sub expression matches - */ -typedef csview _Resub; - -/* - * substitution list - */ -typedef struct _Resublist -{ - _Resub m[_NSUBEXP]; -} _Resublist; - -/* - * Actions and Tokens (_Reinst types) - * - * 0x800000-0x80FFFF: operators, value => precedence - * 0x810000-0x81FFFF: TOK_RUNE and char classes. - * 0x820000-0x82FFFF: tokens, i.e. operands for operators - */ -enum { - TOK_MASK = 0xFF00000, - TOK_OPERATOR = 0x8000000, /* Bitmask of all operators */ - TOK_START = 0x8000001, /* Start, used for marker on stack */ - TOK_RBRA , /* Right bracket, ) */ - TOK_LBRA , /* Left bracket, ( */ - TOK_OR , /* Alternation, | */ - TOK_CAT , /* Concatentation, implicit operator */ - TOK_STAR , /* Closure, * */ - TOK_PLUS , /* a+ == aa* */ - TOK_QUEST , /* a? == a|nothing, i.e. 0 or 1 a's */ - TOK_RUNE = 0x8100000, - TOK_IRUNE , - ASC_an , ASC_AN, /* alphanum */ - ASC_al , ASC_AL, /* alpha */ - ASC_as , ASC_AS, /* ascii */ - ASC_bl , ASC_BL, /* blank */ - ASC_ct , ASC_CT, /* ctrl */ - ASC_d , ASC_D, /* digit */ - ASC_s , ASC_S, /* space */ - ASC_w , ASC_W, /* word */ - ASC_gr , ASC_GR, /* graphic */ - ASC_pr , ASC_PR, /* print */ - ASC_pu , ASC_PU, /* punct */ - ASC_lo , ASC_LO, /* lower */ - ASC_up , ASC_UP, /* upper */ - ASC_xd , ASC_XD, /* hex */ - UTF_an , UTF_AN, /* utf8 alphanumeric */ - UTF_bl , UTF_BL, /* utf8 blank */ - UTF_lc , UTF_LC, /* utf8 letter cased */ - UTF_ll , UTF_LL, /* utf8 letter lowercase */ - UTF_lu , UTF_LU, /* utf8 letter uppercase */ - UTF_sp , UTF_SP, /* utf8 space */ - UTF_wr , UTF_WR, /* utf8 word */ - UTF_GRP = 0x8150000, // odd enums = inverse: - UTF_cc = UTF_GRP+2*U8G_Cc, UTF_CC, /* utf8 control char */ - UTF_l = UTF_GRP+2*U8G_L, UTF_L, /* utf8 letter */ - UTF_lm = UTF_GRP+2*U8G_Lm, UTF_LM, /* utf8 letter modifier */ - UTF_lt = UTF_GRP+2*U8G_Lt, UTF_LT, /* utf8 letter titlecase */ - UTF_nd = UTF_GRP+2*U8G_Nd, UTF_ND, /* utf8 number decimal */ - UTF_nl = UTF_GRP+2*U8G_Nl, UTF_NL, /* utf8 number letter */ - UTF_no = UTF_GRP+2*U8G_No, UTF_NO, /* utf8 number other */ - UTF_p = UTF_GRP+2*U8G_P, UTF_P, /* utf8 punctuation */ - UTF_pc = UTF_GRP+2*U8G_Pc, UTF_PC, /* utf8 punct connector */ - UTF_pd = UTF_GRP+2*U8G_Pd, UTF_PD, /* utf8 punct dash */ - UTF_pe = UTF_GRP+2*U8G_Pe, UTF_PE, /* utf8 punct close */ - UTF_pf = UTF_GRP+2*U8G_Pf, UTF_PF, /* utf8 punct final */ - UTF_pi = UTF_GRP+2*U8G_Pi, UTF_PI, /* utf8 punct initial */ - UTF_ps = UTF_GRP+2*U8G_Ps, UTF_PS, /* utf8 punct open */ - UTF_sc = UTF_GRP+2*U8G_Sc, UTF_SC, /* utf8 symbol currency */ - UTF_sk = UTF_GRP+2*U8G_Sk, UTF_SK, /* utf8 symbol modifier */ - UTF_sm = UTF_GRP+2*U8G_Sm, UTF_SM, /* utf8 symbol math */ - UTF_zl = UTF_GRP+2*U8G_Zl, UTF_ZL, /* utf8 separator line */ - UTF_zp = UTF_GRP+2*U8G_Zp, UTF_ZP, /* utf8 separator paragraph */ - UTF_zs = UTF_GRP+2*U8G_Zs, UTF_ZS, /* utf8 separator space */ - UTF_arabic = UTF_GRP+2*U8G_Arabic, UTF_ARABIC, - UTF_bengali = UTF_GRP+2*U8G_Bengali, UTF_BENGALI, - UTF_cyrillic = UTF_GRP+2*U8G_Cyrillic, UTF_CYRILLIC, - UTF_devanagari = UTF_GRP+2*U8G_Devanagari, UTF_DEVANAGARI, - UTF_georgian = UTF_GRP+2*U8G_Georgian, UTF_GEORGIAN, - UTF_greek = UTF_GRP+2*U8G_Greek, UTF_GREEK, - UTF_han = UTF_GRP+2*U8G_Han, UTF_HAN, - UTF_hiragana = UTF_GRP+2*U8G_Hiragana, UTF_HIRAGANA, - UTF_katakana = UTF_GRP+2*U8G_Katakana, UTF_KATAKANA, - UTF_latin = UTF_GRP+2*U8G_Latin, UTF_LATIN, - UTF_thai = UTF_GRP+2*U8G_Thai, UTF_THAI, - TOK_ANY = 0x8200000, /* Any character except newline, . */ - TOK_ANYNL , /* Any character including newline, . */ - TOK_NOP , /* No operation, internal use only */ - TOK_BOL , TOK_BOS, /* Beginning of line / string, ^ */ - TOK_EOL , TOK_EOS, /* End of line / string, $ */ - TOK_EOZ , /* End of line with optional NL */ - TOK_CCLASS , /* Character class, [] */ - TOK_NCCLASS , /* Negated character class, [] */ - TOK_WBOUND , /* Non-word boundary, not consuming meta char */ - TOK_NWBOUND , /* Word boundary, not consuming meta char */ - TOK_CASED , /* (?-i) */ - TOK_ICASE , /* (?i) */ - TOK_END = 0x82FFFFF, /* Terminate: match found */ -}; - -/* - * _regexec execution lists - */ -#define _LISTSIZE 10 -#define _BIGLISTSIZE (10*_LISTSIZE) - -typedef struct _Relist -{ - _Reinst* inst; /* Reinstruction of the thread */ - _Resublist se; /* matched subexpressions in this thread */ -} _Relist; - -typedef struct _Reljunk -{ - _Relist* relist[2]; - _Relist* reliste[2]; - int starttype; - _Rune startchar; - const char* starts; - const char* eol; -} _Reljunk; - -/* - * utf8 and _Rune code - */ - -static inline int -chartorune(_Rune *rune, const char *s) -{ - utf8_decode_t d = {.state=0}; - int n = utf8_decode_codepoint(&d, s, NULL); - *rune = d.codep; - return n; -} - -static const char* -utfrune(const char *s, _Rune c) // search -{ - if (c < 0x80) /* ascii */ - return strchr((char *)s, (int)c); - - utf8_decode_t d = {.state=0}; - while (*s != 0) { - int n = utf8_decode_codepoint(&d, s, NULL); - if (d.codep == c) return s; - s += n; - } - return NULL; -} - -static const char* -utfruneicase(const char *s, _Rune c) { - if (c < 0x80) { - for (int low = tolower((int)c); *s != 0; ++s) - if (tolower(*s) == low) - return s; - } else { - utf8_decode_t d = {.state=0}; - c = utf8_casefold(c); - while (*s != 0) { - int n = utf8_decode_codepoint(&d, s, NULL); - if (utf8_casefold(d.codep) == c) - return s; - s += n; - } - } - return NULL; -} - -/************ - * regaux.c * - ************/ - -/* - * save a new match in mp - */ -static void -_renewmatch(_Resub *mp, int ms, _Resublist *sp, int nsubids) -{ - if (mp==NULL || ms==0) - return; - if (mp[0].buf == NULL || sp->m[0].buf < mp[0].buf || - (sp->m[0].buf == mp[0].buf && sp->m[0].size > mp[0].size)) { - for (int i=0; im[i]; - } -} - -/* - * Note optimization in _renewthread: - * *lp must be pending when _renewthread called; if *l has been looked - * at already, the optimization is a bug. - */ -static _Relist* -_renewthread(_Relist *lp, /* _relist to add to */ - _Reinst *ip, /* instruction to add */ - int ms, - _Resublist *sep) /* pointers to subexpressions */ -{ - _Relist *p; - - for (p=lp; p->inst; p++) { - if (p->inst == ip) { - if (sep->m[0].buf < p->se.m[0].buf) { - if (ms > 1) - p->se = *sep; - else - p->se.m[0] = sep->m[0]; - } - return 0; - } - } - p->inst = ip; - if (ms > 1) - p->se = *sep; - else - p->se.m[0] = sep->m[0]; - (++p)->inst = NULL; - return p; -} - -/* - * same as renewthread, but called with - * initial empty start pointer. - */ -static _Relist* -_renewemptythread(_Relist *lp, /* _relist to add to */ - _Reinst *ip, /* instruction to add */ - int ms, - const char *sp) /* pointers to subexpressions */ -{ - _Relist *p; - - for (p=lp; p->inst; p++) { - if (p->inst == ip) { - if (sp < p->se.m[0].buf) { - if (ms > 1) - memset(&p->se, 0, sizeof(p->se)); - p->se.m[0].buf = sp; - } - return 0; - } - } - p->inst = ip; - if (ms > 1) - memset(&p->se, 0, sizeof(p->se)); - p->se.m[0].buf = sp; - (++p)->inst = NULL; - return p; -} - -/* - * _Parser Information - */ -typedef struct _Node -{ - _Reinst* first; - _Reinst* last; -} _Node; - -#define _NSTACK 20 -typedef struct _Parser -{ - const char* exprp; /* pointer to next character in source expression */ - _Node andstack[_NSTACK]; - _Node* andp; - _Token atorstack[_NSTACK]; - _Token* atorp; - short subidstack[_NSTACK]; /* parallel to atorstack */ - short* subidp; - short cursubid; /* id of current subexpression */ - int error; - _Reflags flags; - int dot_type; - int rune_type; - bool litmode; - bool lastwasand; /* Last token was _operand */ - short nbra; - short nclass; - isize instcap; - _Rune yyrune; /* last lex'd rune */ - _Reclass *yyclassp; /* last lex'd class */ - _Reclass* classp; - _Reinst* freep; - jmp_buf regkaboom; -} _Parser; - -/* predeclared crap */ -static void _operator(_Parser *par, _Token type); -static void _pushand(_Parser *par, _Reinst *first, _Reinst *last); -static void _pushator(_Parser *par, _Token type); -static void _evaluntil(_Parser *par, _Token type); -static int _bldcclass(_Parser *par); - -static void -_rcerror(_Parser *par, cregex_result err) -{ - par->error = err; - longjmp(par->regkaboom, 1); -} - -static _Reinst* -_newinst(_Parser *par, _Token t) -{ - par->freep->type = t; - par->freep->l.left = 0; - par->freep->r.right = 0; - return par->freep++; -} - -static void -_operand(_Parser *par, _Token t) -{ - _Reinst *i; - - if (par->lastwasand) - _operator(par, TOK_CAT); /* catenate is implicit */ - i = _newinst(par, t); - switch (t) { - case TOK_CCLASS: case TOK_NCCLASS: - i->r.classp = par->yyclassp; break; - case TOK_RUNE: - i->r.rune = par->yyrune; break; - case TOK_IRUNE: - i->r.rune = utf8_casefold(par->yyrune); - } - _pushand(par, i, i); - par->lastwasand = true; -} - -static void -_operator(_Parser *par, _Token t) -{ - if (t==TOK_RBRA && --par->nbra<0) - _rcerror(par, CREG_UNMATCHEDRIGHTPARENTHESIS); - if (t==TOK_LBRA) { - if (++par->cursubid >= _NSUBEXP) - _rcerror(par, CREG_TOOMANYSUBEXPRESSIONS); - par->nbra++; - if (par->lastwasand) - _operator(par, TOK_CAT); - } else - _evaluntil(par, t); - if (t != TOK_RBRA) - _pushator(par, t); - par->lastwasand = 0; - if (t==TOK_STAR || t==TOK_QUEST || t==TOK_PLUS || t==TOK_RBRA) - par->lastwasand = true; /* these look like operands */ -} - -static void -_pushand(_Parser *par, _Reinst *f, _Reinst *l) -{ - if (par->andp >= &par->andstack[_NSTACK]) - _rcerror(par, CREG_OPERANDSTACKOVERFLOW); - par->andp->first = f; - par->andp->last = l; - par->andp++; -} - -static void -_pushator(_Parser *par, _Token t) -{ - if (par->atorp >= &par->atorstack[_NSTACK]) - _rcerror(par, CREG_OPERATORSTACKOVERFLOW); - *par->atorp++ = t; - *par->subidp++ = par->cursubid; -} - -static _Node* -_popand(_Parser *par, _Token op) -{ - (void)op; - _Reinst *inst; - - if (par->andp <= &par->andstack[0]) { - _rcerror(par, CREG_MISSINGOPERAND); - inst = _newinst(par, TOK_NOP); - _pushand(par, inst, inst); - } - return --par->andp; -} - -static _Token -_popator(_Parser *par) -{ - if (par->atorp <= &par->atorstack[0]) - _rcerror(par, CREG_OPERATORSTACKUNDERFLOW); - --par->subidp; - return *--par->atorp; -} - - -static void -_evaluntil(_Parser *par, _Token pri) -{ - _Node *op1, *op2; - _Reinst *inst1, *inst2; - - while (pri==TOK_RBRA || par->atorp[-1]>=pri) { - switch (_popator(par)) { - default: - _rcerror(par, CREG_UNKNOWNOPERATOR); - break; - case TOK_LBRA: /* must have been TOK_RBRA */ - op1 = _popand(par, '('); - inst2 = _newinst(par, TOK_RBRA); - inst2->r.subid = *par->subidp; - op1->last->l.next = inst2; - inst1 = _newinst(par, TOK_LBRA); - inst1->r.subid = *par->subidp; - inst1->l.next = op1->first; - _pushand(par, inst1, inst2); - return; - case TOK_OR: - op2 = _popand(par, '|'); - op1 = _popand(par, '|'); - inst2 = _newinst(par, TOK_NOP); - op2->last->l.next = inst2; - op1->last->l.next = inst2; - inst1 = _newinst(par, TOK_OR); - inst1->r.right = op1->first; - inst1->l.left = op2->first; - _pushand(par, inst1, inst2); - break; - case TOK_CAT: - op2 = _popand(par, 0); - op1 = _popand(par, 0); - op1->last->l.next = op2->first; - _pushand(par, op1->first, op2->last); - break; - case TOK_STAR: - op2 = _popand(par, '*'); - inst1 = _newinst(par, TOK_OR); - op2->last->l.next = inst1; - inst1->r.right = op2->first; - _pushand(par, inst1, inst1); - break; - case TOK_PLUS: - op2 = _popand(par, '+'); - inst1 = _newinst(par, TOK_OR); - op2->last->l.next = inst1; - inst1->r.right = op2->first; - _pushand(par, op2->first, inst1); - break; - case TOK_QUEST: - op2 = _popand(par, '?'); - inst1 = _newinst(par, TOK_OR); - inst2 = _newinst(par, TOK_NOP); - inst1->l.left = inst2; - inst1->r.right = op2->first; - op2->last->l.next = inst2; - _pushand(par, inst1, inst2); - break; - } - } -} - - -static _Reprog* -_optimize(_Parser *par, _Reprog *pp) -{ - _Reinst *inst, *target; - _Reclass *cl; - - /* - * get rid of NOOP chains - */ - for (inst = pp->firstinst; inst->type != TOK_END; inst++) { - target = inst->l.next; - while (target->type == TOK_NOP) - target = target->l.next; - inst->l.next = target; - } - - /* - * The original allocation is for an area larger than - * necessary. Reallocate to the actual space used - * and then relocate the code. - */ - if ((par->freep - pp->firstinst)*2 > par->instcap) - return pp; - - intptr_t ipp = (intptr_t)pp; // convert pointer to integer! - isize new_allocsize = c_sizeof(_Reprog) + (par->freep - pp->firstinst)*c_sizeof(_Reinst); - _Reprog *npp = (_Reprog *)c_realloc(pp, pp->allocsize, new_allocsize); - isize diff = (intptr_t)npp - ipp; - - if ((npp == NULL) | (diff == 0)) - return (_Reprog *)ipp; - npp->allocsize = new_allocsize; - par->freep = (_Reinst *)((char *)par->freep + diff); - - for (inst = npp->firstinst; inst < par->freep; inst++) { - switch (inst->type) { - case TOK_OR: - case TOK_STAR: - case TOK_PLUS: - case TOK_QUEST: - inst->r.right = (_Reinst *)((char*)inst->r.right + diff); - break; - case TOK_CCLASS: - case TOK_NCCLASS: - inst->r.right = (_Reinst *)((char*)inst->r.right + diff); - cl = inst->r.classp; - cl->end = (_Rune *)((char*)cl->end + diff); - break; - } - if (inst->l.left) - inst->l.left = (_Reinst *)((char*)inst->l.left + diff); - } - npp->startinst = (_Reinst *)((char*)npp->startinst + diff); - return npp; -} - - -static _Reclass* -_newclass(_Parser *par) -{ - if (par->nclass >= _NCLASS) - _rcerror(par, CREG_TOOMANYCHARACTERCLASSES); - return &(par->classp[par->nclass++]); -} - - -static int /* quoted */ -_nextc(_Parser *par, _Rune *rp) -{ - int ret; - for (;;) { - ret = par->litmode; - par->exprp += chartorune(rp, par->exprp); - - if (*rp == '\\') { - if (par->litmode) { - if (*par->exprp != 'E') - break; - par->exprp += 1; - par->litmode = false; - continue; - } - par->exprp += chartorune(rp, par->exprp); - if (*rp == 'Q') { - par->litmode = true; - continue; - } - if (*rp == 'x' && *par->exprp == '{') { - *rp = (_Rune)strtol(par->exprp + 1, (char **)&par->exprp, 16); - if (*par->exprp != '}') - _rcerror(par, CREG_UNMATCHEDRIGHTPARENTHESIS); - par->exprp++; - } - ret = 1; - } - break; - } - return ret; -} - - -static void -_lexasciiclass(_Parser *par, _Rune *rp) /* assume *rp == '[' and *par->exprp == ':' */ -{ - static struct { const char* c; int n, r; } cls[] = { - {"alnum:]", 7, ASC_an}, {"alpha:]", 7, ASC_al}, {"ascii:]", 7, ASC_as}, - {"blank:]", 7, ASC_bl}, {"cntrl:]", 7, ASC_ct}, {"digit:]", 7, ASC_d}, - {"graph:]", 7, ASC_gr}, {"lower:]", 7, ASC_lo}, {"print:]", 7, ASC_pr}, - {"punct:]", 7, ASC_pu}, {"space:]", 7, ASC_s}, {"upper:]", 7, ASC_up}, - {"xdigit:]", 8, ASC_xd}, {"word:]", 6, ASC_w}, - }; - int inv = par->exprp[1] == '^', off = 1 + inv; - for (unsigned i = 0; i < (sizeof cls/sizeof *cls); ++i) - if (strncmp(par->exprp + off, cls[i].c, (size_t)cls[i].n) == 0) { - *rp = (_Rune)cls[i].r; - par->exprp += off + cls[i].n; - break; - } - if (par->rune_type == TOK_IRUNE && (*rp == ASC_lo || *rp == ASC_up)) - *rp = (_Rune)ASC_al; - if (inv && *rp != '[') - *rp += 1; -} - - -static void -_lexutfclass(_Parser *par, _Rune *rp) -{ - static struct { const char* c; uint32_t n, r; } cls[] = { - {"{Alpha}", 7, UTF_l}, {"{L&}", 4, UTF_lc}, - {"{Digit}", 7, UTF_nd}, {"{Nd}", 4, UTF_nd}, - {"{Lower}", 7, UTF_ll}, {"{Ll}", 4, UTF_ll}, - {"{Upper}", 7, UTF_lu}, {"{Lu}", 4, UTF_lu}, - {"{Cntrl}", 7, UTF_cc}, {"{Cc}", 4, UTF_cc}, - {"{Alnum}", 7, UTF_an}, {"{Blank}", 7, UTF_bl}, - {"{Space}", 7, UTF_sp}, {"{Word}", 6, UTF_wr}, - {"{XDigit}", 8, ASC_xd}, - {"{L}", 3, UTF_l}, {"{Lm}", 4, UTF_lm}, - {"{Lt}", 4, UTF_lt}, - {"{Nl}", 4, UTF_nl}, {"{No}", 4, UTF_no}, - {"{P}", 3, UTF_p}, {"{Pc}", 4, UTF_pc}, - {"{Pd}", 4, UTF_pd}, {"{Pe}", 4, UTF_pe}, - {"{Pf}", 4, UTF_pf}, {"{Pi}", 4, UTF_pi}, - {"{Ps}", 4, UTF_ps}, - {"{Zl}", 4, UTF_zl}, {"{Zp}", 4, UTF_zp}, - {"{Zs}", 4, UTF_zs}, {"{Sc}", 4, UTF_sc}, - {"{Sk}", 4, UTF_sk}, {"{Sm}", 4, UTF_sm}, - {"{Arabic}", 8, UTF_arabic}, - {"{Bengali}", 9, UTF_bengali}, - {"{Cyrillic}", 10, UTF_cyrillic}, - {"{Devanagari}", 12, UTF_devanagari}, - {"{Georgian}", 10, UTF_georgian}, - {"{Greek}", 7, UTF_greek}, - {"{Han}", 5, UTF_han}, - {"{Hiragana}", 10, UTF_hiragana}, - {"{Katakana}", 10, UTF_katakana}, - {"{Latin}", 7, UTF_latin}, - {"{Thai}", 6, UTF_thai}, - }; - unsigned inv = (*rp == 'P'); - for (unsigned i = 0; i < (sizeof cls/sizeof *cls); ++i) { - if (strncmp(par->exprp, cls[i].c, (size_t)cls[i].n) == 0) { - if (par->rune_type == TOK_IRUNE && (cls[i].r == UTF_ll || cls[i].r == UTF_lu)) - *rp = (_Rune)(UTF_lc + inv); - else - *rp = (_Rune)(cls[i].r + inv); - par->exprp += cls[i].n; - break; - } - } -} - -#define CASE_RUNE_MAPPINGS(rune) \ - case 't': rune = '\t'; break; \ - case 'n': rune = '\n'; break; \ - case 'r': rune = '\r'; break; \ - case 'v': rune = '\v'; break; \ - case 'f': rune = '\f'; break; \ - case 'a': rune = '\a'; break; \ - case 'd': rune = UTF_nd; break; \ - case 'D': rune = UTF_ND; break; \ - case 's': rune = UTF_sp; break; \ - case 'S': rune = UTF_SP; break; \ - case 'w': rune = UTF_wr; break; \ - case 'W': rune = UTF_WR; break - - -static _Token -_lex(_Parser *par) -{ - bool quoted = _nextc(par, &par->yyrune); - - if (quoted) { - if (par->litmode) - return par->rune_type; - - switch (par->yyrune) { - CASE_RUNE_MAPPINGS(par->yyrune); - case 'b': return TOK_WBOUND; - case 'B': return TOK_NWBOUND; - case 'A': return TOK_BOS; - case 'z': return TOK_EOS; - case 'Z': return TOK_EOZ; - case 'p': case 'P': - _lexutfclass(par, &par->yyrune); - break; - } - return par->rune_type; - } - - switch (par->yyrune) { - case 0 : return TOK_END; - case '*': return TOK_STAR; - case '?': return TOK_QUEST; - case '+': return TOK_PLUS; - case '|': return TOK_OR; - case '^': return TOK_BOL; - case '$': return TOK_EOL; - case '.': return par->dot_type; - case '[': return _bldcclass(par); - case '(': - if (par->exprp[0] == '?') { /* override global flags */ - for (int k = 1, enable = 1; ; ++k) switch (par->exprp[k]) { - case 0 : par->exprp += k; return TOK_END; - case ')': par->exprp += k + 1; - return TOK_CASED + (par->rune_type == TOK_IRUNE); - case '-': enable = 0; break; - case 's': par->dot_type = TOK_ANY + enable; break; - case 'i': par->rune_type = TOK_RUNE + enable; break; - default: _rcerror(par, CREG_UNKNOWNOPERATOR); return 0; - } - } - return TOK_LBRA; - case ')': return TOK_RBRA; - } - return par->rune_type; -} - - -static _Token -_bldcclass(_Parser *par) -{ - _Token type; - _Rune r[_NCCRUNE]; - _Rune *p, *ep, *np; - _Rune rune; - int quoted; - - /* we have already seen the '[' */ - type = TOK_CCLASS; - par->yyclassp = _newclass(par); - - /* look ahead for negation */ - /* SPECIAL CASE!!! negated classes don't match \n */ - ep = r; - quoted = _nextc(par, &rune); - if (!quoted && rune == '^') { - type = TOK_NCCLASS; - quoted = _nextc(par, &rune); - ep[0] = ep[1] = '\n'; - ep += 2; - } - - /* parse class into a set of spans */ - for (; ep < &r[_NCCRUNE]; quoted = _nextc(par, &rune)) { - if (rune == 0) { - _rcerror(par, CREG_MALFORMEDCHARACTERCLASS); - return 0; - } - if (!quoted) { - if (rune == ']') - break; - if (rune == '-') { - if (ep != r && *par->exprp != ']') { - quoted = _nextc(par, &rune); - if (rune == 0) { - _rcerror(par, CREG_MALFORMEDCHARACTERCLASS); - return 0; - } - ep[-1] = par->rune_type == TOK_IRUNE ? utf8_casefold(rune) : rune; - continue; - } - } - if (rune == '[' && *par->exprp == ':') - _lexasciiclass(par, &rune); - } else switch (rune) { - CASE_RUNE_MAPPINGS(rune); - case 'p': case 'P': - _lexutfclass(par, &rune); - break; - } - ep[0] = ep[1] = par->rune_type == TOK_IRUNE ? utf8_casefold(rune) : rune; - ep += 2; - } - - /* sort on span start */ - for (p = r; p < ep; p += 2) - for (np = p; np < ep; np += 2) - if (*np < *p) { - rune = np[0]; np[0] = p[0]; p[0] = rune; - rune = np[1]; np[1] = p[1]; p[1] = rune; - } - - /* merge spans */ - np = par->yyclassp->spans; - p = r; - if (r == ep) - par->yyclassp->end = np; - else { - np[0] = *p++; - np[1] = *p++; - for (; p < ep; p += 2) - if (p[0] <= np[1]) { - if (p[1] > np[1]) - np[1] = p[1]; - } else { - np += 2; - np[0] = p[0]; - np[1] = p[1]; - } - par->yyclassp->end = np+2; - } - - return type; -} - - -static _Reprog* -_regcomp1(_Reprog *pp, _Parser *par, const char *s, int cflags) -{ - _Token token; - - /* get memory for the program. estimated max usage */ - isize instcap = 5 + 6*c_strlen(s); - isize new_allocsize = c_sizeof(_Reprog) + instcap*c_sizeof(_Reinst); - pp = (_Reprog *)c_realloc(pp, pp ? pp->allocsize : 0, new_allocsize); - if (pp == NULL) { - par->error = CREG_OUTOFMEMORY; - return NULL; - } - pp->allocsize = new_allocsize; - pp->flags.icase = (cflags & CREG_ICASE) != 0; - pp->flags.dotall = (cflags & CREG_DOTALL) != 0; - par->instcap = instcap; - par->freep = pp->firstinst; - par->classp = pp->cclass; - par->error = 0; - - if (setjmp(par->regkaboom)) - goto out; - - /* go compile the sucker */ - par->flags = pp->flags; - par->rune_type = pp->flags.icase ? TOK_IRUNE : TOK_RUNE; - par->dot_type = pp->flags.dotall ? TOK_ANYNL : TOK_ANY; - par->litmode = false; - par->exprp = s; - par->nclass = 0; - par->nbra = 0; - par->atorp = par->atorstack; - par->andp = par->andstack; - par->subidp = par->subidstack; - par->lastwasand = false; - par->cursubid = 0; - - /* Start with a low priority operator to prime parser */ - _pushator(par, TOK_START-1); - while ((token = _lex(par)) != TOK_END) { - if ((token & TOK_MASK) == TOK_OPERATOR) - _operator(par, token); - else - _operand(par, token); - } - - /* Close with a low priority operator */ - _evaluntil(par, TOK_START); - - /* Force TOK_END */ - _operand(par, TOK_END); - _evaluntil(par, TOK_START); - - if (par->nbra) - _rcerror(par, CREG_UNMATCHEDLEFTPARENTHESIS); - --par->andp; /* points to first and only _operand */ - pp->startinst = par->andp->first; - - pp = _optimize(par, pp); - pp->nsubids = par->cursubid; -out: - if (par->error) { - c_free(pp, pp->allocsize); - pp = NULL; - } - return pp; -} - -#if defined __clang__ - #pragma clang diagnostic ignored "-Wimplicit-fallthrough" -#elif defined __GNUC__ - #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" -#endif - -static int -_runematch(_Rune s, _Rune r) -{ - int inv = 0, n; - switch (s) { - case ASC_D: inv = 1; case ASC_d: return inv ^ (isdigit((int)r) != 0); - case ASC_S: inv = 1; case ASC_s: return inv ^ (isspace((int)r) != 0); - case ASC_W: inv = 1; case ASC_w: return inv ^ ((isalnum((int)r) != 0) | (r == '_')); - case ASC_AL: inv = 1; case ASC_al: return inv ^ (isalpha((int)r) != 0); - case ASC_AN: inv = 1; case ASC_an: return inv ^ (isalnum((int)r) != 0); - case ASC_AS: return (r >= 128); case ASC_as: return (r < 128); - case ASC_BL: inv = 1; case ASC_bl: return inv ^ ((r == ' ') | (r == '\t')); - case ASC_CT: inv = 1; case ASC_ct: return inv ^ (iscntrl((int)r) != 0); - case ASC_GR: inv = 1; case ASC_gr: return inv ^ (isgraph((int)r) != 0); - case ASC_PR: inv = 1; case ASC_pr: return inv ^ (isprint((int)r) != 0); - case ASC_PU: inv = 1; case ASC_pu: return inv ^ (ispunct((int)r) != 0); - case ASC_LO: inv = 1; case ASC_lo: return inv ^ (islower((int)r) != 0); - case ASC_UP: inv = 1; case ASC_up: return inv ^ (isupper((int)r) != 0); - case ASC_XD: inv = 1; case ASC_xd: return inv ^ (isxdigit((int)r) != 0); - case UTF_AN: inv = 1; case UTF_an: return inv ^ (int)utf8_isalnum(r); - case UTF_BL: inv = 1; case UTF_bl: return inv ^ (int)utf8_isblank(r); - case UTF_SP: inv = 1; case UTF_sp: return inv ^ (int)utf8_isspace(r); - case UTF_LL: inv = 1; case UTF_ll: return inv ^ (int)utf8_islower(r); - case UTF_LU: inv = 1; case UTF_lu: return inv ^ (int)utf8_isupper(r); - case UTF_LC: inv = 1; case UTF_lc: return inv ^ (int)utf8_iscased(r); - case UTF_WR: inv = 1; case UTF_wr: return inv ^ (int)utf8_isword(r); - case UTF_L: inv = 1; case UTF_l: return inv ^ (int)utf8_isalpha(r); - case UTF_ND: inv = 1; case UTF_nd: return inv ^ (int)utf8_isdigit(r); -/* isgroup: */ - case UTF_cc: case UTF_CC: - case UTF_lm: case UTF_LM: - case UTF_lt: case UTF_LT: - case UTF_nl: case UTF_NL: - case UTF_no: case UTF_NO: - case UTF_p: case UTF_P: - case UTF_pc: case UTF_PC: - case UTF_pd: case UTF_PD: - case UTF_pe: case UTF_PE: - case UTF_pf: case UTF_PF: - case UTF_pi: case UTF_PI: - case UTF_ps: case UTF_PS: - case UTF_sc: case UTF_SC: - case UTF_sk: case UTF_SK: - case UTF_sm: case UTF_SM: - case UTF_zl: case UTF_ZL: - case UTF_zp: case UTF_ZP: - case UTF_zs: case UTF_ZS: - case UTF_arabic: case UTF_ARABIC: - case UTF_bengali: case UTF_BENGALI: - case UTF_cyrillic: case UTF_CYRILLIC: - case UTF_devanagari: case UTF_DEVANAGARI: - case UTF_georgian: case UTF_GEORGIAN: - case UTF_greek: case UTF_GREEK: - case UTF_han: case UTF_HAN: - case UTF_hiragana: case UTF_HIRAGANA: - case UTF_katakana: case UTF_KATAKANA: - case UTF_latin: case UTF_LATIN: - case UTF_thai: case UTF_THAI: - n = (int)s - UTF_GRP; - inv = n & 1; - return inv ^ (int)utf8_isgroup(n / 2, r); - } - return s == r; -} - -/* - * return 0 if no match - * >0 if a match - * <0 if we ran out of _relist space - */ -static int -_regexec1(const _Reprog *progp, /* program to run */ - const char *bol, /* string to run machine on */ - _Resub *mp, /* subexpression elements */ - int ms, /* number of elements at mp */ - _Reljunk *j, - int mflags -) -{ - int flag=0; - _Reinst *inst; - _Relist *tlp; - _Relist *tl, *nl; /* This list, next list */ - _Relist *tle, *nle; /* Ends of this and next list */ - const char *s, *p; - _Rune r, *rp, *ep; - int n, checkstart, match = 0; - - bool icase = progp->flags.icase; - checkstart = j->starttype; - if (mp) memset(mp, 0, (unsigned)ms*sizeof *mp); - j->relist[0][0].inst = NULL; - j->relist[1][0].inst = NULL; - - /* Execute machine once for each character, including terminal NUL */ - s = j->starts; - do { - /* fast check for first char */ - if (checkstart) { - switch (j->starttype) { - case TOK_IRUNE: - p = utfruneicase(s, j->startchar); - goto next1; - case TOK_RUNE: - p = utfrune(s, j->startchar); - next1: - if (p == NULL || s == j->eol) - return match; - s = p; - break; - case TOK_BOL: - if (s == bol) - break; - p = utfrune(s, '\n'); - if (p == NULL || s == j->eol) - return match; - s = p+1; - break; - } - } - r = *(uint8_t*)s; - n = r < 0x80 ? 1 : chartorune(&r, s); - - /* switch run lists */ - tl = j->relist[flag]; - tle = j->reliste[flag]; - nl = j->relist[flag^=1]; - nle = j->reliste[flag]; - nl->inst = NULL; - - /* Add first instruction to current list */ - if (match == 0) - _renewemptythread(tl, progp->startinst, ms, s); - - /* Execute machine until current list is empty */ - for (tlp=tl; tlp->inst; tlp++) { /* assignment = */ - for (inst = tlp->inst; ; inst = inst->l.next) { - int ok = false; - - switch (inst->type) { - case TOK_IRUNE: - r = utf8_casefold(r); /* FALLTHRU */ - case TOK_RUNE: - ok = _runematch(inst->r.rune, r); - break; - case TOK_CASED: case TOK_ICASE: - icase = inst->type == TOK_ICASE; - continue; - case TOK_LBRA: - tlp->se.m[inst->r.subid].buf = s; - continue; - case TOK_RBRA: - tlp->se.m[inst->r.subid].size = (s - tlp->se.m[inst->r.subid].buf); - continue; - case TOK_ANY: - ok = (r != '\n'); - break; - case TOK_ANYNL: - ok = true; - break; - case TOK_BOL: - if (s == bol || s[-1] == '\n') continue; - break; - case TOK_BOS: - if (s == bol) continue; - break; - case TOK_EOL: - if (r == '\n') continue; /* FALLTHRU */ - case TOK_EOS: - if (s == j->eol || r == 0) continue; - break; - case TOK_EOZ: - if (s == j->eol || r == 0 || (r == '\n' && s[1] == 0)) continue; - break; - case TOK_NWBOUND: - ok = true; /* FALLTHRU */ - case TOK_WBOUND: - if (ok ^ (r == 0 || s == bol || s == j->eol || - (utf8_isword(utf8_peek_at(s, -1)) ^ - utf8_isword(utf8_peek(s))))) - continue; - break; - case TOK_NCCLASS: - ok = true; /* FALLTHRU */ - case TOK_CCLASS: - ep = inst->r.classp->end; - if (icase) r = utf8_casefold(r); - for (rp = inst->r.classp->spans; rp < ep; rp += 2) { - if ((r >= rp[0] && r <= rp[1]) || (rp[0] == rp[1] && _runematch(rp[0], r))) - break; - } - ok ^= (rp < ep); - break; - case TOK_OR: - /* evaluate right choice later */ - if (_renewthread(tlp, inst->r.right, ms, &tlp->se) == tle) - return -1; - /* efficiency: advance and re-evaluate */ - continue; - case TOK_END: /* Match! */ - match = !(mflags & CREG_FULLMATCH) || - ((s == j->eol || r == 0 || r == '\n') && - (tlp->se.m[0].buf == bol || tlp->se.m[0].buf[-1] == '\n')); - tlp->se.m[0].size = (s - tlp->se.m[0].buf); - if (mp != NULL) - _renewmatch(mp, ms, &tlp->se, progp->nsubids); - break; - } - - if (ok && _renewthread(nl, inst->l.next, ms, &tlp->se) == nle) - return -1; - break; - } - } - if (s == j->eol) - break; - checkstart = j->starttype && nl->inst==NULL; - s += n; - } while (r); - return match; -} - - -static int -_regexec2(const _Reprog *progp, /* program to run */ - const char *bol, /* string to run machine on */ - _Resub *mp, /* subexpression elements */ - int ms, /* number of elements at mp */ - _Reljunk *j, - int mflags -) -{ - int rv; - _Relist *relists; - - /* mark space */ - isize sz = 2 * _BIGLISTSIZE*c_sizeof(_Relist); - relists = (_Relist *)c_malloc(sz); - if (relists == NULL) - return -1; - - j->relist[0] = relists; - j->relist[1] = relists + _BIGLISTSIZE; - j->reliste[0] = relists + _BIGLISTSIZE - 2; - j->reliste[1] = relists + 2*_BIGLISTSIZE - 2; - - rv = _regexec1(progp, bol, mp, ms, j, mflags); - c_free(relists, sz); - return rv; -} - -static int -_regexec(const _Reprog *progp, /* program to run */ - const char *bol, /* string to run machine on */ - const char *bol_end,/* end of string (or NULL for null-termination) */ - int ms, /* number of elements at mp */ - _Resub mp[], /* subexpression elements */ - int mflags) -{ - _Reljunk j; - _Relist relist0[_LISTSIZE], relist1[_LISTSIZE]; - int rv; - - /* - * use user-specified starting/ending location if specified - */ - j.starts = bol; - j.eol = bol_end; - - if ((mflags & CREG_NEXT) && mp[0].buf) - j.starts = mp[0].buf + mp[0].size; - if (j.eol && j.starts > j.eol) - return 0; // no match - - j.starttype = 0; - j.startchar = 0; - int rune_type = progp->flags.icase ? TOK_IRUNE : TOK_RUNE; - if (progp->startinst->type == rune_type && progp->startinst->r.rune < 128) { - j.starttype = rune_type; - j.startchar = progp->startinst->r.rune; - } - if (progp->startinst->type == TOK_BOL) - j.starttype = TOK_BOL; - - /* mark space */ - j.relist[0] = relist0; - j.relist[1] = relist1; - j.reliste[0] = relist0 + _LISTSIZE - 2; - j.reliste[1] = relist1 + _LISTSIZE - 2; - - rv = _regexec1(progp, bol, mp, ms, &j, mflags); - if (rv >= 0) - return rv; - rv = _regexec2(progp, bol, mp, ms, &j, mflags); - return rv; -} - - -static void -_build_substitution(const char* replace, int nmatch, const csview match[], - bool(*transform)(int, csview, cstr*), cstr* subst) { - cstr_buf mbuf = cstr_getbuf(subst); - isize len = 0, cap = mbuf.cap; - char* dst = mbuf.data; - cstr tr_str = {0}; - - while (*replace != '\0') { - if (*replace == '$') { - int arg = replace[1]; - if (arg >= '0' && arg <= '9') { - arg -= '0'; - if (replace[2] >= '0' && replace[2] <= '9' && replace[3] == ';') - { arg = arg*10 + (replace[2] - '0'); replace += 2; } - replace += 2; - if (arg < nmatch) { - csview tr_sv = transform && transform(arg, match[arg], &tr_str) - ? cstr_sv(&tr_str) : match[arg]; - if (len + tr_sv.size > cap) - dst = cstr_reserve(subst, cap += cap/2 + tr_sv.size); - for (int i = 0; i < tr_sv.size; ++i) - dst[len++] = tr_sv.buf[i]; - } - continue; - } - if (arg == '$') // allow e.g. "$$3" => "$3" - ++replace; - } - if (len == cap) - dst = cstr_reserve(subst, cap += cap/2 + 4); - dst[len++] = *replace++; - } - cstr_drop(&tr_str); - _cstr_set_size(subst, len); -} - - -/* --------------------------------------------------------------- - * API functions - */ - -int cregex_compile_pro(cregex *self, const char* pattern, int cflags) { - _Parser par; - self->prog = _regcomp1(self->prog, &par, pattern, cflags); - return self->error = par.error; -} - -int cregex_captures(const cregex* self) { - return self->prog ? self->prog->nsubids : 0; -} - -void cregex_drop(cregex* self) { - c_free(self->prog, self->prog->allocsize); -} - -int cregex_match_opt(const cregex* re, const char* input, const char* input_end, struct cregex_match_opt opt) { - int res = _regexec(re->prog, input, input_end, cregex_captures(re) + 1, opt.match, opt.flags); - switch (res) { - case 1: return CREG_OK; - case 0: return CREG_NOMATCH; - default: return CREG_MATCHERROR; - } -} - -int cregex_match_aio_opt(const char* pattern, const char* input, const char* input_end, struct cregex_match_opt opt) { - cregex re = cregex_make(pattern, opt.flags); - if (re.error != CREG_OK) return re.error; - int res = cregex_match_opt(&re, input, input_end, opt); - cregex_drop(&re); - return res; -} - -cstr cregex_replace_opt(const cregex* re, const char* input, const char* input_end, const char* replace, struct cregex_replace_opt opt) { - cstr out = {0}; - cstr subst = {0}; - csview match[CREG_MAX_CAPTURES]; - int nmatch = cregex_captures(re) + 1; - bool copy = !(opt.flags & CREG_STRIP); - struct cregex_match_opt mopt = {match}; - opt.count += (opt.count != 0); - - while (--opt.count && cregex_match_opt(re, input, input_end, mopt) == CREG_OK) { - _build_substitution(replace, nmatch, match, opt.xform, &subst); - const isize mpos = (match[0].buf - input); - if (copy & (mpos > 0)) - cstr_append_n(&out, input, mpos); - cstr_append_s(&out, subst); - input = match[0].buf + match[0].size; - } - if (copy) { - isize len = input_end ? input_end - input : c_strlen(input); - cstr_append_sv(&out, c_sv(input, len)); - } - cstr_drop(&subst); - return out; -} - -cstr cregex_replace_aio_opt(const char* pattern, const char* input, const char* input_end, const char* replace, struct cregex_replace_opt opt) { - cregex re = {0}; - if (cregex_compile_pro(&re, pattern, opt.flags) != CREG_OK) - assert(0); - cstr out = cregex_replace_opt(&re, input, input_end, replace, opt); - cregex_drop(&re); - return out; -} - -#endif // STC_CREGEX_PRV_C_INCLUDED diff --git a/src/finchlite/codegen/stc/include/stc/priv/cstr_prv.c b/src/finchlite/codegen/stc/include/stc/priv/cstr_prv.c deleted file mode 100644 index c01218e5..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/cstr_prv.c +++ /dev/null @@ -1,291 +0,0 @@ -/* 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. - */ -// ------------------- 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 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_internal_move(cstr* self, const isize pos1, const isize pos2) { - cstr_buf b = cstr_getbuf(self); - if (pos1 != pos2) { - const isize 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; -} - -char* _cstr_init(cstr* self, const isize len, const isize 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 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 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 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 cstr_find_at(const cstr* self, const isize 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 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 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; -} - -cstr cstr_from_replace(csview in, csview search, csview repl, int32_t count) { - cstr out = cstr_init(); - isize 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 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; -} - -void cstr_erase(cstr* self, const isize pos, isize 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); -} - -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); - } -} -#endif // STC_CSTR_CORE_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 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 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 cstr_vfmt(cstr* self, isize 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 cstr_append_fmt(cstr* self, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - const isize n = cstr_vfmt(self, cstr_size(self), fmt, args); - va_end(args); - return n; -} - -/* NB! self-data in args is UB */ -isize cstr_printf(cstr* self, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - const isize 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 - -void cstr_u8_erase(cstr* self, const isize u8pos, const isize u8len) { - csview b = cstr_sv(self); - csview span = utf8_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 utf8_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, utf8_casefold}, - {toLower, utf8_tolower}, - {toUpper, utf8_toupper}}; - -cstr cstr_tocase_sv(csview sv, int k) { - cstr out = {0}; - char *buf = cstr_reserve(&out, sv.size*3/2); - isize sz = 0; - utf8_decode_t d = {.state=0}; - const char* end = sv.buf + sv.size; - - while (sv.buf < end) { - sv.buf += utf8_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 += utf8_encode(buf + sz, cp); - } - } - _cstr_set_size(&out, sz); - cstr_shrink_to_fit(&out); - return out; -} -#endif // i_import STC_CSTR_UTF8_C_INCLUDED diff --git a/src/finchlite/codegen/stc/include/stc/priv/cstr_prv.h b/src/finchlite/codegen/stc/include/stc/priv/cstr_prv.h deleted file mode 100644 index 40f58c94..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/cstr_prv.h +++ /dev/null @@ -1,420 +0,0 @@ -/* 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. - */ -// IWYU pragma: private, include "stc/cstr.h" -#ifndef STC_CSTR_PRV_H_INCLUDED -#define STC_CSTR_PRV_H_INCLUDED - -#include /* FILE*, vsnprintf */ -#include /* malloc */ -#include /* size_t */ -#include /* 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)(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)(~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)(~(s)->lon.ncap) - #define cstr_l_set_cap(s, cap) ((s)->lon.ncap = ~(uintptr_t)(cap)) -#endif -#define cstr_l_size(s) (isize)((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 len, isize cap); -extern char* _cstr_internal_move(cstr* self, isize pos1, isize 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 cap); -extern void cstr_shrink_to_fit(cstr* self); -extern char* cstr_resize(cstr* self, isize size, char value); -extern isize cstr_find_at(const cstr* self, isize pos, const char* search); -extern isize cstr_find_sv(const cstr* self, csview search); -extern char* cstr_assign_n(cstr* self, const char* str, isize len); -extern char* cstr_append_n(cstr* self, const char* str, isize len); -extern isize cstr_append_fmt(cstr* self, const char* fmt, ...) c_GNUATTR(format(printf, 2, 3)); -extern char* cstr_append_uninit(cstr *self, isize len); - -extern bool cstr_getdelim(cstr *self, int delim, FILE *fp); -extern void cstr_erase(cstr* self, isize pos, isize len); -extern isize cstr_printf(cstr* self, const char* fmt, ...) c_GNUATTR(format(printf, 2, 3)); -extern isize cstr_vfmt(cstr* self, isize 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 u8pos, isize 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 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 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 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 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 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 cstr_capacity(const cstr* self) - { return cstr_is_long(self) ? cstr_l_cap(self) : cstr_s_cap; } - -STC_INLINE isize cstr_to_index(const cstr* self, cstr_iter it) - { return it.ref - cstr_str(self); } - -STC_INLINE cstr cstr_from_s(cstr s, isize pos, isize len) - { return cstr_from_n(cstr_str(&s) + pos, len); } - -STC_INLINE csview cstr_subview(const cstr* self, isize pos, isize 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 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 u8pos, isize u8len) - { str = utf8_at(str, u8pos); return cstr_from_n(str, utf8_to_index(str, u8len)); } - -STC_INLINE isize cstr_u8_size(const cstr* self) - { return utf8_count(cstr_str(self)); } - -STC_INLINE isize cstr_u8_to_index(const cstr* self, isize u8pos) - { return utf8_to_index(cstr_str(self), u8pos); } - -STC_INLINE zsview cstr_u8_tail(const cstr* self, isize 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 u8pos, isize u8len) - { return utf8_subview(cstr_str(self), u8pos, u8len); } - -STC_INLINE cstr_iter cstr_u8_at(const cstr* self, isize u8pos) { - csview sv; - sv.buf = utf8_at(cstr_str(self), u8pos); - sv.size = utf8_chr_size(sv.buf); - c_assert(sv.size); - return c_literal(cstr_iter){.chr = sv}; -} - -// utf8 iterator - -STC_INLINE cstr_iter cstr_begin(const cstr* self) { - csview sv = cstr_sv(self); - cstr_iter it = {.chr = {sv.buf, utf8_chr_size(sv.buf)}}; - 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; - it->chr.size = utf8_chr_size(it->ref); - if (*it->ref == '\0') it->ref = NULL; -} - -STC_INLINE cstr_iter cstr_advance(cstr_iter it, isize u8pos) { - it.ref = utf8_offset(it.ref, u8pos); - it.chr.size = utf8_chr_size(it.ref); - if (*it.ref == '\0') it.ref = NULL; - return it; -} - -// 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 len = c_strlen(sub); - return len <= sv.size && !utf8_icompare((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 len = c_strlen(sub); - return len <= sv.size && !utf8_icmp(sv.buf + sv.size - len, sub); -} - -STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2) - { return utf8_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 && !utf8_icompare(x, y); -} - -STC_INLINE bool cstr_iequals(const cstr* self, const char* str) - { return !utf8_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 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, utf8_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 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 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 pos, isize 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 pos, isize 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 u8pos, isize u8len, const char* repl) { - const char* s = cstr_str(self); csview span = utf8_subview(s, u8pos, u8len); - cstr_replace_at(self, span.buf - s, span.size, repl); -} - - -STC_INLINE void cstr_insert_sv(cstr* self, isize pos, csview sv) - { cstr_replace_at_sv(self, pos, 0, sv); } - -STC_INLINE void cstr_insert(cstr* self, isize 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 u8pos, const char* str) - { cstr_insert(self, utf8_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 diff --git a/src/finchlite/codegen/stc/include/stc/priv/linkage.h b/src/finchlite/codegen/stc/include/stc/priv/linkage.h deleted file mode 100644 index ed18c729..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/linkage.h +++ /dev/null @@ -1,77 +0,0 @@ -/* 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. - */ -#undef STC_API -#undef STC_DEF - -#if !defined i_static && !defined STC_STATIC && (defined i_header || defined STC_HEADER || \ - defined i_implement || defined STC_IMPLEMENT) - #define STC_API extern - #define STC_DEF -#else - #define i_implement - #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 -#endif -#if defined STC_IMPLEMENT || defined i_import - #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 diff --git a/src/finchlite/codegen/stc/include/stc/priv/linkage2.h b/src/finchlite/codegen/stc/include/stc/priv/linkage2.h deleted file mode 100644 index d99dd239..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/linkage2.h +++ /dev/null @@ -1,42 +0,0 @@ -/* 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. - */ - -#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 diff --git a/src/finchlite/codegen/stc/include/stc/priv/queue_prv.h b/src/finchlite/codegen/stc/include/stc/priv/queue_prv.h deleted file mode 100644 index b1d46c60..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/queue_prv.h +++ /dev/null @@ -1,291 +0,0 @@ -/* 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. - */ - -// IWYU pragma: private -#ifndef i_declared -_c_DEFTYPES(_declare_queue, Self, i_key, _i_aux_def); -#endif -typedef i_keyraw _m_raw; - -STC_API bool _c_MEMB(_reserve)(Self* self, const isize cap); -STC_API void _c_MEMB(_clear)(Self* self); -STC_API void _c_MEMB(_drop)(const Self* cself); -STC_API _m_value* _c_MEMB(_push)(Self* self, _m_value value); // push_back -STC_API void _c_MEMB(_shrink_to_fit)(Self *self); -STC_API _m_iter _c_MEMB(_advance)(_m_iter it, isize n); - -#define _cbuf_toidx(self, pos) (((pos) - (self)->start) & (self)->capmask) -#define _cbuf_topos(self, idx) (((self)->start + (idx)) & (self)->capmask) - -#ifndef _i_no_put -STC_INLINE void _c_MEMB(_put_n)(Self* self, const _m_raw* raw, isize n) - { while (n--) _c_MEMB(_push)(self, i_keyfrom((*raw))), ++raw; } -#endif - -STC_INLINE void _c_MEMB(_value_drop)(const Self* self, _m_value* val) - { (void)self; i_keydrop(val); } - -#ifndef _i_aux_alloc - STC_INLINE Self _c_MEMB(_init)(void) - { Self out = {0}; return out; } - - STC_INLINE Self _c_MEMB(_with_capacity)(isize cap) { - cap = c_next_pow2(cap + 1); - Self out = {_i_new_n(_m_value, cap), 0, 0, cap - 1}; - return out; - } - - STC_INLINE Self _c_MEMB(_with_size_uninit)(isize size) - { Self out = _c_MEMB(_with_capacity)(size); out.end = size; return out; } - - STC_INLINE Self _c_MEMB(_with_size)(isize size, _m_raw default_raw) { - Self out = _c_MEMB(_with_capacity)(size); - while (out.end < size) out.cbuf[out.end++] = i_keyfrom(default_raw); - return out; - } - - #ifndef _i_no_put - STC_INLINE Self _c_MEMB(_from_n)(const _m_raw* raw, isize n) { - Self out = _c_MEMB(_with_capacity)(n); - _c_MEMB(_put_n)(&out, raw, n); return out; - } - #endif -#endif - -#ifndef i_no_emplace -STC_INLINE _m_value* _c_MEMB(_emplace)(Self* self, _m_raw raw) - { return _c_MEMB(_push)(self, i_keyfrom(raw)); } -#endif - -#if defined _i_has_eq -STC_API bool _c_MEMB(_eq)(const Self* self, const Self* other); -#endif - -#ifndef i_no_clone -STC_API Self _c_MEMB(_clone)(Self q); - -STC_INLINE _m_value _c_MEMB(_value_clone)(const Self* self, _m_value val) - { (void)self; return i_keyclone(val); } - -STC_INLINE void _c_MEMB(_copy)(Self* self, const Self* other) { - if (self == other) return; - _c_MEMB(_drop)(self); - *self = _c_MEMB(_clone)(*other); -} -#endif // !i_no_clone - -STC_INLINE isize _c_MEMB(_size)(const Self* self) - { return _cbuf_toidx(self, self->end); } - -STC_INLINE isize _c_MEMB(_capacity)(const Self* self) - { return self->capmask; } - -STC_INLINE bool _c_MEMB(_is_empty)(const Self* self) - { return self->start == self->end; } - -STC_INLINE _m_raw _c_MEMB(_value_toraw)(const _m_value* pval) - { return i_keytoraw(pval); } - -STC_INLINE const _m_value* _c_MEMB(_front)(const Self* self) - { return self->cbuf + self->start; } - -STC_INLINE _m_value* _c_MEMB(_front_mut)(Self* self) - { return self->cbuf + self->start; } - -STC_INLINE const _m_value* _c_MEMB(_back)(const Self* self) - { return self->cbuf + ((self->end - 1) & self->capmask); } - -STC_INLINE _m_value* _c_MEMB(_back_mut)(Self* self) - { return (_m_value*)_c_MEMB(_back)(self); } - -STC_INLINE Self _c_MEMB(_move)(Self *self) { - Self m = *self; - self->capmask = self->start = self->end = 0; - self->cbuf = NULL; - return m; -} - -STC_INLINE void _c_MEMB(_take)(Self *self, Self unowned) - { _c_MEMB(_drop)(self); *self = unowned; } - -STC_INLINE void _c_MEMB(_pop)(Self* self) { // pop_front - c_assert(!_c_MEMB(_is_empty)(self)); - i_keydrop((self->cbuf + self->start)); - self->start = (self->start + 1) & self->capmask; -} - -STC_INLINE _m_value _c_MEMB(_pull)(Self* self) { // move front out of queue - c_assert(!_c_MEMB(_is_empty)(self)); - isize s = self->start; - self->start = (s + 1) & self->capmask; - return self->cbuf[s]; -} - -STC_INLINE _m_iter _c_MEMB(_begin)(const Self* self) { - return c_literal(_m_iter){ - .ref=_c_MEMB(_is_empty)(self) ? NULL : self->cbuf + self->start, - .pos=self->start, ._s=self}; -} - -STC_INLINE _m_iter _c_MEMB(_rbegin)(const Self* self) { - isize pos = (self->end - 1) & self->capmask; - return c_literal(_m_iter){ - .ref=_c_MEMB(_is_empty)(self) ? NULL : self->cbuf + pos, - .pos=pos, ._s=self}; -} - -STC_INLINE _m_iter _c_MEMB(_end)(const Self* self) - { (void)self; return c_literal(_m_iter){0}; } - -STC_INLINE _m_iter _c_MEMB(_rend)(const Self* self) - { (void)self; return c_literal(_m_iter){0}; } - -STC_INLINE void _c_MEMB(_next)(_m_iter* it) { - if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; } - else { it->ref -= it->pos; it->pos = 0; } - if (it->pos == it->_s->end) it->ref = NULL; -} - -STC_INLINE void _c_MEMB(_rnext)(_m_iter* it) { - if (it->pos == it->_s->start) it->ref = NULL; - else if (it->pos != 0) { --it->ref; --it->pos; } - else it->ref += (it->pos = it->_s->capmask); -} - -STC_INLINE isize _c_MEMB(_index)(const Self* self, _m_iter it) - { return _cbuf_toidx(self, it.pos); } - -STC_INLINE void _c_MEMB(_adjust_end_)(Self* self, isize n) - { self->end = (self->end + n) & self->capmask; } - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement - -STC_DEF _m_iter _c_MEMB(_advance)(_m_iter it, isize n) { - isize len = _c_MEMB(_size)(it._s); - isize pos = it.pos, idx = _cbuf_toidx(it._s, pos); - it.pos = (pos + n) & it._s->capmask; - it.ref += it.pos - pos; - if (!c_uless(idx + n, len)) it.ref = NULL; - return it; -} - -STC_DEF void -_c_MEMB(_clear)(Self* self) { - for (c_each(i, Self, *self)) - { i_keydrop(i.ref); } - self->start = 0, self->end = 0; -} - -STC_DEF void -_c_MEMB(_drop)(const Self* cself) { - Self* self = (Self*)cself; - _c_MEMB(_clear)(self); - _i_free_n(self->cbuf, self->capmask + 1); -} - -STC_DEF bool -_c_MEMB(_reserve)(Self* self, const isize cap) { - isize oldpow2 = self->capmask + (self->capmask & 1); // handle capmask = 0 - isize newpow2 = c_next_pow2(cap + 1); - if (newpow2 <= oldpow2) - return self->cbuf != NULL; - _m_value* d = (_m_value *)_i_realloc_n(self->cbuf, oldpow2, newpow2); - if (d == NULL) - return false; - isize head = oldpow2 - self->start; - if (self->start <= self->end) // [..S########E....|................] - ; - else if (head < self->end) { // [#######E.....S##|.............s!!] - c_memcpy(d + newpow2 - head, d + self->start, head*c_sizeof *d); - self->start = newpow2 - head; - } else { // [##E.....S#######|!!e.............] - c_memcpy(d + oldpow2, d, self->end*c_sizeof *d); - self->end += oldpow2; - } - self->capmask = newpow2 - 1; - self->cbuf = d; - return true; -} - -STC_DEF _m_value* -_c_MEMB(_push)(Self* self, _m_value value) { // push_back - isize end = (self->end + 1) & self->capmask; - if (end == self->start) { // full - if (!_c_MEMB(_reserve)(self, self->capmask + 3)) // => 2x expand - return NULL; - end = (self->end + 1) & self->capmask; - } - _m_value *v = self->cbuf + self->end; - self->end = end; - *v = value; - return v; -} - -STC_DEF void -_c_MEMB(_shrink_to_fit)(Self *self) { - isize sz = _c_MEMB(_size)(self); - isize newpow2 = c_next_pow2(sz + 1); - if (newpow2 > self->capmask) - return; - if (self->start <= self->end) { - c_memmove(self->cbuf, self->cbuf + self->start, sz*c_sizeof *self->cbuf); - self->start = 0, self->end = sz; - } else { - isize n = self->capmask - self->start + 1; - c_memmove(self->cbuf + (newpow2 - n), self->cbuf + self->start, n*c_sizeof *self->cbuf); - self->start = newpow2 - n; - } - self->cbuf = (_m_value *)_i_realloc_n(self->cbuf, self->capmask + 1, newpow2); - self->capmask = newpow2 - 1; -} - -#ifndef i_no_clone -STC_DEF Self -_c_MEMB(_clone)(Self q) { - Self out = q, *self = &out; (void)self; // may be used by _i_new_n/i_keyclone via i_aux. - out.start = 0; out.end = _c_MEMB(_size)(&q); - out.capmask = c_next_pow2(out.end + 1) - 1; - out.cbuf = _i_new_n(_m_value, out.capmask + 1); - isize i = 0; - if (out.cbuf) - for (c_each(it, Self, q)) - out.cbuf[i++] = i_keyclone((*it.ref)); - return out; -} -#endif // i_no_clone - -#if defined _i_has_eq -STC_DEF bool -_c_MEMB(_eq)(const Self* self, const Self* other) { - if (_c_MEMB(_size)(self) != _c_MEMB(_size)(other)) return false; - for (_m_iter i = _c_MEMB(_begin)(self), j = _c_MEMB(_begin)(other); - i.ref; _c_MEMB(_next)(&i), _c_MEMB(_next)(&j)) - { - const _m_raw _rx = i_keytoraw(i.ref), _ry = i_keytoraw(j.ref); - if (!(i_eq((&_rx), (&_ry)))) return false; - } - return true; -} -#endif // _i_has_eq -#endif // IMPLEMENTATION diff --git a/src/finchlite/codegen/stc/include/stc/priv/sort_prv.h b/src/finchlite/codegen/stc/include/stc/priv/sort_prv.h deleted file mode 100644 index 6a9f5098..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/sort_prv.h +++ /dev/null @@ -1,136 +0,0 @@ -/* 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. - */ - -// IWYU pragma: private -#ifdef _i_is_list - #define i_at(self, idx) (&((_m_value *)(self)->last)[idx]) - #define i_at_mut i_at -#elif !defined i_at - #define i_at(self, idx) _c_MEMB(_at)(self, idx) - #define i_at_mut(self, idx) _c_MEMB(_at_mut)(self, idx) -#endif - -STC_API void _c_MEMB(_sort_lowhigh)(Self* self, isize lo, isize hi); - -#ifdef _i_is_array -STC_API isize _c_MEMB(_lower_bound_range)(const Self* self, const _m_raw raw, isize start, isize end); -STC_API isize _c_MEMB(_binary_search_range)(const Self* self, const _m_raw raw, isize start, isize end); - -static inline void _c_MEMB(_sort)(Self* arr, isize n) - { _c_MEMB(_sort_lowhigh)(arr, 0, n - 1); } - -static inline isize // c_NPOS = not found -_c_MEMB(_lower_bound)(const Self* arr, const _m_raw raw, isize n) - { return _c_MEMB(_lower_bound_range)(arr, raw, 0, n); } - -static inline isize // c_NPOS = not found -_c_MEMB(_binary_search)(const Self* arr, const _m_raw raw, isize n) - { return _c_MEMB(_binary_search_range)(arr, raw, 0, n); } - -#elif !defined _i_is_list -STC_API isize _c_MEMB(_lower_bound_range)(const Self* self, const _m_raw raw, isize start, isize end); -STC_API isize _c_MEMB(_binary_search_range)(const Self* self, const _m_raw raw, isize start, isize end); - -static inline void _c_MEMB(_sort)(Self* self) - { _c_MEMB(_sort_lowhigh)(self, 0, _c_MEMB(_size)(self) - 1); } - -static inline isize // c_NPOS = not found -_c_MEMB(_lower_bound)(const Self* self, const _m_raw raw) - { return _c_MEMB(_lower_bound_range)(self, raw, 0, _c_MEMB(_size)(self)); } - -static inline isize // c_NPOS = not found -_c_MEMB(_binary_search)(const Self* self, const _m_raw raw) - { return _c_MEMB(_binary_search_range)(self, raw, 0, _c_MEMB(_size)(self)); } -#endif - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement - -static void _c_MEMB(_insertsort_lowhigh)(Self* self, isize lo, isize hi) { - for (isize j = lo, i = lo + 1; i <= hi; j = i, ++i) { - _m_value x = *i_at(self, i); - _m_raw rx = i_keytoraw((&x)); - while (j >= 0) { - _m_raw ry = i_keytoraw(i_at(self, j)); - if (!(i_less((&rx), (&ry)))) break; - *i_at_mut(self, j + 1) = *i_at(self, j); - --j; - } - *i_at_mut(self, j + 1) = x; - } -} - -STC_DEF void _c_MEMB(_sort_lowhigh)(Self* self, isize lo, isize hi) { - isize i = lo, j; - while (lo < hi) { - _m_raw pivot = i_keytoraw(i_at(self, (isize)(lo + (hi - lo)*7LL/16))), rx; - j = hi; - do { - do { rx = i_keytoraw(i_at(self, i)); } while ((i_less((&rx), (&pivot))) && ++i); - do { rx = i_keytoraw(i_at(self, j)); } while ((i_less((&pivot), (&rx))) && --j); - if (i > j) break; - c_swap(i_at_mut(self, i), i_at_mut(self, j)); - ++i; --j; - } while (i <= j); - - if (j - lo > hi - i) { - c_swap(&lo, &i); - c_swap(&hi, &j); - } - if (j - lo > 64) _c_MEMB(_sort_lowhigh)(self, lo, j); - else if (j > lo) _c_MEMB(_insertsort_lowhigh)(self, lo, j); - lo = i; - } -} - -#ifndef _i_is_list -STC_DEF isize // c_NPOS = not found -_c_MEMB(_lower_bound_range)(const Self* self, const _m_raw raw, isize start, isize end) { - isize count = end - start, step = count/2; - while (count > 0) { - const _m_raw rx = i_keytoraw(i_at(self, start + step)); - if (i_less((&rx), (&raw))) { - start += step + 1; - count -= step + 1; - step = count*7/8; - } else { - count = step; - step = count/8; - } - } - return start >= end ? c_NPOS : start; -} - -STC_DEF isize // c_NPOS = not found -_c_MEMB(_binary_search_range)(const Self* self, const _m_raw raw, isize start, isize end) { - isize res = _c_MEMB(_lower_bound_range)(self, raw, start, end); - if (res != c_NPOS) { - const _m_raw rx = i_keytoraw(i_at(self, res)); - if (i_less((&raw), (&rx))) res = c_NPOS; - } - return res; -} -#endif // !_i_is_list -#endif // IMPLEMENTATION -#undef i_at -#undef i_at_mut diff --git a/src/finchlite/codegen/stc/include/stc/priv/template.h b/src/finchlite/codegen/stc/include/stc/priv/template.h deleted file mode 100644 index 86211456..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/template.h +++ /dev/null @@ -1,301 +0,0 @@ -/* 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. - */ -// 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_arc2 (1<<2) - #define c_no_clone (1<<3) - #define c_no_hash (1<<4) - #define c_use_cmp (1<<5) - #define c_use_eq (1<<6) - #define c_cmpclass (1<<7) - #define c_keyclass (1<<8) - #define c_valclass (1<<9) - #define c_keypro (1<<10) - #define c_valpro (1<<11) -#endif - -#if defined i_rawclass // [deprecated] - #define i_cmpclass i_rawclass -#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) - #if c_NUMARGS(i_type) == 3 - #if defined _i_is_map - #define i_val c_GETARG(3, i_type) - #else - #define i_opt c_GETARG(3, i_type) - #endif - #elif c_NUMARGS(i_type) == 4 - #define i_val c_GETARG(3, i_type) - #define i_opt c_GETARG(4, i_type) - #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_no_hash) - #define i_no_hash -#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_keyclass) - #define i_keyclass i_key -#endif -#if c_OPTION(c_valclass) - #define i_valclass i_val -#endif -#if c_OPTION(c_cmpclass) - #define i_cmpclass i_key - #define i_use_cmp -#endif -#if c_OPTION(c_keypro) - #define i_keypro i_key -#endif -#if c_OPTION(c_valpro) - #define i_valpro i_val -#endif - -#if defined i_keypro - #define i_keyclass i_keypro - #define i_cmpclass c_JOIN(i_keypro, _raw) -#endif - -#if defined i_cmpclass - #define i_keyraw i_cmpclass -#elif defined i_keyclass && !defined i_keyraw - // When only i_keyclass is defined, we also define i_cmpclass to the same. - // We do not define i_keyraw here, otherwise _from() / _toraw() is expected to exist. - #define i_cmpclass 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_keyclass - #ifndef i_key - #define i_key i_keyclass - #endif - #if !defined i_keyclone && !defined i_no_clone - #define i_keyclone c_JOIN(i_keyclass, _clone) - #endif - #ifndef i_keydrop - #define i_keydrop c_JOIN(i_keyclass, _drop) - #endif - #if !defined i_keyfrom && defined i_keyraw - #define i_keyfrom c_JOIN(i_keyclass, _from) - #endif - #if !defined i_keytoraw && defined i_keyraw - #define i_keytoraw c_JOIN(i_keyclass, _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 - #define _i_has_cmp -#endif -#if defined i_use_cmp || defined i_cmp || defined i_use_eq || defined i_eq - #define _i_has_eq -#endif - -// Bind to i_cmpclass "class members": _cmp, _eq and _hash (when conditions are met). -#if defined i_cmpclass - #if !(defined i_cmp || defined i_less) && (defined i_use_cmp || defined _i_sorted) - #define i_cmp c_JOIN(i_cmpclass, _cmp) - #endif - #if !defined i_eq && (defined i_use_eq || defined i_hash || defined _i_is_hash) - #define i_eq c_JOIN(i_cmpclass, _eq) - #endif - #if !(defined i_hash || defined i_no_hash) - #define i_hash c_JOIN(i_cmpclass, _hash) - #endif -#endif - -#if !defined i_key - #error "No i_key defined" -#elif defined i_keyraw && !(c_OPTION(c_cmpclass) || defined i_keytoraw) - #error "If i_cmpclass / 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 && defined i_cmp - #define i_eq(x, y) (i_cmp(x, y)) == 0 -#elif !defined i_eq - #define i_eq(x, y) *x == *y // works for integral types -#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 - -#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 -#endif - -#if defined _i_is_map // ---- process hashmap/sortedmap value i_val, ... ---- - -#if defined i_valpro - #define i_valclass i_valpro - #define i_valraw c_JOIN(i_valpro, _raw) -#endif - -#ifdef i_valclass - #ifndef i_val - #define i_val i_valclass - #endif - #if !defined i_valclone && !defined i_no_clone - #define i_valclone c_JOIN(i_valclass, _clone) - #endif - #ifndef i_valdrop - #define i_valdrop c_JOIN(i_valclass, _drop) - #endif - #if !defined i_valfrom && defined i_valraw - #define i_valfrom c_JOIN(i_valclass, _from) - #endif - #if !defined i_valtoraw && defined i_valraw - #define i_valtoraw c_JOIN(i_valclass, _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 -#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 diff --git a/src/finchlite/codegen/stc/include/stc/priv/template2.h b/src/finchlite/codegen/stc/include/stc/priv/template2.h deleted file mode 100644 index fc5cc8f2..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/template2.h +++ /dev/null @@ -1,72 +0,0 @@ -/* 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. - */ -// 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_key -#undef i_keypro // Replaces next two -#undef i_key_str // [deprecated] -#undef i_key_arcbox // [deprecated] -#undef i_keyclass -#undef i_cmpclass // define i_keyraw, and bind i_cmp, i_eq, i_hash "class members" -#undef i_rawclass // [deprecated] for i_cmpclass -#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_val -#undef i_valpro // Replaces next two -#undef i_val_str // [deprecated] -#undef i_val_arcbox // [deprecated] -#undef i_valclass -#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_no_emplace -#undef i_declared - -#undef _i_no_put -#undef _i_aux_def -#undef _i_has_cmp -#undef _i_has_eq -#undef _i_prefix -#undef _i_template -#undef Self diff --git a/src/finchlite/codegen/stc/include/stc/priv/ucd_prv.c b/src/finchlite/codegen/stc/include/stc/priv/ucd_prv.c deleted file mode 100644 index 154da4e3..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/ucd_prv.c +++ /dev/null @@ -1,1296 +0,0 @@ -/* 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_UCD_PRV_C_INCLUDED -#define STC_UCD_PRV_C_INCLUDED - -// ------------------------------------------------------ -// The following requires linking with utf8 symbols. -// To call them, either define i_import before including -// one of cstr, csview, zsview, or link with src/libstc.o. - -/* The tables below are extracted from the RE2 library */ - -typedef struct { - uint16_t lo; - uint16_t hi; -} URange16; - -static const URange16 Cc_range16[] = { // Control - { 0, 31 }, - { 127, 159 }, -}; - -static const URange16 L_range16[] = { // Letter - { 65, 90 }, - { 97, 122 }, - { 170, 170 }, - { 181, 181 }, - { 186, 186 }, - { 192, 214 }, - { 216, 246 }, - { 248, 705 }, - { 710, 721 }, - { 736, 740 }, - { 748, 748 }, - { 750, 750 }, - { 880, 884 }, - { 886, 887 }, - { 890, 893 }, - { 895, 895 }, - { 902, 902 }, - { 904, 906 }, - { 908, 908 }, - { 910, 929 }, - { 931, 1013 }, - { 1015, 1153 }, - { 1162, 1327 }, - { 1329, 1366 }, - { 1369, 1369 }, - { 1376, 1416 }, - { 1488, 1514 }, - { 1519, 1522 }, - { 1568, 1610 }, - { 1646, 1647 }, - { 1649, 1747 }, - { 1749, 1749 }, - { 1765, 1766 }, - { 1774, 1775 }, - { 1786, 1788 }, - { 1791, 1791 }, - { 1808, 1808 }, - { 1810, 1839 }, - { 1869, 1957 }, - { 1969, 1969 }, - { 1994, 2026 }, - { 2036, 2037 }, - { 2042, 2042 }, - { 2048, 2069 }, - { 2074, 2074 }, - { 2084, 2084 }, - { 2088, 2088 }, - { 2112, 2136 }, - { 2144, 2154 }, - { 2160, 2183 }, - { 2185, 2190 }, - { 2208, 2249 }, - { 2308, 2361 }, - { 2365, 2365 }, - { 2384, 2384 }, - { 2392, 2401 }, - { 2417, 2432 }, - { 2437, 2444 }, - { 2447, 2448 }, - { 2451, 2472 }, - { 2474, 2480 }, - { 2482, 2482 }, - { 2486, 2489 }, - { 2493, 2493 }, - { 2510, 2510 }, - { 2524, 2525 }, - { 2527, 2529 }, - { 2544, 2545 }, - { 2556, 2556 }, - { 2565, 2570 }, - { 2575, 2576 }, - { 2579, 2600 }, - { 2602, 2608 }, - { 2610, 2611 }, - { 2613, 2614 }, - { 2616, 2617 }, - { 2649, 2652 }, - { 2654, 2654 }, - { 2674, 2676 }, - { 2693, 2701 }, - { 2703, 2705 }, - { 2707, 2728 }, - { 2730, 2736 }, - { 2738, 2739 }, - { 2741, 2745 }, - { 2749, 2749 }, - { 2768, 2768 }, - { 2784, 2785 }, - { 2809, 2809 }, - { 2821, 2828 }, - { 2831, 2832 }, - { 2835, 2856 }, - { 2858, 2864 }, - { 2866, 2867 }, - { 2869, 2873 }, - { 2877, 2877 }, - { 2908, 2909 }, - { 2911, 2913 }, - { 2929, 2929 }, - { 2947, 2947 }, - { 2949, 2954 }, - { 2958, 2960 }, - { 2962, 2965 }, - { 2969, 2970 }, - { 2972, 2972 }, - { 2974, 2975 }, - { 2979, 2980 }, - { 2984, 2986 }, - { 2990, 3001 }, - { 3024, 3024 }, - { 3077, 3084 }, - { 3086, 3088 }, - { 3090, 3112 }, - { 3114, 3129 }, - { 3133, 3133 }, - { 3160, 3162 }, - { 3165, 3165 }, - { 3168, 3169 }, - { 3200, 3200 }, - { 3205, 3212 }, - { 3214, 3216 }, - { 3218, 3240 }, - { 3242, 3251 }, - { 3253, 3257 }, - { 3261, 3261 }, - { 3293, 3294 }, - { 3296, 3297 }, - { 3313, 3314 }, - { 3332, 3340 }, - { 3342, 3344 }, - { 3346, 3386 }, - { 3389, 3389 }, - { 3406, 3406 }, - { 3412, 3414 }, - { 3423, 3425 }, - { 3450, 3455 }, - { 3461, 3478 }, - { 3482, 3505 }, - { 3507, 3515 }, - { 3517, 3517 }, - { 3520, 3526 }, - { 3585, 3632 }, - { 3634, 3635 }, - { 3648, 3654 }, - { 3713, 3714 }, - { 3716, 3716 }, - { 3718, 3722 }, - { 3724, 3747 }, - { 3749, 3749 }, - { 3751, 3760 }, - { 3762, 3763 }, - { 3773, 3773 }, - { 3776, 3780 }, - { 3782, 3782 }, - { 3804, 3807 }, - { 3840, 3840 }, - { 3904, 3911 }, - { 3913, 3948 }, - { 3976, 3980 }, - { 4096, 4138 }, - { 4159, 4159 }, - { 4176, 4181 }, - { 4186, 4189 }, - { 4193, 4193 }, - { 4197, 4198 }, - { 4206, 4208 }, - { 4213, 4225 }, - { 4238, 4238 }, - { 4256, 4293 }, - { 4295, 4295 }, - { 4301, 4301 }, - { 4304, 4346 }, - { 4348, 4680 }, - { 4682, 4685 }, - { 4688, 4694 }, - { 4696, 4696 }, - { 4698, 4701 }, - { 4704, 4744 }, - { 4746, 4749 }, - { 4752, 4784 }, - { 4786, 4789 }, - { 4792, 4798 }, - { 4800, 4800 }, - { 4802, 4805 }, - { 4808, 4822 }, - { 4824, 4880 }, - { 4882, 4885 }, - { 4888, 4954 }, - { 4992, 5007 }, - { 5024, 5109 }, - { 5112, 5117 }, - { 5121, 5740 }, - { 5743, 5759 }, - { 5761, 5786 }, - { 5792, 5866 }, - { 5873, 5880 }, - { 5888, 5905 }, - { 5919, 5937 }, - { 5952, 5969 }, - { 5984, 5996 }, - { 5998, 6000 }, - { 6016, 6067 }, - { 6103, 6103 }, - { 6108, 6108 }, - { 6176, 6264 }, - { 6272, 6276 }, - { 6279, 6312 }, - { 6314, 6314 }, - { 6320, 6389 }, - { 6400, 6430 }, - { 6480, 6509 }, - { 6512, 6516 }, - { 6528, 6571 }, - { 6576, 6601 }, - { 6656, 6678 }, - { 6688, 6740 }, - { 6823, 6823 }, - { 6917, 6963 }, - { 6981, 6988 }, - { 7043, 7072 }, - { 7086, 7087 }, - { 7098, 7141 }, - { 7168, 7203 }, - { 7245, 7247 }, - { 7258, 7293 }, - { 7296, 7304 }, - { 7312, 7354 }, - { 7357, 7359 }, - { 7401, 7404 }, - { 7406, 7411 }, - { 7413, 7414 }, - { 7418, 7418 }, - { 7424, 7615 }, - { 7680, 7957 }, - { 7960, 7965 }, - { 7968, 8005 }, - { 8008, 8013 }, - { 8016, 8023 }, - { 8025, 8025 }, - { 8027, 8027 }, - { 8029, 8029 }, - { 8031, 8061 }, - { 8064, 8116 }, - { 8118, 8124 }, - { 8126, 8126 }, - { 8130, 8132 }, - { 8134, 8140 }, - { 8144, 8147 }, - { 8150, 8155 }, - { 8160, 8172 }, - { 8178, 8180 }, - { 8182, 8188 }, - { 8305, 8305 }, - { 8319, 8319 }, - { 8336, 8348 }, - { 8450, 8450 }, - { 8455, 8455 }, - { 8458, 8467 }, - { 8469, 8469 }, - { 8473, 8477 }, - { 8484, 8484 }, - { 8486, 8486 }, - { 8488, 8488 }, - { 8490, 8493 }, - { 8495, 8505 }, - { 8508, 8511 }, - { 8517, 8521 }, - { 8526, 8526 }, - { 8579, 8580 }, - { 11264, 11492 }, - { 11499, 11502 }, - { 11506, 11507 }, - { 11520, 11557 }, - { 11559, 11559 }, - { 11565, 11565 }, - { 11568, 11623 }, - { 11631, 11631 }, - { 11648, 11670 }, - { 11680, 11686 }, - { 11688, 11694 }, - { 11696, 11702 }, - { 11704, 11710 }, - { 11712, 11718 }, - { 11720, 11726 }, - { 11728, 11734 }, - { 11736, 11742 }, - { 11823, 11823 }, - { 12293, 12294 }, - { 12337, 12341 }, - { 12347, 12348 }, - { 12353, 12438 }, - { 12445, 12447 }, - { 12449, 12538 }, - { 12540, 12543 }, - { 12549, 12591 }, - { 12593, 12686 }, - { 12704, 12735 }, - { 12784, 12799 }, - { 13312, 19903 }, - { 19968, 42124 }, - { 42192, 42237 }, - { 42240, 42508 }, - { 42512, 42527 }, - { 42538, 42539 }, - { 42560, 42606 }, - { 42623, 42653 }, - { 42656, 42725 }, - { 42775, 42783 }, - { 42786, 42888 }, - { 42891, 42954 }, - { 42960, 42961 }, - { 42963, 42963 }, - { 42965, 42969 }, - { 42994, 43009 }, - { 43011, 43013 }, - { 43015, 43018 }, - { 43020, 43042 }, - { 43072, 43123 }, - { 43138, 43187 }, - { 43250, 43255 }, - { 43259, 43259 }, - { 43261, 43262 }, - { 43274, 43301 }, - { 43312, 43334 }, - { 43360, 43388 }, - { 43396, 43442 }, - { 43471, 43471 }, - { 43488, 43492 }, - { 43494, 43503 }, - { 43514, 43518 }, - { 43520, 43560 }, - { 43584, 43586 }, - { 43588, 43595 }, - { 43616, 43638 }, - { 43642, 43642 }, - { 43646, 43695 }, - { 43697, 43697 }, - { 43701, 43702 }, - { 43705, 43709 }, - { 43712, 43712 }, - { 43714, 43714 }, - { 43739, 43741 }, - { 43744, 43754 }, - { 43762, 43764 }, - { 43777, 43782 }, - { 43785, 43790 }, - { 43793, 43798 }, - { 43808, 43814 }, - { 43816, 43822 }, - { 43824, 43866 }, - { 43868, 43881 }, - { 43888, 44002 }, - { 44032, 55203 }, - { 55216, 55238 }, - { 55243, 55291 }, - { 63744, 64109 }, - { 64112, 64217 }, - { 64256, 64262 }, - { 64275, 64279 }, - { 64285, 64285 }, - { 64287, 64296 }, - { 64298, 64310 }, - { 64312, 64316 }, - { 64318, 64318 }, - { 64320, 64321 }, - { 64323, 64324 }, - { 64326, 64433 }, - { 64467, 64829 }, - { 64848, 64911 }, - { 64914, 64967 }, - { 65008, 65019 }, - { 65136, 65140 }, - { 65142, 65276 }, - { 65313, 65338 }, - { 65345, 65370 }, - { 65382, 65470 }, - { 65474, 65479 }, - { 65482, 65487 }, - { 65490, 65495 }, - { 65498, 65500 }, -}; - -static const URange16 Lm_range16[] = { // Modifier letter - { 688, 705 }, - { 710, 721 }, - { 736, 740 }, - { 748, 748 }, - { 750, 750 }, - { 884, 884 }, - { 890, 890 }, - { 1369, 1369 }, - { 1600, 1600 }, - { 1765, 1766 }, - { 2036, 2037 }, - { 2042, 2042 }, - { 2074, 2074 }, - { 2084, 2084 }, - { 2088, 2088 }, - { 2249, 2249 }, - { 2417, 2417 }, - { 3654, 3654 }, - { 3782, 3782 }, - { 4348, 4348 }, - { 6103, 6103 }, - { 6211, 6211 }, - { 6823, 6823 }, - { 7288, 7293 }, - { 7468, 7530 }, - { 7544, 7544 }, - { 7579, 7615 }, - { 8305, 8305 }, - { 8319, 8319 }, - { 8336, 8348 }, - { 11388, 11389 }, - { 11631, 11631 }, - { 11823, 11823 }, - { 12293, 12293 }, - { 12337, 12341 }, - { 12347, 12347 }, - { 12445, 12446 }, - { 12540, 12542 }, - { 40981, 40981 }, - { 42232, 42237 }, - { 42508, 42508 }, - { 42623, 42623 }, - { 42652, 42653 }, - { 42775, 42783 }, - { 42864, 42864 }, - { 42888, 42888 }, - { 42994, 42996 }, - { 43000, 43001 }, - { 43471, 43471 }, - { 43494, 43494 }, - { 43632, 43632 }, - { 43741, 43741 }, - { 43763, 43764 }, - { 43868, 43871 }, - { 43881, 43881 }, - { 65392, 65392 }, - { 65438, 65439 }, -}; - -static const URange16 Lt_range16[] = { // Title case - { 453, 453 }, - { 456, 456 }, - { 459, 459 }, - { 498, 498 }, - { 8072, 8079 }, - { 8088, 8095 }, - { 8104, 8111 }, - { 8124, 8124 }, - { 8140, 8140 }, - { 8188, 8188 }, -}; - -static const URange16 Nd_range16[] = { // Decimal number - { 48, 57 }, - { 1632, 1641 }, - { 1776, 1785 }, - { 1984, 1993 }, - { 2406, 2415 }, - { 2534, 2543 }, - { 2662, 2671 }, - { 2790, 2799 }, - { 2918, 2927 }, - { 3046, 3055 }, - { 3174, 3183 }, - { 3302, 3311 }, - { 3430, 3439 }, - { 3558, 3567 }, - { 3664, 3673 }, - { 3792, 3801 }, - { 3872, 3881 }, - { 4160, 4169 }, - { 4240, 4249 }, - { 6112, 6121 }, - { 6160, 6169 }, - { 6470, 6479 }, - { 6608, 6617 }, - { 6784, 6793 }, - { 6800, 6809 }, - { 6992, 7001 }, - { 7088, 7097 }, - { 7232, 7241 }, - { 7248, 7257 }, - { 42528, 42537 }, - { 43216, 43225 }, - { 43264, 43273 }, - { 43472, 43481 }, - { 43504, 43513 }, - { 43600, 43609 }, - { 44016, 44025 }, - { 65296, 65305 }, -}; - -static const URange16 Nl_range16[] = { // Number letter - { 5870, 5872 }, - { 8544, 8578 }, - { 8581, 8584 }, - { 12295, 12295 }, - { 12321, 12329 }, - { 12344, 12346 }, - { 42726, 42735 }, -}; - -static const URange16 No_range16[] = { // Other number - { 178, 179 }, - { 185, 185 }, - { 188, 190 }, - { 2548, 2553 }, - { 2930, 2935 }, - { 3056, 3058 }, - { 3192, 3198 }, - { 3416, 3422 }, - { 3440, 3448 }, - { 3882, 3891 }, - { 4969, 4988 }, - { 6128, 6137 }, - { 6618, 6618 }, - { 8304, 8304 }, - { 8308, 8313 }, - { 8320, 8329 }, - { 8528, 8543 }, - { 8585, 8585 }, - { 9312, 9371 }, - { 9450, 9471 }, - { 10102, 10131 }, - { 11517, 11517 }, - { 12690, 12693 }, - { 12832, 12841 }, - { 12872, 12879 }, - { 12881, 12895 }, - { 12928, 12937 }, - { 12977, 12991 }, - { 43056, 43061 }, -}; - -static const URange16 P_range16[] = { // Punctuation - { 33, 35 }, - { 37, 42 }, - { 44, 47 }, - { 58, 59 }, - { 63, 64 }, - { 91, 93 }, - { 95, 95 }, - { 123, 123 }, - { 125, 125 }, - { 161, 161 }, - { 167, 167 }, - { 171, 171 }, - { 182, 183 }, - { 187, 187 }, - { 191, 191 }, - { 894, 894 }, - { 903, 903 }, - { 1370, 1375 }, - { 1417, 1418 }, - { 1470, 1470 }, - { 1472, 1472 }, - { 1475, 1475 }, - { 1478, 1478 }, - { 1523, 1524 }, - { 1545, 1546 }, - { 1548, 1549 }, - { 1563, 1563 }, - { 1565, 1567 }, - { 1642, 1645 }, - { 1748, 1748 }, - { 1792, 1805 }, - { 2039, 2041 }, - { 2096, 2110 }, - { 2142, 2142 }, - { 2404, 2405 }, - { 2416, 2416 }, - { 2557, 2557 }, - { 2678, 2678 }, - { 2800, 2800 }, - { 3191, 3191 }, - { 3204, 3204 }, - { 3572, 3572 }, - { 3663, 3663 }, - { 3674, 3675 }, - { 3844, 3858 }, - { 3860, 3860 }, - { 3898, 3901 }, - { 3973, 3973 }, - { 4048, 4052 }, - { 4057, 4058 }, - { 4170, 4175 }, - { 4347, 4347 }, - { 4960, 4968 }, - { 5120, 5120 }, - { 5742, 5742 }, - { 5787, 5788 }, - { 5867, 5869 }, - { 5941, 5942 }, - { 6100, 6102 }, - { 6104, 6106 }, - { 6144, 6154 }, - { 6468, 6469 }, - { 6686, 6687 }, - { 6816, 6822 }, - { 6824, 6829 }, - { 7002, 7008 }, - { 7037, 7038 }, - { 7164, 7167 }, - { 7227, 7231 }, - { 7294, 7295 }, - { 7360, 7367 }, - { 7379, 7379 }, - { 8208, 8231 }, - { 8240, 8259 }, - { 8261, 8273 }, - { 8275, 8286 }, - { 8317, 8318 }, - { 8333, 8334 }, - { 8968, 8971 }, - { 9001, 9002 }, - { 10088, 10101 }, - { 10181, 10182 }, - { 10214, 10223 }, - { 10627, 10648 }, - { 10712, 10715 }, - { 10748, 10749 }, - { 11513, 11516 }, - { 11518, 11519 }, - { 11632, 11632 }, - { 11776, 11822 }, - { 11824, 11855 }, - { 11858, 11869 }, - { 12289, 12291 }, - { 12296, 12305 }, - { 12308, 12319 }, - { 12336, 12336 }, - { 12349, 12349 }, - { 12448, 12448 }, - { 12539, 12539 }, - { 42238, 42239 }, - { 42509, 42511 }, - { 42611, 42611 }, - { 42622, 42622 }, - { 42738, 42743 }, - { 43124, 43127 }, - { 43214, 43215 }, - { 43256, 43258 }, - { 43260, 43260 }, - { 43310, 43311 }, - { 43359, 43359 }, - { 43457, 43469 }, - { 43486, 43487 }, - { 43612, 43615 }, - { 43742, 43743 }, - { 43760, 43761 }, - { 44011, 44011 }, - { 64830, 64831 }, - { 65040, 65049 }, - { 65072, 65106 }, - { 65108, 65121 }, - { 65123, 65123 }, - { 65128, 65128 }, - { 65130, 65131 }, - { 65281, 65283 }, - { 65285, 65290 }, - { 65292, 65295 }, - { 65306, 65307 }, - { 65311, 65312 }, - { 65339, 65341 }, - { 65343, 65343 }, - { 65371, 65371 }, - { 65373, 65373 }, - { 65375, 65381 }, -}; - -static const URange16 Pc_range16[] = { // Connector punctuation - { 95, 95 }, - { 8255, 8256 }, - { 8276, 8276 }, - { 65075, 65076 }, - { 65101, 65103 }, - { 65343, 65343 }, -}; - -static const URange16 Pd_range16[] = { // Dash punctuation - { 45, 45 }, - { 1418, 1418 }, - { 1470, 1470 }, - { 5120, 5120 }, - { 6150, 6150 }, - { 8208, 8213 }, - { 11799, 11799 }, - { 11802, 11802 }, - { 11834, 11835 }, - { 11840, 11840 }, - { 11869, 11869 }, - { 12316, 12316 }, - { 12336, 12336 }, - { 12448, 12448 }, - { 65073, 65074 }, - { 65112, 65112 }, - { 65123, 65123 }, - { 65293, 65293 }, -}; - -static const URange16 Pe_range16[] = { // End/close punctuation - { 41, 41 }, - { 93, 93 }, - { 125, 125 }, - { 3899, 3899 }, - { 3901, 3901 }, - { 5788, 5788 }, - { 8262, 8262 }, - { 8318, 8318 }, - { 8334, 8334 }, - { 8969, 8969 }, - { 8971, 8971 }, - { 9002, 9002 }, - { 10089, 10089 }, - { 10091, 10091 }, - { 10093, 10093 }, - { 10095, 10095 }, - { 10097, 10097 }, - { 10099, 10099 }, - { 10101, 10101 }, - { 10182, 10182 }, - { 10215, 10215 }, - { 10217, 10217 }, - { 10219, 10219 }, - { 10221, 10221 }, - { 10223, 10223 }, - { 10628, 10628 }, - { 10630, 10630 }, - { 10632, 10632 }, - { 10634, 10634 }, - { 10636, 10636 }, - { 10638, 10638 }, - { 10640, 10640 }, - { 10642, 10642 }, - { 10644, 10644 }, - { 10646, 10646 }, - { 10648, 10648 }, - { 10713, 10713 }, - { 10715, 10715 }, - { 10749, 10749 }, - { 11811, 11811 }, - { 11813, 11813 }, - { 11815, 11815 }, - { 11817, 11817 }, - { 11862, 11862 }, - { 11864, 11864 }, - { 11866, 11866 }, - { 11868, 11868 }, - { 12297, 12297 }, - { 12299, 12299 }, - { 12301, 12301 }, - { 12303, 12303 }, - { 12305, 12305 }, - { 12309, 12309 }, - { 12311, 12311 }, - { 12313, 12313 }, - { 12315, 12315 }, - { 12318, 12319 }, - { 64830, 64830 }, - { 65048, 65048 }, - { 65078, 65078 }, - { 65080, 65080 }, - { 65082, 65082 }, - { 65084, 65084 }, - { 65086, 65086 }, - { 65088, 65088 }, - { 65090, 65090 }, - { 65092, 65092 }, - { 65096, 65096 }, - { 65114, 65114 }, - { 65116, 65116 }, - { 65118, 65118 }, - { 65289, 65289 }, - { 65341, 65341 }, - { 65373, 65373 }, - { 65376, 65376 }, - { 65379, 65379 }, -}; - -static const URange16 Pf_range16[] = { // Final punctuation - { 187, 187 }, - { 8217, 8217 }, - { 8221, 8221 }, - { 8250, 8250 }, - { 11779, 11779 }, - { 11781, 11781 }, - { 11786, 11786 }, - { 11789, 11789 }, - { 11805, 11805 }, - { 11809, 11809 }, -}; - -static const URange16 Pi_range16[] = { // Initial punctuation - { 171, 171 }, - { 8216, 8216 }, - { 8219, 8220 }, - { 8223, 8223 }, - { 8249, 8249 }, - { 11778, 11778 }, - { 11780, 11780 }, - { 11785, 11785 }, - { 11788, 11788 }, - { 11804, 11804 }, - { 11808, 11808 }, -}; - -static const URange16 Ps_range16[] = { // Start/open punctuation - { 40, 40 }, - { 91, 91 }, - { 123, 123 }, - { 3898, 3898 }, - { 3900, 3900 }, - { 5787, 5787 }, - { 8218, 8218 }, - { 8222, 8222 }, - { 8261, 8261 }, - { 8317, 8317 }, - { 8333, 8333 }, - { 8968, 8968 }, - { 8970, 8970 }, - { 9001, 9001 }, - { 10088, 10088 }, - { 10090, 10090 }, - { 10092, 10092 }, - { 10094, 10094 }, - { 10096, 10096 }, - { 10098, 10098 }, - { 10100, 10100 }, - { 10181, 10181 }, - { 10214, 10214 }, - { 10216, 10216 }, - { 10218, 10218 }, - { 10220, 10220 }, - { 10222, 10222 }, - { 10627, 10627 }, - { 10629, 10629 }, - { 10631, 10631 }, - { 10633, 10633 }, - { 10635, 10635 }, - { 10637, 10637 }, - { 10639, 10639 }, - { 10641, 10641 }, - { 10643, 10643 }, - { 10645, 10645 }, - { 10647, 10647 }, - { 10712, 10712 }, - { 10714, 10714 }, - { 10748, 10748 }, - { 11810, 11810 }, - { 11812, 11812 }, - { 11814, 11814 }, - { 11816, 11816 }, - { 11842, 11842 }, - { 11861, 11861 }, - { 11863, 11863 }, - { 11865, 11865 }, - { 11867, 11867 }, - { 12296, 12296 }, - { 12298, 12298 }, - { 12300, 12300 }, - { 12302, 12302 }, - { 12304, 12304 }, - { 12308, 12308 }, - { 12310, 12310 }, - { 12312, 12312 }, - { 12314, 12314 }, - { 12317, 12317 }, - { 64831, 64831 }, - { 65047, 65047 }, - { 65077, 65077 }, - { 65079, 65079 }, - { 65081, 65081 }, - { 65083, 65083 }, - { 65085, 65085 }, - { 65087, 65087 }, - { 65089, 65089 }, - { 65091, 65091 }, - { 65095, 65095 }, - { 65113, 65113 }, - { 65115, 65115 }, - { 65117, 65117 }, - { 65288, 65288 }, - { 65339, 65339 }, - { 65371, 65371 }, - { 65375, 65375 }, - { 65378, 65378 }, -}; - -static const URange16 Sc_range16[] = { // Currency symbol - { 36, 36 }, - { 162, 165 }, - { 1423, 1423 }, - { 1547, 1547 }, - { 2046, 2047 }, - { 2546, 2547 }, - { 2555, 2555 }, - { 2801, 2801 }, - { 3065, 3065 }, - { 3647, 3647 }, - { 6107, 6107 }, - { 8352, 8384 }, - { 43064, 43064 }, - { 65020, 65020 }, - { 65129, 65129 }, - { 65284, 65284 }, - { 65504, 65505 }, - { 65509, 65510 }, -}; - -static const URange16 Sk_range16[] = { // Modifier symbol - { 94, 94 }, - { 96, 96 }, - { 168, 168 }, - { 175, 175 }, - { 180, 180 }, - { 184, 184 }, - { 706, 709 }, - { 722, 735 }, - { 741, 747 }, - { 749, 749 }, - { 751, 767 }, - { 885, 885 }, - { 900, 901 }, - { 2184, 2184 }, - { 8125, 8125 }, - { 8127, 8129 }, - { 8141, 8143 }, - { 8157, 8159 }, - { 8173, 8175 }, - { 8189, 8190 }, - { 12443, 12444 }, - { 42752, 42774 }, - { 42784, 42785 }, - { 42889, 42890 }, - { 43867, 43867 }, - { 43882, 43883 }, - { 64434, 64450 }, - { 65342, 65342 }, - { 65344, 65344 }, - { 65507, 65507 }, -}; - -static const URange16 Sm_range16[] = { // Math symbol - { 43, 43 }, - { 60, 62 }, - { 124, 124 }, - { 126, 126 }, - { 172, 172 }, - { 177, 177 }, - { 215, 215 }, - { 247, 247 }, - { 1014, 1014 }, - { 1542, 1544 }, - { 8260, 8260 }, - { 8274, 8274 }, - { 8314, 8316 }, - { 8330, 8332 }, - { 8472, 8472 }, - { 8512, 8516 }, - { 8523, 8523 }, - { 8592, 8596 }, - { 8602, 8603 }, - { 8608, 8608 }, - { 8611, 8611 }, - { 8614, 8614 }, - { 8622, 8622 }, - { 8654, 8655 }, - { 8658, 8658 }, - { 8660, 8660 }, - { 8692, 8959 }, - { 8992, 8993 }, - { 9084, 9084 }, - { 9115, 9139 }, - { 9180, 9185 }, - { 9655, 9655 }, - { 9665, 9665 }, - { 9720, 9727 }, - { 9839, 9839 }, - { 10176, 10180 }, - { 10183, 10213 }, - { 10224, 10239 }, - { 10496, 10626 }, - { 10649, 10711 }, - { 10716, 10747 }, - { 10750, 11007 }, - { 11056, 11076 }, - { 11079, 11084 }, - { 64297, 64297 }, - { 65122, 65122 }, - { 65124, 65126 }, - { 65291, 65291 }, - { 65308, 65310 }, - { 65372, 65372 }, - { 65374, 65374 }, - { 65506, 65506 }, - { 65513, 65516 }, -}; - -static const URange16 Zl_range16[] = { // Line separator - { 8232, 8232 }, -}; - -static const URange16 Zp_range16[] = { // Paragraph separator - { 8233, 8233 }, -}; - -static const URange16 Zs_range16[] = { // Space separator - { 32, 32 }, - { 160, 160 }, - { 5760, 5760 }, - { 8192, 8202 }, - { 8239, 8239 }, - { 8287, 8287 }, - { 12288, 12288 }, -}; - -static const URange16 Arabic_range16[] = { - { 1536, 1540 }, - { 1542, 1547 }, - { 1549, 1562 }, - { 1564, 1566 }, - { 1568, 1599 }, - { 1601, 1610 }, - { 1622, 1647 }, - { 1649, 1756 }, - { 1758, 1791 }, - { 1872, 1919 }, - { 2160, 2190 }, - { 2192, 2193 }, - { 2200, 2273 }, - { 2275, 2303 }, - { 64336, 64450 }, - { 64467, 64829 }, - { 64832, 64911 }, - { 64914, 64967 }, - { 64975, 64975 }, - { 65008, 65023 }, - { 65136, 65140 }, - { 65142, 65276 }, -}; - -static const URange16 Bengali_range16[] = { - { 2432, 2435 }, - { 2437, 2444 }, - { 2447, 2448 }, - { 2451, 2472 }, - { 2474, 2480 }, - { 2482, 2482 }, - { 2486, 2489 }, - { 2492, 2500 }, - { 2503, 2504 }, - { 2507, 2510 }, - { 2519, 2519 }, - { 2524, 2525 }, - { 2527, 2531 }, - { 2534, 2558 }, -}; - -static const URange16 Cyrillic_range16[] = { - { 1024, 1156 }, - { 1159, 1327 }, - { 7296, 7304 }, - { 7467, 7467 }, - { 7544, 7544 }, - { 11744, 11775 }, - { 42560, 42655 }, - { 65070, 65071 }, -}; - -static const URange16 Devanagari_range16[] = { - { 2304, 2384 }, - { 2389, 2403 }, - { 2406, 2431 }, - { 43232, 43263 }, -}; - -static const URange16 Georgian_range16[] = { - { 4256, 4293 }, - { 4295, 4295 }, - { 4301, 4301 }, - { 4304, 4346 }, - { 4348, 4351 }, - { 7312, 7354 }, - { 7357, 7359 }, - { 11520, 11557 }, - { 11559, 11559 }, - { 11565, 11565 }, -}; - -static const URange16 Greek_range16[] = { - { 880, 883 }, - { 885, 887 }, - { 890, 893 }, - { 895, 895 }, - { 900, 900 }, - { 902, 902 }, - { 904, 906 }, - { 908, 908 }, - { 910, 929 }, - { 931, 993 }, - { 1008, 1023 }, - { 7462, 7466 }, - { 7517, 7521 }, - { 7526, 7530 }, - { 7615, 7615 }, - { 7936, 7957 }, - { 7960, 7965 }, - { 7968, 8005 }, - { 8008, 8013 }, - { 8016, 8023 }, - { 8025, 8025 }, - { 8027, 8027 }, - { 8029, 8029 }, - { 8031, 8061 }, - { 8064, 8116 }, - { 8118, 8132 }, - { 8134, 8147 }, - { 8150, 8155 }, - { 8157, 8175 }, - { 8178, 8180 }, - { 8182, 8190 }, - { 8486, 8486 }, - { 43877, 43877 }, -}; - -static const URange16 Han_range16[] = { - { 11904, 11929 }, - { 11931, 12019 }, - { 12032, 12245 }, - { 12293, 12293 }, - { 12295, 12295 }, - { 12321, 12329 }, - { 12344, 12347 }, - { 13312, 19903 }, - { 19968, 40959 }, - { 63744, 64109 }, - { 64112, 64217 }, -}; - -static const URange16 Hiragana_range16[] = { - { 12353, 12438 }, - { 12445, 12447 }, -}; - -static const URange16 Katakana_range16[] = { - { 12449, 12538 }, - { 12541, 12543 }, - { 12784, 12799 }, - { 13008, 13054 }, - { 13056, 13143 }, - { 65382, 65391 }, - { 65393, 65437 }, -}; - -static const URange16 Latin_range16[] = { - { 65, 90 }, - { 97, 122 }, - { 170, 170 }, - { 186, 186 }, - { 192, 214 }, - { 216, 246 }, - { 248, 696 }, - { 736, 740 }, - { 7424, 7461 }, - { 7468, 7516 }, - { 7522, 7525 }, - { 7531, 7543 }, - { 7545, 7614 }, - { 7680, 7935 }, - { 8305, 8305 }, - { 8319, 8319 }, - { 8336, 8348 }, - { 8490, 8491 }, - { 8498, 8498 }, - { 8526, 8526 }, - { 8544, 8584 }, - { 11360, 11391 }, - { 42786, 42887 }, - { 42891, 42954 }, - { 42960, 42961 }, - { 42963, 42963 }, - { 42965, 42969 }, - { 42994, 43007 }, - { 43824, 43866 }, - { 43868, 43876 }, - { 43878, 43881 }, - { 64256, 64262 }, - { 65313, 65338 }, - { 65345, 65370 }, -}; - -static const URange16 Thai_range16[] = { - { 3585, 3642 }, - { 3648, 3675 }, -}; - -#ifdef __cplusplus - #define _e_arg(k, v) v -#else - #define _e_arg(k, v) [k] = v -#endif -#define UNI_ENTRY(Code) { Code##_range16, sizeof(Code##_range16)/sizeof(URange16) } - -typedef struct { - const URange16 *r16; - int nr16; -} UGroup; - -static const UGroup _utf8_unicode_groups[U8G_SIZE] = { - _e_arg(U8G_Cc, UNI_ENTRY(Cc)), - _e_arg(U8G_L, UNI_ENTRY(L)), - _e_arg(U8G_Lm, UNI_ENTRY(Lm)), - _e_arg(U8G_Lt, UNI_ENTRY(Lt)), - _e_arg(U8G_Nd, UNI_ENTRY(Nd)), - _e_arg(U8G_Nl, UNI_ENTRY(Nl)), - _e_arg(U8G_No, UNI_ENTRY(No)), - _e_arg(U8G_P, UNI_ENTRY(P)), - _e_arg(U8G_Pc, UNI_ENTRY(Pc)), - _e_arg(U8G_Pd, UNI_ENTRY(Pd)), - _e_arg(U8G_Pe, UNI_ENTRY(Pe)), - _e_arg(U8G_Pf, UNI_ENTRY(Pf)), - _e_arg(U8G_Pi, UNI_ENTRY(Pi)), - _e_arg(U8G_Ps, UNI_ENTRY(Ps)), - _e_arg(U8G_Sc, UNI_ENTRY(Sc)), - _e_arg(U8G_Sk, UNI_ENTRY(Sk)), - _e_arg(U8G_Sm, UNI_ENTRY(Sm)), - _e_arg(U8G_Zl, UNI_ENTRY(Zl)), - _e_arg(U8G_Zp, UNI_ENTRY(Zp)), - _e_arg(U8G_Zs, UNI_ENTRY(Zs)), - _e_arg(U8G_Arabic, UNI_ENTRY(Arabic)), - _e_arg(U8G_Bengali, UNI_ENTRY(Bengali)), - _e_arg(U8G_Cyrillic, UNI_ENTRY(Cyrillic)), - _e_arg(U8G_Devanagari, UNI_ENTRY(Devanagari)), - _e_arg(U8G_Georgian, UNI_ENTRY(Georgian)), - _e_arg(U8G_Greek, UNI_ENTRY(Greek)), - _e_arg(U8G_Han, UNI_ENTRY(Han)), - _e_arg(U8G_Hiragana, UNI_ENTRY(Hiragana)), - _e_arg(U8G_Katakana, UNI_ENTRY(Katakana)), - _e_arg(U8G_Latin, UNI_ENTRY(Latin)), - _e_arg(U8G_Thai, UNI_ENTRY(Thai)), -}; - -bool utf8_isgroup(int group, uint32_t c) { - #define _at_group(idx) &_utf8_unicode_groups[group].r16[idx].hi - int i, n = _utf8_unicode_groups[group].nr16; - c_lowerbound(uint32_t, c, _at_group, c_default_less, n, &i); - return (i < n && c >= _utf8_unicode_groups[group].r16[i].lo); -} - -#endif // STC_UCD_PRV_C_INCLUDED diff --git a/src/finchlite/codegen/stc/include/stc/priv/utf8_prv.c b/src/finchlite/codegen/stc/include/stc/priv/utf8_prv.c deleted file mode 100644 index c8f344e6..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/utf8_prv.c +++ /dev/null @@ -1,162 +0,0 @@ -/* 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_UTF8_PRV_C_INCLUDED -#define STC_UTF8_PRV_C_INCLUDED - -#include "utf8_tab.c" - -const uint8_t utf8_dtab[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, - 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, - 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, - 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, - 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, - 12,36,12,12,12,12,12,12,12,12,12,12, -}; - -int utf8_encode(char *out, uint32_t c) { - if (c < 0x80U) { - out[0] = (char) c; - return 1; - } else if (c < 0x0800U) { - out[0] = (char) ((c>>6 & 0x1F) | 0xC0); - out[1] = (char) ((c & 0x3F) | 0x80); - return 2; - } else if (c < 0x010000U) { - if ((c < 0xD800U) | (c >= 0xE000U)) { - out[0] = (char) ((c>>12 & 0x0F) | 0xE0); - out[1] = (char) ((c>>6 & 0x3F) | 0x80); - out[2] = (char) ((c & 0x3F) | 0x80); - return 3; - } - } else if (c < 0x110000U) { - out[0] = (char) ((c>>18 & 0x07) | 0xF0); - out[1] = (char) ((c>>12 & 0x3F) | 0x80); - out[2] = (char) ((c>>6 & 0x3F) | 0x80); - out[3] = (char) ((c & 0x3F) | 0x80); - return 4; - } - return 0; -} - -uint32_t utf8_peek_at(const char* s, isize offset) { - return utf8_peek(utf8_offset(s, offset)); -} - -bool utf8_valid(const char* s) { - utf8_decode_t d = {.state=0}; - while ((utf8_decode(&d, (uint8_t)*s) != utf8_REJECT) & (*s != '\0')) - ++s; - return d.state == utf8_ACCEPT; -} - -bool utf8_valid_n(const char* s, isize nbytes) { - utf8_decode_t d = {.state=0}; - for (; nbytes-- != 0; ++s) - if ((utf8_decode(&d, (uint8_t)*s) == utf8_REJECT) | (*s == '\0')) - break; - return d.state == utf8_ACCEPT; -} - -uint32_t utf8_casefold(uint32_t c) { - #define _at_fold(idx) &casemappings[idx].c2 - int i; - c_lowerbound(uint32_t, c, _at_fold, c_default_less, casefold_len, &i); - if (i < casefold_len && casemappings[i].c1 <= c) { - const struct CaseMapping entry = casemappings[i]; - int d = entry.m2 - entry.c2; - if (d == 1) return c + ((entry.c2 & 1U) == (c & 1U)); - return (uint32_t)((int)c + d); - } - return c; -} - -uint32_t utf8_tolower(uint32_t c) { - #define _at_upper(idx) &casemappings[upcase_ind[idx]].c2 - int i, n = c_countof(upcase_ind); - c_lowerbound(uint32_t, c, _at_upper, c_default_less, n, &i); - if (i < n) { - const struct CaseMapping entry = casemappings[upcase_ind[i]]; - if (entry.c1 <= c) { - int d = entry.m2 - entry.c2; - if (d == 1) return c + ((entry.c2 & 1U) == (c & 1U)); - return (uint32_t)((int)c + d); - } - } - return c; -} - -uint32_t utf8_toupper(uint32_t c) { - #define _at_lower(idx) &casemappings[lowcase_ind[idx]].m2 - int i, n = c_countof(lowcase_ind); - c_lowerbound(uint32_t, c, _at_lower, c_default_less, n, &i); - if (i < n) { - const struct CaseMapping entry = casemappings[lowcase_ind[i]]; - int d = entry.m2 - entry.c2; - if (entry.c1 + (uint32_t)d <= c) { - if (d == 1) return c - ((entry.m2 & 1U) == (c & 1U)); - return (uint32_t)((int)c - d); - } - } - return c; -} - -int utf8_decode_codepoint(utf8_decode_t* d, const char* s, const char* end) { // s < end - const char* start = s; - do switch (utf8_decode(d, (uint8_t)*s++)) { - case utf8_ACCEPT: return (int)(s - start); - case utf8_REJECT: goto recover; - } while (s != end); - - recover: // non-complete utf8 is also treated as utf8_REJECT - d->state = utf8_ACCEPT; - d->codep = 0xFFFD; - //return 1; - int n = (int)(s - start); - return n > 2 ? n - 1 : 1; -} - -int utf8_icompare(const csview s1, const csview s2) { - utf8_decode_t d1 = {.state=0}, d2 = {.state=0}; - const char *e1 = s1.buf + s1.size, *e2 = s2.buf + s2.size; - isize j1 = 0, j2 = 0; - while ((j1 < s1.size) & (j2 < s2.size)) { - if (s2.buf[j2] == '\0') return s1.buf[j1]; - - j1 += utf8_decode_codepoint(&d1, s1.buf + j1, e1); - j2 += utf8_decode_codepoint(&d2, s2.buf + j2, e2); - - int32_t c = (int32_t)utf8_casefold(d1.codep) - (int32_t)utf8_casefold(d2.codep); - if (c != 0) return (int)c; - } - return (int)(s1.size - s2.size); -} - -#endif // STC_UTF8_PRV_C_INCLUDED diff --git a/src/finchlite/codegen/stc/include/stc/priv/utf8_prv.h b/src/finchlite/codegen/stc/include/stc/priv/utf8_prv.h deleted file mode 100644 index 1a5e6154..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/utf8_prv.h +++ /dev/null @@ -1,192 +0,0 @@ -/* 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. - */ -// IWYU pragma: private, include "stc/utf8.h" -#ifndef STC_UTF8_PRV_H_INCLUDED -#define STC_UTF8_PRV_H_INCLUDED - -#include - -// The following functions assume valid utf8 strings: - -/* number of bytes in the utf8 codepoint from s */ -STC_INLINE int utf8_chr_size(const char *s) { - unsigned b = (uint8_t)*s; - if (b < 0x80) return 1; - /*if (b < 0xC2) return 0;*/ - if (b < 0xE0) return 2; - if (b < 0xF0) return 3; - /*if (b < 0xF5)*/ return 4; - /*return 0;*/ -} - -/* number of codepoints in the utf8 string s */ -STC_INLINE isize utf8_count(const char *s) { - isize size = 0; - while (*s) - size += (*++s & 0xC0) != 0x80; - return size; -} - -STC_INLINE isize utf8_count_n(const char *s, isize nbytes) { - isize size = 0; - while ((nbytes-- != 0) & (*s != 0)) { - size += (*++s & 0xC0) != 0x80; - } - return size; -} - -STC_INLINE const char* utf8_at(const char *s, isize u8pos) { - while ((u8pos > 0) & (*s != 0)) - u8pos -= (*++s & 0xC0) != 0x80; - return s; -} - -STC_INLINE const char* utf8_offset(const char* s, isize u8pos) { - int inc = 1; - if (u8pos < 0) u8pos = -u8pos, inc = -1; - while (u8pos && *s) - u8pos -= (*(s += inc) & 0xC0) != 0x80; - return s; -} - -STC_INLINE isize utf8_to_index(const char* s, isize u8pos) - { return utf8_at(s, u8pos) - s; } - -STC_INLINE csview utf8_subview(const char *s, isize u8pos, isize u8len) { - csview span; - span.buf = utf8_at(s, u8pos); - span.size = utf8_to_index(span.buf, u8len); - return span; -} - -// ------------------------------------------------------ -// Functions below must be linked with utf8_prv.c content -// To call them, either define i_import before including -// one of cstr, csview, zsview, or link with src/libstc.a - -/* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */ -typedef struct { uint32_t state, codep; } utf8_decode_t; -extern const uint8_t utf8_dtab[]; /* utf8code.c */ -#define utf8_ACCEPT 0 -#define utf8_REJECT 12 - -extern bool utf8_valid(const char* s); -extern bool utf8_valid_n(const char* s, isize nbytes); -extern int utf8_encode(char *out, uint32_t c); -extern int utf8_decode_codepoint(utf8_decode_t* d, const char* s, const char* end); -extern int utf8_icompare(const csview s1, const csview s2); -extern uint32_t utf8_peek_at(const char* s, isize u8offset); -extern uint32_t utf8_casefold(uint32_t c); -extern uint32_t utf8_tolower(uint32_t c); -extern uint32_t utf8_toupper(uint32_t c); - -STC_INLINE bool utf8_isupper(uint32_t c) - { return c < 128 ? (c >= 'A') & (c <= 'Z') : utf8_tolower(c) != c; } - -STC_INLINE bool utf8_islower(uint32_t c) - { return c < 128 ? (c >= 'a') & (c <= 'z') : utf8_toupper(c) != c; } - -STC_INLINE uint32_t utf8_decode(utf8_decode_t* d, const uint32_t byte) { - const uint32_t type = utf8_dtab[byte]; - d->codep = d->state ? (byte & 0x3fu) | (d->codep << 6) - : (0xffU >> type) & byte; - return d->state = utf8_dtab[256 + d->state + type]; -} - -STC_INLINE uint32_t utf8_peek(const char* s) { - utf8_decode_t d = {.state=0}; - do { - utf8_decode(&d, (uint8_t)*s++); - } while (d.state > utf8_REJECT); - return d.state == utf8_ACCEPT ? d.codep : 0xFFFD; -} - -/* case-insensitive utf8 string comparison */ -STC_INLINE int utf8_icmp(const char* s1, const char* s2) { - return utf8_icompare(c_sv(s1, INTPTR_MAX), c_sv(s2, INTPTR_MAX)); -} - -// ------------------------------------------------------ -// Functions below must be linked with ucd_prv.c content - -enum utf8_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 utf8_isgroup(int group, uint32_t c); - -STC_INLINE bool utf8_isdigit(uint32_t c) - { return c < 128 ? (c >= '0') & (c <= '9') : utf8_isgroup(U8G_Nd, c); } - -STC_INLINE bool utf8_isalpha(uint32_t c) - { return (c < 128 ? isalpha((int)c) != 0 : utf8_isgroup(U8G_L, c)); } - -STC_INLINE bool utf8_iscased(uint32_t c) { - if (c < 128) return isalpha((int)c) != 0; - return utf8_toupper(c) != c || utf8_tolower(c) != c || utf8_isgroup(U8G_Lt, c); -} - -STC_INLINE bool utf8_isalnum(uint32_t c) { - if (c < 128) return isalnum((int)c) != 0; - return utf8_isgroup(U8G_L, c) || utf8_isgroup(U8G_Nd, c); -} - -STC_INLINE bool utf8_isword(uint32_t c) { - if (c < 128) return (isalnum((int)c) != 0) | (c == '_'); - return utf8_isgroup(U8G_L, c) || utf8_isgroup(U8G_Nd, c) || utf8_isgroup(U8G_Pc, c); -} - -STC_INLINE bool utf8_isblank(uint32_t c) { - if (c < 128) return (c == ' ') | (c == '\t'); - return utf8_isgroup(U8G_Zs, c); -} - -STC_INLINE bool utf8_isspace(uint32_t c) { - if (c < 128) return isspace((int)c) != 0; - return ((c == 8232) | (c == 8233)) || utf8_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 diff --git a/src/finchlite/codegen/stc/include/stc/priv/utf8_tab.c b/src/finchlite/codegen/stc/include/stc/priv/utf8_tab.c deleted file mode 100644 index f8542543..00000000 --- a/src/finchlite/codegen/stc/include/stc/priv/utf8_tab.c +++ /dev/null @@ -1,250 +0,0 @@ - -struct CaseMapping { uint16_t c1, c2, m2; }; - -static struct CaseMapping casemappings[] = { - {0x0041, 0x005A, 0x007A}, // A a (26) LATIN CAPITAL LETTER A - {0x00B5, 0x00B5, 0x03BC}, // µ μ ( 1) MICRO SIGN - {0x00C0, 0x00D6, 0x00F6}, // À à (23) LATIN CAPITAL LETTER A WITH GRAVE - {0x00D8, 0x00DE, 0x00FE}, // Ø ø ( 7) LATIN CAPITAL LETTER O WITH STROKE - {0x0100, 0x012E, 0x012F}, // Ā ā (24) LATIN CAPITAL LETTER A WITH MACRON - {0x0132, 0x0136, 0x0137}, // IJ ij ( 3) LATIN CAPITAL LIGATURE IJ - {0x0139, 0x0147, 0x0148}, // Ĺ ĺ ( 8) LATIN CAPITAL LETTER L WITH ACUTE - {0x014A, 0x0176, 0x0177}, // Ŋ ŋ (23) LATIN CAPITAL LETTER ENG - {0x0178, 0x0178, 0x00FF}, // Ÿ ÿ ( 1) LATIN CAPITAL LETTER Y WITH DIAERESIS - {0x0179, 0x017D, 0x017E}, // Ź ź ( 3) LATIN CAPITAL LETTER Z WITH ACUTE - {0x017F, 0x017F, 0x0073}, // ſ s ( 1) LATIN SMALL LETTER LONG S - {0x0181, 0x0181, 0x0253}, // Ɓ ɓ ( 1) LATIN CAPITAL LETTER B WITH HOOK - {0x0182, 0x0184, 0x0185}, // Ƃ ƃ ( 2) LATIN CAPITAL LETTER B WITH TOPBAR - {0x0186, 0x0186, 0x0254}, // Ɔ ɔ ( 1) LATIN CAPITAL LETTER OPEN O - {0x0187, 0x0187, 0x0188}, // Ƈ ƈ ( 1) LATIN CAPITAL LETTER C WITH HOOK - {0x0189, 0x018A, 0x0257}, // Ɖ ɖ ( 2) LATIN CAPITAL LETTER AFRICAN D - {0x018B, 0x018B, 0x018C}, // Ƌ ƌ ( 1) LATIN CAPITAL LETTER D WITH TOPBAR - {0x018E, 0x018E, 0x01DD}, // Ǝ ǝ ( 1) LATIN CAPITAL LETTER REVERSED E - {0x018F, 0x018F, 0x0259}, // Ə ə ( 1) LATIN CAPITAL LETTER SCHWA - {0x0190, 0x0190, 0x025B}, // Ɛ ɛ ( 1) LATIN CAPITAL LETTER OPEN E - {0x0191, 0x0191, 0x0192}, // Ƒ ƒ ( 1) LATIN CAPITAL LETTER F WITH HOOK - {0x0193, 0x0193, 0x0260}, // Ɠ ɠ ( 1) LATIN CAPITAL LETTER G WITH HOOK - {0x0194, 0x0194, 0x0263}, // Ɣ ɣ ( 1) LATIN CAPITAL LETTER GAMMA - {0x0196, 0x0196, 0x0269}, // Ɩ ɩ ( 1) LATIN CAPITAL LETTER IOTA - {0x0197, 0x0197, 0x0268}, // Ɨ ɨ ( 1) LATIN CAPITAL LETTER I WITH STROKE - {0x0198, 0x0198, 0x0199}, // Ƙ ƙ ( 1) LATIN CAPITAL LETTER K WITH HOOK - {0x019C, 0x019C, 0x026F}, // Ɯ ɯ ( 1) LATIN CAPITAL LETTER TURNED M - {0x019D, 0x019D, 0x0272}, // Ɲ ɲ ( 1) LATIN CAPITAL LETTER N WITH LEFT HOOK - {0x019F, 0x019F, 0x0275}, // Ɵ ɵ ( 1) LATIN CAPITAL LETTER O WITH MIDDLE TILDE - {0x01A0, 0x01A4, 0x01A5}, // Ơ ơ ( 3) LATIN CAPITAL LETTER O WITH HORN - {0x01A6, 0x01A6, 0x0280}, // Ʀ ʀ ( 1) LATIN LETTER YR - {0x01A7, 0x01A7, 0x01A8}, // Ƨ ƨ ( 1) LATIN CAPITAL LETTER TONE TWO - {0x01A9, 0x01A9, 0x0283}, // Ʃ ʃ ( 1) LATIN CAPITAL LETTER ESH - {0x01AC, 0x01AC, 0x01AD}, // Ƭ ƭ ( 1) LATIN CAPITAL LETTER T WITH HOOK - {0x01AE, 0x01AE, 0x0288}, // Ʈ ʈ ( 1) LATIN CAPITAL LETTER T WITH RETROFLEX HOOK - {0x01AF, 0x01AF, 0x01B0}, // Ư ư ( 1) LATIN CAPITAL LETTER U WITH HORN - {0x01B1, 0x01B2, 0x028B}, // Ʊ ʊ ( 2) LATIN CAPITAL LETTER UPSILON - {0x01B3, 0x01B5, 0x01B6}, // Ƴ ƴ ( 2) LATIN CAPITAL LETTER Y WITH HOOK - {0x01B7, 0x01B7, 0x0292}, // Ʒ ʒ ( 1) LATIN CAPITAL LETTER EZH - {0x01B8, 0x01B8, 0x01B9}, // Ƹ ƹ ( 1) LATIN CAPITAL LETTER EZH REVERSED - {0x01BC, 0x01BC, 0x01BD}, // Ƽ ƽ ( 1) LATIN CAPITAL LETTER TONE FIVE - {0x01C4, 0x01C4, 0x01C6}, // DŽ dž ( 1) LATIN CAPITAL LETTER DZ WITH CARON - {0x01C5, 0x01C5, 0x01C6}, // Dž dž ( 1) LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON - {0x01C7, 0x01C7, 0x01C9}, // LJ lj ( 1) LATIN CAPITAL LETTER LJ - {0x01C8, 0x01C8, 0x01C9}, // Lj lj ( 1) LATIN CAPITAL LETTER L WITH SMALL LETTER J - {0x01CA, 0x01CA, 0x01CC}, // NJ nj ( 1) LATIN CAPITAL LETTER NJ - {0x01CB, 0x01DB, 0x01DC}, // Nj nj ( 9) LATIN CAPITAL LETTER N WITH SMALL LETTER J - {0x01DE, 0x01EE, 0x01EF}, // Ǟ ǟ ( 9) LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON - {0x01F1, 0x01F1, 0x01F3}, // DZ dz ( 1) LATIN CAPITAL LETTER DZ - {0x01F2, 0x01F4, 0x01F5}, // Dz dz ( 2) LATIN CAPITAL LETTER D WITH SMALL LETTER Z - {0x01F6, 0x01F6, 0x0195}, // Ƕ ƕ ( 1) LATIN CAPITAL LETTER HWAIR - {0x01F7, 0x01F7, 0x01BF}, // Ƿ ƿ ( 1) LATIN CAPITAL LETTER WYNN - {0x01F8, 0x021E, 0x021F}, // Ǹ ǹ (20) LATIN CAPITAL LETTER N WITH GRAVE - {0x0220, 0x0220, 0x019E}, // Ƞ ƞ ( 1) LATIN CAPITAL LETTER N WITH LONG RIGHT LEG - {0x0222, 0x0232, 0x0233}, // Ȣ ȣ ( 9) LATIN CAPITAL LETTER OU - {0x023A, 0x023A, 0x2C65}, // Ⱥ ⱥ ( 1) LATIN CAPITAL LETTER A WITH STROKE - {0x023B, 0x023B, 0x023C}, // Ȼ ȼ ( 1) LATIN CAPITAL LETTER C WITH STROKE - {0x023D, 0x023D, 0x019A}, // Ƚ ƚ ( 1) LATIN CAPITAL LETTER L WITH BAR - {0x023E, 0x023E, 0x2C66}, // Ⱦ ⱦ ( 1) LATIN CAPITAL LETTER T WITH DIAGONAL STROKE - {0x0241, 0x0241, 0x0242}, // Ɂ ɂ ( 1) LATIN CAPITAL LETTER GLOTTAL STOP - {0x0243, 0x0243, 0x0180}, // Ƀ ƀ ( 1) LATIN CAPITAL LETTER B WITH STROKE - {0x0244, 0x0244, 0x0289}, // Ʉ ʉ ( 1) LATIN CAPITAL LETTER U BAR - {0x0245, 0x0245, 0x028C}, // Ʌ ʌ ( 1) LATIN CAPITAL LETTER TURNED V - {0x0246, 0x024E, 0x024F}, // Ɇ ɇ ( 5) LATIN CAPITAL LETTER E WITH STROKE - {0x0345, 0x0345, 0x03B9}, // ͅ ι ( 1) COMBINING GREEK YPOGEGRAMMENI - {0x0370, 0x0372, 0x0373}, // Ͱ ͱ ( 2) GREEK CAPITAL LETTER HETA - {0x0376, 0x0376, 0x0377}, // Ͷ ͷ ( 1) GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA - {0x037F, 0x037F, 0x03F3}, // Ϳ ϳ ( 1) GREEK CAPITAL LETTER YOT - {0x0386, 0x0386, 0x03AC}, // Ά ά ( 1) GREEK CAPITAL LETTER ALPHA WITH TONOS - {0x0388, 0x038A, 0x03AF}, // Έ έ ( 3) GREEK CAPITAL LETTER EPSILON WITH TONOS - {0x038C, 0x038C, 0x03CC}, // Ό ό ( 1) GREEK CAPITAL LETTER OMICRON WITH TONOS - {0x038E, 0x038F, 0x03CE}, // Ύ ύ ( 2) GREEK CAPITAL LETTER UPSILON WITH TONOS - {0x0391, 0x03A1, 0x03C1}, // Α α (17) GREEK CAPITAL LETTER ALPHA - {0x03A3, 0x03AB, 0x03CB}, // Σ σ ( 9) GREEK CAPITAL LETTER SIGMA - {0x03C2, 0x03C2, 0x03C3}, // ς σ ( 1) GREEK SMALL LETTER FINAL SIGMA - {0x03CF, 0x03CF, 0x03D7}, // Ϗ ϗ ( 1) GREEK CAPITAL KAI SYMBOL - {0x03D0, 0x03D0, 0x03B2}, // ϐ β ( 1) GREEK BETA SYMBOL - {0x03D1, 0x03D1, 0x03B8}, // ϑ θ ( 1) GREEK THETA SYMBOL - {0x03D5, 0x03D5, 0x03C6}, // ϕ φ ( 1) GREEK PHI SYMBOL - {0x03D6, 0x03D6, 0x03C0}, // ϖ π ( 1) GREEK PI SYMBOL - {0x03D8, 0x03EE, 0x03EF}, // Ϙ ϙ (12) GREEK LETTER ARCHAIC KOPPA - {0x03F0, 0x03F0, 0x03BA}, // ϰ κ ( 1) GREEK KAPPA SYMBOL - {0x03F1, 0x03F1, 0x03C1}, // ϱ ρ ( 1) GREEK RHO SYMBOL - {0x03F4, 0x03F4, 0x03B8}, // ϴ θ ( 1) GREEK CAPITAL THETA SYMBOL - {0x03F5, 0x03F5, 0x03B5}, // ϵ ε ( 1) GREEK LUNATE EPSILON SYMBOL - {0x03F7, 0x03F7, 0x03F8}, // Ϸ ϸ ( 1) GREEK CAPITAL LETTER SHO - {0x03F9, 0x03F9, 0x03F2}, // Ϲ ϲ ( 1) GREEK CAPITAL LUNATE SIGMA SYMBOL - {0x03FA, 0x03FA, 0x03FB}, // Ϻ ϻ ( 1) GREEK CAPITAL LETTER SAN - {0x03FD, 0x03FF, 0x037D}, // Ͻ ͻ ( 3) GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL - {0x0400, 0x040F, 0x045F}, // Ѐ ѐ (16) CYRILLIC CAPITAL LETTER IE WITH GRAVE - {0x0410, 0x042F, 0x044F}, // А а (32) CYRILLIC CAPITAL LETTER A - {0x0460, 0x0480, 0x0481}, // Ѡ ѡ (17) CYRILLIC CAPITAL LETTER OMEGA - {0x048A, 0x04BE, 0x04BF}, // Ҋ ҋ (27) CYRILLIC CAPITAL LETTER SHORT I WITH TAIL - {0x04C0, 0x04C0, 0x04CF}, // Ӏ ӏ ( 1) CYRILLIC LETTER PALOCHKA - {0x04C1, 0x04CD, 0x04CE}, // Ӂ ӂ ( 7) CYRILLIC CAPITAL LETTER ZHE WITH BREVE - {0x04D0, 0x052E, 0x052F}, // Ӑ ӑ (48) CYRILLIC CAPITAL LETTER A WITH BREVE - {0x0531, 0x0556, 0x0586}, // Ա ա (38) ARMENIAN CAPITAL LETTER AYB - {0x10A0, 0x10C5, 0x2D25}, // Ⴀ ⴀ (38) GEORGIAN CAPITAL LETTER AN - {0x10C7, 0x10C7, 0x2D27}, // Ⴧ ⴧ ( 1) GEORGIAN CAPITAL LETTER YN - {0x10CD, 0x10CD, 0x2D2D}, // Ⴭ ⴭ ( 1) GEORGIAN CAPITAL LETTER AEN - {0x13F8, 0x13FD, 0x13F5}, // ᏸ Ᏸ ( 6) CHEROKEE SMALL LETTER YE - {0x1C80, 0x1C80, 0x0432}, // ᲀ в ( 1) CYRILLIC SMALL LETTER ROUNDED VE - {0x1C81, 0x1C81, 0x0434}, // ᲁ д ( 1) CYRILLIC SMALL LETTER LONG-LEGGED DE - {0x1C82, 0x1C82, 0x043E}, // ᲂ о ( 1) CYRILLIC SMALL LETTER NARROW O - {0x1C83, 0x1C84, 0x0442}, // ᲃ с ( 2) CYRILLIC SMALL LETTER WIDE ES - {0x1C85, 0x1C85, 0x0442}, // ᲅ т ( 1) CYRILLIC SMALL LETTER THREE-LEGGED TE - {0x1C86, 0x1C86, 0x044A}, // ᲆ ъ ( 1) CYRILLIC SMALL LETTER TALL HARD SIGN - {0x1C87, 0x1C87, 0x0463}, // ᲇ ѣ ( 1) CYRILLIC SMALL LETTER TALL YAT - {0x1C88, 0x1C88, 0xA64B}, // ᲈ ꙋ ( 1) CYRILLIC SMALL LETTER UNBLENDED UK - {0x1C90, 0x1CBA, 0x10FA}, // Ა ა (43) GEORGIAN MTAVRULI CAPITAL LETTER AN - {0x1CBD, 0x1CBF, 0x10FF}, // Ჽ ჽ ( 3) GEORGIAN MTAVRULI CAPITAL LETTER AEN - {0x1E00, 0x1E94, 0x1E95}, // Ḁ ḁ (75) LATIN CAPITAL LETTER A WITH RING BELOW - {0x1E9B, 0x1E9B, 0x1E61}, // ẛ ṡ ( 1) LATIN SMALL LETTER LONG S WITH DOT ABOVE - {0x1E9E, 0x1E9E, 0x00DF}, // ẞ ß ( 1) LATIN CAPITAL LETTER SHARP S - {0x1EA0, 0x1EFE, 0x1EFF}, // Ạ ạ (48) LATIN CAPITAL LETTER A WITH DOT BELOW - {0x1F08, 0x1F0F, 0x1F07}, // Ἀ ἀ ( 8) GREEK CAPITAL LETTER ALPHA WITH PSILI - {0x1F18, 0x1F1D, 0x1F15}, // Ἐ ἐ ( 6) GREEK CAPITAL LETTER EPSILON WITH PSILI - {0x1F28, 0x1F2F, 0x1F27}, // Ἠ ἠ ( 8) GREEK CAPITAL LETTER ETA WITH PSILI - {0x1F38, 0x1F3F, 0x1F37}, // Ἰ ἰ ( 8) GREEK CAPITAL LETTER IOTA WITH PSILI - {0x1F48, 0x1F4D, 0x1F45}, // Ὀ ὀ ( 6) GREEK CAPITAL LETTER OMICRON WITH PSILI - {0x1F59, 0x1F5F, 0x1F57}, // Ὑ ὑ ( 7) GREEK CAPITAL LETTER UPSILON WITH DASIA - {0x1F68, 0x1F6F, 0x1F67}, // Ὠ ὠ ( 8) GREEK CAPITAL LETTER OMEGA WITH PSILI - {0x1F88, 0x1F8F, 0x1F87}, // ᾈ ᾀ ( 8) GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI - {0x1F98, 0x1F9F, 0x1F97}, // ᾘ ᾐ ( 8) GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI - {0x1FA8, 0x1FAF, 0x1FA7}, // ᾨ ᾠ ( 8) GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI - {0x1FB8, 0x1FB9, 0x1FB1}, // Ᾰ ᾰ ( 2) GREEK CAPITAL LETTER ALPHA WITH VRACHY - {0x1FBA, 0x1FBB, 0x1F71}, // Ὰ ὰ ( 2) GREEK CAPITAL LETTER ALPHA WITH VARIA - {0x1FBC, 0x1FBC, 0x1FB3}, // ᾼ ᾳ ( 1) GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI - {0x1FBE, 0x1FBE, 0x03B9}, // ι ι ( 1) GREEK PROSGEGRAMMENI - {0x1FC8, 0x1FCB, 0x1F75}, // Ὲ ὲ ( 4) GREEK CAPITAL LETTER EPSILON WITH VARIA - {0x1FCC, 0x1FCC, 0x1FC3}, // ῌ ῃ ( 1) GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI - {0x1FD8, 0x1FD9, 0x1FD1}, // Ῐ ῐ ( 2) GREEK CAPITAL LETTER IOTA WITH VRACHY - {0x1FDA, 0x1FDB, 0x1F77}, // Ὶ ὶ ( 2) GREEK CAPITAL LETTER IOTA WITH VARIA - {0x1FE8, 0x1FE9, 0x1FE1}, // Ῠ ῠ ( 2) GREEK CAPITAL LETTER UPSILON WITH VRACHY - {0x1FEA, 0x1FEB, 0x1F7B}, // Ὺ ὺ ( 2) GREEK CAPITAL LETTER UPSILON WITH VARIA - {0x1FEC, 0x1FEC, 0x1FE5}, // Ῥ ῥ ( 1) GREEK CAPITAL LETTER RHO WITH DASIA - {0x1FF8, 0x1FF9, 0x1F79}, // Ὸ ὸ ( 2) GREEK CAPITAL LETTER OMICRON WITH VARIA - {0x1FFA, 0x1FFB, 0x1F7D}, // Ὼ ὼ ( 2) GREEK CAPITAL LETTER OMEGA WITH VARIA - {0x1FFC, 0x1FFC, 0x1FF3}, // ῼ ῳ ( 1) GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI - {0x2126, 0x2126, 0x03C9}, // Ω ω ( 1) OHM SIGN - {0x212A, 0x212A, 0x006B}, // K k ( 1) KELVIN SIGN - {0x212B, 0x212B, 0x00E5}, // Å å ( 1) ANGSTROM SIGN - {0x2132, 0x2132, 0x214E}, // Ⅎ ⅎ ( 1) TURNED CAPITAL F - {0x2160, 0x216F, 0x217F}, // Ⅰ ⅰ (16) ROMAN NUMERAL ONE - {0x2183, 0x2183, 0x2184}, // Ↄ ↄ ( 1) ROMAN NUMERAL REVERSED ONE HUNDRED - {0x24B6, 0x24CF, 0x24E9}, // Ⓐ ⓐ (26) CIRCLED LATIN CAPITAL LETTER A - {0x2C00, 0x2C2F, 0x2C5F}, // Ⰰ ⰰ (48) GLAGOLITIC CAPITAL LETTER AZU - {0x2C60, 0x2C60, 0x2C61}, // Ⱡ ⱡ ( 1) LATIN CAPITAL LETTER L WITH DOUBLE BAR - {0x2C62, 0x2C62, 0x026B}, // Ɫ ɫ ( 1) LATIN CAPITAL LETTER L WITH MIDDLE TILDE - {0x2C63, 0x2C63, 0x1D7D}, // Ᵽ ᵽ ( 1) LATIN CAPITAL LETTER P WITH STROKE - {0x2C64, 0x2C64, 0x027D}, // Ɽ ɽ ( 1) LATIN CAPITAL LETTER R WITH TAIL - {0x2C67, 0x2C6B, 0x2C6C}, // Ⱨ ⱨ ( 3) LATIN CAPITAL LETTER H WITH DESCENDER - {0x2C6D, 0x2C6D, 0x0251}, // Ɑ ɑ ( 1) LATIN CAPITAL LETTER ALPHA - {0x2C6E, 0x2C6E, 0x0271}, // Ɱ ɱ ( 1) LATIN CAPITAL LETTER M WITH HOOK - {0x2C6F, 0x2C6F, 0x0250}, // Ɐ ɐ ( 1) LATIN CAPITAL LETTER TURNED A - {0x2C70, 0x2C70, 0x0252}, // Ɒ ɒ ( 1) LATIN CAPITAL LETTER TURNED ALPHA - {0x2C72, 0x2C72, 0x2C73}, // Ⱳ ⱳ ( 1) LATIN CAPITAL LETTER W WITH HOOK - {0x2C75, 0x2C75, 0x2C76}, // Ⱶ ⱶ ( 1) LATIN CAPITAL LETTER HALF H - {0x2C7E, 0x2C7F, 0x0240}, // Ȿ ȿ ( 2) LATIN CAPITAL LETTER S WITH SWASH TAIL - {0x2C80, 0x2CE2, 0x2CE3}, // Ⲁ ⲁ (50) COPTIC CAPITAL LETTER ALFA - {0x2CEB, 0x2CED, 0x2CEE}, // Ⳬ ⳬ ( 2) COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI - {0x2CF2, 0x2CF2, 0x2CF3}, // Ⳳ ⳳ ( 1) COPTIC CAPITAL LETTER BOHAIRIC KHEI - {0xA640, 0xA66C, 0xA66D}, // Ꙁ ꙁ (23) CYRILLIC CAPITAL LETTER ZEMLYA - {0xA680, 0xA69A, 0xA69B}, // Ꚁ ꚁ (14) CYRILLIC CAPITAL LETTER DWE - {0xA722, 0xA72E, 0xA72F}, // Ꜣ ꜣ ( 7) LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF - {0xA732, 0xA76E, 0xA76F}, // Ꜳ ꜳ (31) LATIN CAPITAL LETTER AA - {0xA779, 0xA77B, 0xA77C}, // Ꝺ ꝺ ( 2) LATIN CAPITAL LETTER INSULAR D - {0xA77D, 0xA77D, 0x1D79}, // Ᵹ ᵹ ( 1) LATIN CAPITAL LETTER INSULAR G - {0xA77E, 0xA786, 0xA787}, // Ꝿ ꝿ ( 5) LATIN CAPITAL LETTER TURNED INSULAR G - {0xA78B, 0xA78B, 0xA78C}, // Ꞌ ꞌ ( 1) LATIN CAPITAL LETTER SALTILLO - {0xA78D, 0xA78D, 0x0265}, // Ɥ ɥ ( 1) LATIN CAPITAL LETTER TURNED H - {0xA790, 0xA792, 0xA793}, // Ꞑ ꞑ ( 2) LATIN CAPITAL LETTER N WITH DESCENDER - {0xA796, 0xA7A8, 0xA7A9}, // Ꞗ ꞗ (10) LATIN CAPITAL LETTER B WITH FLOURISH - {0xA7AA, 0xA7AA, 0x0266}, // Ɦ ɦ ( 1) LATIN CAPITAL LETTER H WITH HOOK - {0xA7AB, 0xA7AB, 0x025C}, // Ɜ ɜ ( 1) LATIN CAPITAL LETTER REVERSED OPEN E - {0xA7AC, 0xA7AC, 0x0261}, // Ɡ ɡ ( 1) LATIN CAPITAL LETTER SCRIPT G - {0xA7AD, 0xA7AD, 0x026C}, // Ɬ ɬ ( 1) LATIN CAPITAL LETTER L WITH BELT - {0xA7AE, 0xA7AE, 0x026A}, // Ɪ ɪ ( 1) LATIN CAPITAL LETTER SMALL CAPITAL I - {0xA7B0, 0xA7B0, 0x029E}, // Ʞ ʞ ( 1) LATIN CAPITAL LETTER TURNED K - {0xA7B1, 0xA7B1, 0x0287}, // Ʇ ʇ ( 1) LATIN CAPITAL LETTER TURNED T - {0xA7B2, 0xA7B2, 0x029D}, // Ʝ ʝ ( 1) LATIN CAPITAL LETTER J WITH CROSSED-TAIL - {0xA7B3, 0xA7B3, 0xAB53}, // Ꭓ ꭓ ( 1) LATIN CAPITAL LETTER CHI - {0xA7B4, 0xA7C2, 0xA7C3}, // Ꞵ ꞵ ( 8) LATIN CAPITAL LETTER BETA - {0xA7C4, 0xA7C4, 0xA794}, // Ꞔ ꞔ ( 1) LATIN CAPITAL LETTER C WITH PALATAL HOOK - {0xA7C5, 0xA7C5, 0x0282}, // Ʂ ʂ ( 1) LATIN CAPITAL LETTER S WITH HOOK - {0xA7C6, 0xA7C6, 0x1D8E}, // Ᶎ ᶎ ( 1) LATIN CAPITAL LETTER Z WITH PALATAL HOOK - {0xA7C7, 0xA7C9, 0xA7CA}, // Ꟈ ꟈ ( 2) LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY - {0xA7D0, 0xA7D0, 0xA7D1}, // Ꟑ ꟑ ( 1) LATIN CAPITAL LETTER CLOSED INSULAR G - {0xA7D6, 0xA7D8, 0xA7D9}, // Ꟗ ꟗ ( 2) LATIN CAPITAL LETTER MIDDLE SCOTS S - {0xA7F5, 0xA7F5, 0xA7F6}, // Ꟶ ꟶ ( 1) LATIN CAPITAL LETTER REVERSED HALF H - {0xAB70, 0xABBF, 0x13EF}, // ꭰ Ꭰ (80) CHEROKEE SMALL LETTER A - {0xFF21, 0xFF3A, 0xFF5A}, // A a (26) FULLWIDTH LATIN CAPITAL LETTER A - {0x0130, 0x0130, 0x0069}, // İ i ( 1) LATIN CAPITAL LETTER I WITH DOT ABOVE - {0x01CD, 0x01DB, 0x01DC}, // Ǎ ǎ ( 8) LATIN CAPITAL LETTER A WITH CARON - {0x01F4, 0x01F4, 0x01F5}, // Ǵ ǵ ( 1) LATIN CAPITAL LETTER G WITH ACUTE - {0x13A0, 0x13EF, 0xABBF}, // Ꭰ ꭰ (80) CHEROKEE LETTER A - {0x13F0, 0x13F5, 0x13FD}, // Ᏸ ᏸ ( 6) CHEROKEE LETTER YE - {0x039C, 0x039C, 0x00B5}, // Μ µ ( 1) - {0x0049, 0x0049, 0x0131}, // I ı ( 1) - {0x0053, 0x0053, 0x017F}, // S ſ ( 1) - {0x03A3, 0x03A3, 0x03C2}, // Σ ς ( 1) - {0x0392, 0x0392, 0x03D0}, // Β ϐ ( 1) - {0x0398, 0x0398, 0x03D1}, // Θ ϑ ( 1) - {0x03A6, 0x03A6, 0x03D5}, // Φ ϕ ( 1) - {0x03A0, 0x03A0, 0x03D6}, // Π ϖ ( 1) - {0x039A, 0x039A, 0x03F0}, // Κ ϰ ( 1) - {0x03A1, 0x03A1, 0x03F1}, // Ρ ϱ ( 1) - {0x0395, 0x0395, 0x03F5}, // Ε ϵ ( 1) - {0x0412, 0x0412, 0x1C80}, // В ᲀ ( 1) - {0x0414, 0x0414, 0x1C81}, // Д ᲁ ( 1) - {0x041E, 0x041E, 0x1C82}, // О ᲂ ( 1) - {0x0421, 0x0422, 0x1C84}, // С ᲃ ( 2) - {0x0422, 0x0422, 0x1C85}, // Т ᲅ ( 1) - {0x042A, 0x042A, 0x1C86}, // Ъ ᲆ ( 1) - {0x0462, 0x0462, 0x1C87}, // Ѣ ᲇ ( 1) - {0xA64A, 0xA64A, 0x1C88}, // Ꙋ ᲈ ( 1) - {0x1E60, 0x1E60, 0x1E9B}, // Ṡ ẛ ( 1) - {0x0399, 0x0399, 0x1FBE}, // Ι ι ( 1) -}; // 218 - -enum { casefold_len = 192 }; - -static uint8_t upcase_ind[162] = { - 0, 2, 3, 4, 192, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 43, 45, 193, 47, 48, 194, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 80, 83, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 195, 196, 109, 110, 111, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 125, 126, 129, 131, 132, 133, 134, 135, 136, 137, 139, 140, 141, 142, 144, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 191, -}; - -static uint8_t lowcase_ind[184] = { - 0, 197, 113, 2, 3, 8, 4, 198, 5, 6, 7, 9, 199, 60, 12, 14, 16, 20, 50, 25, - 57, 53, 29, 31, 33, 35, 37, 39, 40, 51, 41, 43, 45, 193, 17, 47, 48, 194, 52, 54, - 56, 158, 59, 63, 154, 152, 155, 11, 13, 15, 18, 19, 174, 21, 175, 22, 170, 173, 24, 23, - 177, 148, 176, 26, 153, 27, 28, 150, 30, 184, 32, 179, 34, 61, 36, 62, 38, 180, 178, 65, - 66, 88, 68, 69, 72, 200, 73, 70, 71, 201, 202, 203, 204, 75, 80, 205, 206, 86, 67, 207, - 85, 87, 90, 89, 91, 92, 94, 93, 95, 96, 109, 110, 196, 208, 209, 210, 211, 212, 213, 214, - 215, 167, 149, 185, 111, 216, 114, 115, 116, 117, 118, 119, 120, 121, 126, 129, 132, 136, 134, 137, - 122, 123, 124, 125, 127, 217, 130, 131, 133, 135, 138, 142, 144, 146, 147, 55, 58, 151, 156, 157, - 159, 160, 161, 97, 98, 99, 162, 163, 164, 165, 166, 168, 169, 171, 183, 172, 182, 186, 187, 188, - 189, 181, 195, 191, -}; diff --git a/src/finchlite/codegen/stc/include/stc/queue.h b/src/finchlite/codegen/stc/include/stc/queue.h deleted file mode 100644 index 507cf8ae..00000000 --- a/src/finchlite/codegen/stc/include/stc/queue.h +++ /dev/null @@ -1,39 +0,0 @@ -/* 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. - */ - -// Queue. Implemented as a ring buffer. -#include "priv/linkage.h" -#include "types.h" - -#ifndef STC_QUEUE_H_INCLUDED -#define STC_QUEUE_H_INCLUDED -#include "common.h" -#include -#endif // STC_QUEUE_H_INCLUDED - -#ifndef _i_prefix - #define _i_prefix queue_ -#endif -#include "priv/template.h" -#include "priv/queue_prv.h" -#include "sys/finalize.h" diff --git a/src/finchlite/codegen/stc/include/stc/random.h b/src/finchlite/codegen/stc/include/stc/random.h deleted file mode 100644 index 4d729054..00000000 --- a/src/finchlite/codegen/stc/include/stc/random.h +++ /dev/null @@ -1,248 +0,0 @@ -/* 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. -*/ -#define i_header // external linkage of normal_dist by default. -#include "priv/linkage.h" - -#ifndef STC_RANDOM_H_INCLUDED -#define STC_RANDOM_H_INCLUDED - -#include "common.h" - -// ===== crand64 =================================== - -typedef struct { - uint64_t data[4]; -} crand64; - -typedef struct { - double mean, stddev; - double _next; - int _has_next; -} crand64_normal_dist; - -STC_API double crand64_normal(crand64_normal_dist* d); -STC_API double crand64_normal_r(crand64* rng, uint64_t stream, crand64_normal_dist* d); - -#if INTPTR_MAX == INT64_MAX - #define crandWS crand64 -#else - #define crandWS crand32 -#endif - -#define c_shuffle_seed(s) \ - c_JOIN(crandWS, _seed)(s) - -#define c_shuffle_array(array, n) do { \ - typedef struct { char d[sizeof 0[array]]; } _etype; \ - _etype* _arr = (_etype *)(array); \ - for (isize _i = (n) - 1; _i > 0; --_i) { \ - isize _j = (isize)(c_JOIN(crandWS, _uint)() % (_i + 1)); \ - c_swap(_arr + _i, _arr + _j); \ - } \ -} while (0) - -// Compiles with vec, stack, and deque container types: -#define c_shuffle(CntType, self) do { \ - CntType* _self = self; \ - for (isize _i = CntType##_size(_self) - 1; _i > 0; --_i) { \ - isize _j = (isize)(c_JOIN(crandWS, _uint)() % (_i + 1)); \ - c_swap(CntType##_at_mut(_self, _i), CntType##_at_mut(_self, _j)); \ - } \ -} while (0) - -STC_INLINE void crand64_seed_r(crand64* rng, uint64_t seed) { - uint64_t* s = rng->data; - s[0] = seed*0x9e3779b97f4a7c15; s[0] ^= s[0] >> 30; - s[1] = s[0]*0xbf58476d1ce4e5b9; s[1] ^= s[1] >> 27; - s[2] = s[1]*0x94d049bb133111eb; s[2] ^= s[2] >> 31; - s[3] = seed; -} - -// Minimum period length 2^64 per stream. 2^63 streams (odd numbers only) -STC_INLINE uint64_t crand64_uint_r(crand64* rng, uint64_t stream) { - uint64_t* s = rng->data; - const uint64_t result = (s[0] ^ (s[3] += stream)) + s[1]; - s[0] = s[1] ^ (s[1] >> 11); - s[1] = s[2] + (s[2] << 3); - s[2] = ((s[2] << 24) | (s[2] >> 40)) + result; - return result; -} - -STC_INLINE double crand64_real_r(crand64* rng, uint64_t stream) - { return (double)(crand64_uint_r(rng, stream) >> 11) * 0x1.0p-53; } - -STC_INLINE crand64* _stc64(void) { - static crand64 rng = {{0x9e3779bb07979af0,0x6f682616bae3641a,0xe220a8397b1dcdaf,0x1}}; - return &rng; -} - -STC_INLINE void crand64_seed(uint64_t seed) - { crand64_seed_r(_stc64(), seed); } - -STC_INLINE crand64 crand64_from(uint64_t seed) - { crand64 rng; crand64_seed_r(&rng, seed); return rng; } - -STC_INLINE uint64_t crand64_uint(void) - { return crand64_uint_r(_stc64(), 1); } - -STC_INLINE double crand64_real(void) - { return crand64_real_r(_stc64(), 1); } - -// --- crand64_uniform --- - -typedef struct { - int64_t low; - uint64_t range, threshold; -} crand64_uniform_dist; - -STC_INLINE crand64_uniform_dist -crand64_make_uniform(int64_t low, int64_t high) { - crand64_uniform_dist d = {low, (uint64_t)(high - low + 1)}; - d.threshold = (uint64_t)(0 - d.range) % d.range; - return d; -} - -// 128-bit multiplication -#if defined(__SIZEOF_INT128__) - #define c_umul128(a, b, lo, hi) \ - do { __uint128_t _z = (__uint128_t)(a)*(b); \ - *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0) -#elif defined(_MSC_VER) && defined(_WIN64) - #include - #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi))) -#elif defined(__x86_64__) - #define c_umul128(a, b, lo, hi) \ - asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) -#endif - -STC_INLINE int64_t -crand64_uniform_r(crand64* rng, uint64_t stream, crand64_uniform_dist* d) { - uint64_t lo, hi; - #ifdef c_umul128 - do { c_umul128(crand64_uint_r(rng, stream), d->range, &lo, &hi); } while (lo < d->threshold); - #else - do { lo = crand64_uint_r(rng, stream); hi = lo % d->range; } while (lo - hi > -d->range); - #endif - return d->low + (int64_t)hi; -} - -STC_INLINE int64_t crand64_uniform(crand64_uniform_dist* d) - { return crand64_uniform_r(_stc64(), 1, d); } - -// ===== crand32 =================================== - -typedef struct { uint32_t data[4]; } crand32; - -STC_INLINE void crand32_seed_r(crand32* rng, uint32_t seed) { - uint32_t* s = rng->data; - s[0] = seed*0x9e3779b9; s[0] ^= s[0] >> 16; - s[1] = s[0]*0x21f0aaad; s[1] ^= s[1] >> 15; - s[2] = s[1]*0x735a2d97; s[2] ^= s[2] >> 15; - s[3] = seed; -} - -// Minimum period length 2^32 per stream. 2^31 streams (odd numbers only) -STC_INLINE uint32_t crand32_uint_r(crand32* rng, uint32_t stream) { - uint32_t* s = rng->data; - const uint32_t result = (s[0] ^ (s[3] += stream)) + s[1]; - s[0] = s[1] ^ (s[1] >> 9); - s[1] = s[2] + (s[2] << 3); - s[2] = ((s[2] << 21) | (s[2] >> 11)) + result; - return result; -} - -STC_INLINE double crand32_real_r(crand32* rng, uint32_t stream) - { return crand32_uint_r(rng, stream) * 0x1.0p-32; } - -STC_INLINE crand32* _stc32(void) { - static crand32 rng = {{0x9e37e78e,0x6eab1ba1,0x64625032,0x1}}; - return &rng; -} - -STC_INLINE void crand32_seed(uint32_t seed) - { crand32_seed_r(_stc32(), seed); } - -STC_INLINE crand32 crand32_from(uint32_t seed) - { crand32 rng; crand32_seed_r(&rng, seed); return rng; } - -STC_INLINE uint32_t crand32_uint(void) - { return crand32_uint_r(_stc32(), 1); } - -STC_INLINE double crand32_real(void) - { return crand32_real_r(_stc32(), 1); } - -// --- crand32_uniform --- - -typedef struct { - int32_t low; - uint32_t range, threshold; -} crand32_uniform_dist; - -STC_INLINE crand32_uniform_dist -crand32_make_uniform(int32_t low, int32_t high) { - crand32_uniform_dist d = {low, (uint32_t)(high - low + 1)}; - d.threshold = (uint32_t)(0 - d.range) % d.range; - return d; -} - -STC_INLINE int32_t -crand32_uniform_r(crand32* rng, uint32_t stream, crand32_uniform_dist* d) { - uint64_t r; - do { - r = crand32_uint_r(rng, stream) * (uint64_t)d->range; - } while ((uint32_t)r < d->threshold); - return d->low + (int32_t)(r >> 32); -} - -STC_INLINE int64_t crand32_uniform(crand32_uniform_dist* d) - { return crand32_uniform_r(_stc32(), 1, d); } - -#endif // STC_RANDOM_H_INCLUDED - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement && !defined STC_RANDOM_IMPLEMENT -#define STC_RANDOM_IMPLEMENT -#include - -STC_DEF double -crand64_normal_r(crand64* rng, uint64_t stream, crand64_normal_dist* d) { - double v1, v2, sq, rt; - if (d->_has_next++ & 1) - return d->_next*d->stddev + d->mean; - do { - // range (-1.0, 1.0): - v1 = (double)((int64_t)crand64_uint_r(rng, stream) >> 11) * 0x1.0p-52; - v2 = (double)((int64_t)crand64_uint_r(rng, stream) >> 11) * 0x1.0p-52; - - sq = v1*v1 + v2*v2; - } while (sq >= 1.0 || sq == 0.0); - rt = sqrt(-2.0 * log(sq) / sq); - d->_next = v2*rt; - return (v1*rt)*d->stddev + d->mean; -} - -STC_DEF double crand64_normal(crand64_normal_dist* d) - { return crand64_normal_r(_stc64(), 1, d); } - -#endif // IMPLEMENT -#include "priv/linkage2.h" diff --git a/src/finchlite/codegen/stc/include/stc/rc.h b/src/finchlite/codegen/stc/include/stc/rc.h deleted file mode 100644 index 98ec6e08..00000000 --- a/src/finchlite/codegen/stc/include/stc/rc.h +++ /dev/null @@ -1,38 +0,0 @@ -/* MIT License - * - * Copyright (c) 2025 Tyge Løvmap - * - * 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. - */ - -// Unordered map - implemented with the robin-hood hashing scheme. -/* -#define T IRefc, int -#include -#include - -int main(void) { - IRefc rc = IRefc_make(42); - IRefc_drop(&rc); -} -*/ - -#define i_no_atomic -#define _i_prefix rc_ -#include "arc.h" diff --git a/src/finchlite/codegen/stc/include/stc/smap.h b/src/finchlite/codegen/stc/include/stc/smap.h deleted file mode 100644 index 1dfdb4b8..00000000 --- a/src/finchlite/codegen/stc/include/stc/smap.h +++ /dev/null @@ -1,612 +0,0 @@ -/* 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. - */ - -// Sorted/Ordered set and map - implemented as an AA-tree. -/* -#include -#include - -#define T SMap, cstr, double, (c_keypro) // Sorted map -#include - -int main(void) { - SMap m = {0}; - SMap_emplace(&m, "Testing one", 1.234); - SMap_emplace(&m, "Testing two", 12.34); - SMap_emplace(&m, "Testing three", 123.4); - - SMap_value *v = SMap_get(&m, "Testing five"); // NULL - double num = *SMap_at(&m, "Testing one"); - SMap_emplace_or_assign(&m, "Testing three", 1000.0); // update - SMap_erase(&m, "Testing two"); - - for (c_each(i, SMap, m)) - printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second); - - SMap_drop(&m); -} -*/ -#include "priv/linkage.h" -#include "types.h" - -#ifndef STC_SMAP_H_INCLUDED -#define STC_SMAP_H_INCLUDED -#include "common.h" -#include -#endif // STC_SMAP_H_INCLUDED - -#ifndef _i_prefix - #define _i_prefix smap_ -#endif -#ifndef _i_is_set - #define _i_is_map - #define _i_MAP_ONLY c_true - #define _i_SET_ONLY c_false - #define _i_keyref(vp) (&(vp)->first) -#else - #define _i_MAP_ONLY c_false - #define _i_SET_ONLY c_true - #define _i_keyref(vp) (vp) -#endif -#define _i_sorted -#include "priv/template.h" -#ifndef i_declared - _c_DEFTYPES(_declare_aatree, Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY, _i_aux_def); -#endif - -_i_MAP_ONLY( struct _m_value { - _m_key first; - _m_mapped second; -}; ) -struct _m_node { - int32_t link[2]; - int8_t level; - _m_value value; -}; - -typedef i_keyraw _m_keyraw; -typedef i_valraw _m_rmapped; -typedef _i_SET_ONLY( _m_keyraw ) - _i_MAP_ONLY( struct { _m_keyraw first; _m_rmapped second; } ) - _m_raw; - -#ifndef i_no_emplace -STC_API _m_result _c_MEMB(_emplace)(Self* self, _m_keyraw rkey _i_MAP_ONLY(, _m_rmapped rmapped)); -#endif // !i_no_emplace - -#ifndef i_no_clone -STC_API Self _c_MEMB(_clone)(Self tree); -#endif // !i_no_clone - -STC_API void _c_MEMB(_drop)(const Self* cself); -STC_API bool _c_MEMB(_reserve)(Self* self, isize cap); -STC_API _m_value* _c_MEMB(_find_it)(const Self* self, _m_keyraw rkey, _m_iter* out); -STC_API _m_iter _c_MEMB(_lower_bound)(const Self* self, _m_keyraw rkey); -STC_API _m_value* _c_MEMB(_front)(const Self* self); -STC_API _m_value* _c_MEMB(_back)(const Self* self); -STC_API int _c_MEMB(_erase)(Self* self, _m_keyraw rkey); -STC_API _m_iter _c_MEMB(_erase_at)(Self* self, _m_iter it); -STC_API _m_iter _c_MEMB(_erase_range)(Self* self, _m_iter it1, _m_iter it2); -STC_API _m_iter _c_MEMB(_begin)(const Self* self); -STC_API void _c_MEMB(_next)(_m_iter* it); - -STC_INLINE bool _c_MEMB(_is_empty)(const Self* self) { return self->size == 0; } -STC_INLINE isize _c_MEMB(_size)(const Self* self) { return self->size; } -STC_INLINE isize _c_MEMB(_capacity)(const Self* self) { return self->capacity; } -STC_INLINE _m_iter _c_MEMB(_find)(const Self* self, _m_keyraw rkey) - { _m_iter it; _c_MEMB(_find_it)(self, rkey, &it); return it; } -STC_INLINE bool _c_MEMB(_contains)(const Self* self, _m_keyraw rkey) - { _m_iter it; return _c_MEMB(_find_it)(self, rkey, &it) != NULL; } -STC_INLINE const _m_value* _c_MEMB(_get)(const Self* self, _m_keyraw rkey) - { _m_iter it; return _c_MEMB(_find_it)(self, rkey, &it); } -STC_INLINE _m_value* _c_MEMB(_get_mut)(Self* self, _m_keyraw rkey) - { _m_iter it; return _c_MEMB(_find_it)(self, rkey, &it); } - -STC_INLINE _m_raw _c_MEMB(_value_toraw)(const _m_value* val) { - return _i_SET_ONLY( i_keytoraw(val) ) - _i_MAP_ONLY( c_literal(_m_raw){i_keytoraw((&val->first)), - i_valtoraw((&val->second))} ); -} - -STC_INLINE void _c_MEMB(_value_drop)(const Self* self, _m_value* val) { - (void)self; - i_keydrop(_i_keyref(val)); - _i_MAP_ONLY( i_valdrop((&val->second)); ) -} - -STC_INLINE Self _c_MEMB(_move)(Self *self) { - Self m = *self; - self->capacity = self->size = self->root = self->disp = self->head = 0; - self->nodes = NULL; - return m; -} - -STC_INLINE void _c_MEMB(_clear)(Self* self) { - _c_MEMB(_drop)(self); - (void)_c_MEMB(_move)(self); -} - -STC_INLINE void _c_MEMB(_take)(Self *self, Self unowned) { - _c_MEMB(_drop)(self); - *self = unowned; -} - -#ifndef i_no_clone -STC_INLINE _m_value _c_MEMB(_value_clone)(const Self* self, _m_value _val) { - (void)self; - *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val))); - _i_MAP_ONLY( _val.second = i_valclone(_val.second); ) - return _val; -} - -STC_INLINE void _c_MEMB(_copy)(Self *self, const Self* other) { - if (self == other) - return; - _c_MEMB(_drop)(self); - *self = _c_MEMB(_clone)(*other); -} - -STC_INLINE void _c_MEMB(_shrink_to_fit)(Self *self) { - Self tmp = _c_MEMB(_clone)(*self); - _c_MEMB(_drop)(self); *self = tmp; -} -#endif // !i_no_clone - -STC_API _m_result _c_MEMB(_insert_entry_)(Self* self, _m_keyraw rkey); - -#ifdef _i_is_map - STC_API _m_result _c_MEMB(_insert_or_assign)(Self* self, _m_key key, _m_mapped mapped); - #ifndef i_no_emplace - STC_API _m_result _c_MEMB(_emplace_or_assign)(Self* self, _m_keyraw rkey, _m_rmapped rmapped); - #endif - - STC_INLINE const _m_mapped* _c_MEMB(_at)(const Self* self, _m_keyraw rkey) - { _m_iter it; return &_c_MEMB(_find_it)(self, rkey, &it)->second; } - - STC_INLINE _m_mapped* _c_MEMB(_at_mut)(Self* self, _m_keyraw rkey) - { _m_iter it; return &_c_MEMB(_find_it)(self, rkey, &it)->second; } -#endif // _i_is_map - -STC_INLINE _m_iter _c_MEMB(_end)(const Self* self) { - _m_iter it; (void)self; - it.ref = NULL, it._top = 0, it._tn = 0; - return it; -} - -STC_INLINE _m_iter _c_MEMB(_advance)(_m_iter it, size_t n) { - while (n-- && it.ref) - _c_MEMB(_next)(&it); - return it; -} - -#if defined _i_has_eq -STC_INLINE bool -_c_MEMB(_eq)(const Self* self, const Self* other) { - if (_c_MEMB(_size)(self) != _c_MEMB(_size)(other)) return false; - _m_iter i = _c_MEMB(_begin)(self), j = _c_MEMB(_begin)(other); - for (; i.ref; _c_MEMB(_next)(&i), _c_MEMB(_next)(&j)) { - const _m_keyraw _rx = i_keytoraw(_i_keyref(i.ref)), _ry = i_keytoraw(_i_keyref(j.ref)); - if (!(i_eq((&_rx), (&_ry)))) return false; - } - return true; -} -#endif - -STC_INLINE _m_result -_c_MEMB(_insert)(Self* self, _m_key _key _i_MAP_ONLY(, _m_mapped _mapped)) { - _m_result _res = _c_MEMB(_insert_entry_)(self, i_keytoraw((&_key))); - if (_res.inserted) - { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} - else - { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )} - return _res; -} - -STC_INLINE _m_value* _c_MEMB(_push)(Self* self, _m_value _val) { - _m_result _res = _c_MEMB(_insert_entry_)(self, i_keytoraw(_i_keyref(&_val))); - if (_res.inserted) - *_res.ref = _val; - else - _c_MEMB(_value_drop)(self, &_val); - return _res.ref; -} - -#if defined _i_is_map && !defined _i_no_put -STC_INLINE _m_result _c_MEMB(_put)(Self* self, _m_keyraw rkey, _m_rmapped rmapped) { - #ifdef i_no_emplace - return _c_MEMB(_insert_or_assign)(self, rkey, rmapped); - #else - return _c_MEMB(_emplace_or_assign)(self, rkey, rmapped); - #endif -} -#endif - -#ifndef _i_no_put -STC_INLINE void _c_MEMB(_put_n)(Self* self, const _m_raw* raw, isize n) { - while (n--) - #if defined _i_is_set && defined i_no_emplace - _c_MEMB(_insert)(self, *raw++); - #elif defined _i_is_set - _c_MEMB(_emplace)(self, *raw++); - #else - _c_MEMB(_put)(self, raw->first, raw->second), ++raw; - #endif -} -#endif - -#ifndef _i_aux_alloc -STC_INLINE Self _c_MEMB(_init)(void) - { Self cx = {0}; return cx; } - -#ifndef _i_no_put -STC_INLINE Self _c_MEMB(_from_n)(const _m_raw* raw, isize n) - { Self cx = {0}; _c_MEMB(_put_n)(&cx, raw, n); return cx; } -#endif - -STC_INLINE Self _c_MEMB(_with_capacity)(const isize cap) - { Self cx = {0}; _c_MEMB(_reserve)(&cx, cap); return cx; } -#endif - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement - -STC_DEF void -_c_MEMB(_next)(_m_iter *it) { - int32_t tn = it->_tn; - if (it->_top || tn) { - while (tn) { - it->_st[it->_top++] = tn; - tn = it->_d[tn].link[0]; - } - tn = it->_st[--it->_top]; - it->_tn = it->_d[tn].link[1]; - it->ref = &it->_d[tn].value; - } else - it->ref = NULL; -} - -STC_DEF _m_iter -_c_MEMB(_begin)(const Self* self) { - _m_iter it; - it.ref = NULL; - it._d = self->nodes, it._top = 0; - it._tn = self->root; - if (it._tn) - _c_MEMB(_next)(&it); - return it; -} - -STC_DEF bool -_c_MEMB(_reserve)(Self* self, const isize cap) { - if (cap <= self->capacity) - return false; - _m_node* nodes = (_m_node*)_i_realloc_n(self->nodes, self->capacity + 1, cap + 1); - if (nodes == NULL) - return false; - nodes[0] = c_literal(_m_node){0}; - self->nodes = nodes; - self->capacity = (int32_t)cap; - return true; -} - -STC_DEF _m_value* -_c_MEMB(_front)(const Self* self) { - _m_node *d = self->nodes; - int32_t tn = self->root; - while (d[tn].link[0]) - tn = d[tn].link[0]; - return &d[tn].value; -} - -STC_DEF _m_value* -_c_MEMB(_back)(const Self* self) { - _m_node *d = self->nodes; - int32_t tn = self->root; - while (d[tn].link[1]) - tn = d[tn].link[1]; - return &d[tn].value; -} - -static int32_t -_c_MEMB(_new_node_)(Self* self, int level) { - int32_t tn; - if (self->disp != 0) { - tn = self->disp; - self->disp = self->nodes[tn].link[1]; - } else { - if (self->head == self->capacity) - if (!_c_MEMB(_reserve)(self, self->head*3/2 + 4)) - return 0; - tn = ++self->head; /* start with 1, 0 is nullnode. */ - } - _m_node* dn = &self->nodes[tn]; - dn->link[0] = dn->link[1] = 0; dn->level = (int8_t)level; - return tn; -} - -#ifdef _i_is_map - STC_DEF _m_result - _c_MEMB(_insert_or_assign)(Self* self, _m_key _key, _m_mapped _mapped) { - _m_result _res = _c_MEMB(_insert_entry_)(self, i_keytoraw((&_key))); - _m_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped; - if (_res.inserted) - _res.ref->first = _key; - else - { i_keydrop((&_key)); i_valdrop(_mp); } - *_mp = _mapped; - return _res; - } - - #ifndef i_no_emplace - STC_DEF _m_result - _c_MEMB(_emplace_or_assign)(Self* self, _m_keyraw rkey, _m_rmapped rmapped) { - _m_result _res = _c_MEMB(_insert_entry_)(self, rkey); - if (_res.inserted) - _res.ref->first = i_keyfrom(rkey); - else { - if (_res.ref == NULL) return _res; - i_valdrop((&_res.ref->second)); - } - _res.ref->second = i_valfrom(rmapped); - return _res; - } - #endif // !i_no_emplace -#endif // !_i_is_map - -STC_DEF _m_value* -_c_MEMB(_find_it)(const Self* self, _m_keyraw rkey, _m_iter* out) { - int32_t tn = self->root; - _m_node *d = out->_d = self->nodes; - out->_top = 0; - while (tn) { - int c; const _m_keyraw _raw = i_keytoraw(_i_keyref(&d[tn].value)); - if ((c = i_cmp((&_raw), (&rkey))) < 0) - tn = d[tn].link[1]; - else if (c > 0) - { out->_st[out->_top++] = tn; tn = d[tn].link[0]; } - else - { out->_tn = d[tn].link[1]; return (out->ref = &d[tn].value); } - } - return (out->ref = NULL); -} - -STC_DEF _m_iter -_c_MEMB(_lower_bound)(const Self* self, _m_keyraw rkey) { - _m_iter it; - _c_MEMB(_find_it)(self, rkey, &it); - if (it.ref == NULL && it._top != 0) { - int32_t tn = it._st[--it._top]; - it._tn = it._d[tn].link[1]; - it.ref = &it._d[tn].value; - } - return it; -} - -STC_DEF int32_t -_c_MEMB(_skew_)(_m_node *d, int32_t tn) { - if (tn != 0 && d[d[tn].link[0]].level == d[tn].level) { - int32_t tmp = d[tn].link[0]; - d[tn].link[0] = d[tmp].link[1]; - d[tmp].link[1] = tn; - tn = tmp; - } - return tn; -} - -STC_DEF int32_t -_c_MEMB(_split_)(_m_node *d, int32_t tn) { - if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) { - int32_t tmp = d[tn].link[1]; - d[tn].link[1] = d[tmp].link[0]; - d[tmp].link[0] = tn; - tn = tmp; - ++d[tn].level; - } - return tn; -} - -STC_DEF int32_t -_c_MEMB(_insert_entry_i_)(Self* self, int32_t tn, const _m_keyraw* rkey, _m_result* _res) { - int32_t up[64], tx = tn; - _m_node* d = self->nodes; - int c, top = 0, dir = 0; - while (tx) { - up[top++] = tx; - const _m_keyraw _raw = i_keytoraw(_i_keyref(&d[tx].value)); - if ((c = i_cmp((&_raw), rkey)) == 0) - { _res->ref = &d[tx].value; return tn; } - dir = (c < 0); - tx = d[tx].link[dir]; - } - if ((tx = _c_MEMB(_new_node_)(self, 1)) == 0) - return 0; - d = self->nodes; - _res->ref = &d[tx].value; - _res->inserted = true; - if (top == 0) - return tx; - d[up[top - 1]].link[dir] = tx; - while (top--) { - if (top != 0) - dir = (d[up[top - 1]].link[1] == up[top]); - up[top] = _c_MEMB(_skew_)(d, up[top]); - up[top] = _c_MEMB(_split_)(d, up[top]); - if (top) - d[up[top - 1]].link[dir] = up[top]; - } - return up[0]; -} - -STC_DEF _m_result -_c_MEMB(_insert_entry_)(Self* self, _m_keyraw rkey) { - _m_result res = {0}; - int32_t tn = _c_MEMB(_insert_entry_i_)(self, self->root, &rkey, &res); - self->root = tn; - self->size += res.inserted; - return res; -} - -STC_DEF int32_t -_c_MEMB(_erase_r_)(Self *self, int32_t tn, const _m_keyraw* rkey, int *erased) { - _m_node *d = self->nodes; - if (tn == 0) - return 0; - _m_keyraw raw = i_keytoraw(_i_keyref(&d[tn].value)); - int32_t tx; int c = i_cmp((&raw), rkey); - if (c != 0) - d[tn].link[c < 0] = _c_MEMB(_erase_r_)(self, d[tn].link[c < 0], rkey, erased); - else { - if ((*erased)++ == 0) - _c_MEMB(_value_drop)(self, &d[tn].value); // drop first time, not second. - if (d[tn].link[0] && d[tn].link[1]) { - tx = d[tn].link[0]; - while (d[tx].link[1]) - tx = d[tx].link[1]; - d[tn].value = d[tx].value; /* move */ - raw = i_keytoraw(_i_keyref(&d[tn].value)); - d[tn].link[0] = _c_MEMB(_erase_r_)(self, d[tn].link[0], &raw, erased); - } else { /* unlink node */ - tx = tn; - tn = d[tn].link[ d[tn].link[0] == 0 ]; - /* move it to disposed nodes list */ - d[tx].link[1] = self->disp; - self->disp = tx; - } - } - tx = d[tn].link[1]; - if (d[d[tn].link[0]].level < d[tn].level - 1 || d[tx].level < d[tn].level - 1) { - if (d[tx].level > --d[tn].level) - d[tx].level = d[tn].level; - tn = _c_MEMB(_skew_)(d, tn); - tx = d[tn].link[1] = _c_MEMB(_skew_)(d, d[tn].link[1]); - d[tx].link[1] = _c_MEMB(_skew_)(d, d[tx].link[1]); - tn = _c_MEMB(_split_)(d, tn); - d[tn].link[1] = _c_MEMB(_split_)(d, d[tn].link[1]); - } - return tn; -} - -STC_DEF int -_c_MEMB(_erase)(Self* self, _m_keyraw rkey) { - int erased = 0; - int32_t root = _c_MEMB(_erase_r_)(self, self->root, &rkey, &erased); - if (erased == 0) - return 0; - self->root = root; - --self->size; - return 1; -} - -STC_DEF _m_iter -_c_MEMB(_erase_at)(Self* self, _m_iter it) { - _m_keyraw raw = i_keytoraw(_i_keyref(it.ref)); - _c_MEMB(_next)(&it); - if (it.ref != NULL) { - _m_keyraw nxt = i_keytoraw(_i_keyref(it.ref)); - _c_MEMB(_erase)(self, raw); - _c_MEMB(_find_it)(self, nxt, &it); - } else - _c_MEMB(_erase)(self, raw); - return it; -} - -STC_DEF _m_iter -_c_MEMB(_erase_range)(Self* self, _m_iter it1, _m_iter it2) { - if (it2.ref == NULL) { - while (it1.ref != NULL) - it1 = _c_MEMB(_erase_at)(self, it1); - return it1; - } - _m_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref); - _m_keyraw r1 = i_keytoraw((&k1)); - for (;;) { - if (memcmp(&k1, &k2, sizeof k1) == 0) - return it1; - _c_MEMB(_next)(&it1); - k1 = *_i_keyref(it1.ref); - _c_MEMB(_erase)(self, r1); - r1 = i_keytoraw((&k1)); - _c_MEMB(_find_it)(self, r1, &it1); - } -} - -#ifndef i_no_clone -STC_DEF int32_t -_c_MEMB(_clone_r_)(Self* self, _m_node* src, int32_t sn) { - if (sn == 0) - return 0; - int32_t tx, tn = _c_MEMB(_new_node_)(self, src[sn].level); - self->nodes[tn].value = _c_MEMB(_value_clone)(self, src[sn].value); - tx = _c_MEMB(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx; - tx = _c_MEMB(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx; - return tn; -} - -STC_DEF Self -_c_MEMB(_clone)(Self tree) { - Self out = tree; - out.root = out.disp = out.head = out.size = out.capacity = 0; - out.nodes = NULL; _c_MEMB(_reserve)(&out, tree.size); - out.root = _c_MEMB(_clone_r_)(&out, tree.nodes, tree.root); - return out; -} -#endif // !i_no_clone - -#ifndef i_no_emplace -STC_DEF _m_result -_c_MEMB(_emplace)(Self* self, _m_keyraw rkey _i_MAP_ONLY(, _m_rmapped rmapped)) { - _m_result res = _c_MEMB(_insert_entry_)(self, rkey); - if (res.inserted) { - *_i_keyref(res.ref) = i_keyfrom(rkey); - _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);) - } - return res; -} -#endif // i_no_emplace - -static void -_c_MEMB(_drop_r_)(Self* s, int32_t tn) { - if (tn != 0) { - _c_MEMB(_drop_r_)(s, s->nodes[tn].link[0]); - _c_MEMB(_drop_r_)(s, s->nodes[tn].link[1]); - _c_MEMB(_value_drop)(s, &s->nodes[tn].value); - } -} - -STC_DEF void -_c_MEMB(_drop)(const Self* cself) { - Self* self = (Self*)cself; - if (self->capacity != 0) { - _c_MEMB(_drop_r_)(self, self->root); - _i_free_n(self->nodes, self->capacity + 1); - } -} - -#endif // i_implement -#undef _i_is_set -#undef _i_is_map -#undef _i_sorted -#undef _i_keyref -#undef _i_MAP_ONLY -#undef _i_SET_ONLY -#include "sys/finalize.h" diff --git a/src/finchlite/codegen/stc/include/stc/sort.h b/src/finchlite/codegen/stc/include/stc/sort.h deleted file mode 100644 index a2f95a57..00000000 --- a/src/finchlite/codegen/stc/include/stc/sort.h +++ /dev/null @@ -1,109 +0,0 @@ -/* 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. - */ -/* Generic Quicksort in C, performs as fast as c++ std::sort(), and more robust. -template params: -#define i_key keytype - [required] (or use i_type, see below) -#define i_less(xp, yp) - optional less function. default: *xp < *yp -#define i_cmp(xp, yp) - alternative 3-way comparison. c_default_cmp(xp, yp) -#define T name - optional, defines {name}_sort(), else {i_key}s_sort(). -#define T name, key - alternative one-liner to define both i_type and i_key. - -// ex1: -#include -#define i_key int -#include - -int main(void) { - int nums[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21}; - - ints_sort(nums, c_arraylen(nums)); - - for (int i = 0; i < c_arraylen(nums); i++) - printf(" %d", nums[i]); - puts(""); - - isize idx = ints_binary_search(nums, 25, c_arraylen(nums)); - if (idx != c_NPOS) printf("found: %d\n", nums[idx]); - - idx = ints_lower_bound(nums, 200, c_arraylen(nums)); - if (idx != c_NPOS) printf("found lower 200: %d\n", nums[idx]); -} - -// ex2: Test on a deque !! -#include -#define T IDeq, int, (c_use_cmp) // enable comparison functions -#include - -int main(void) { - IDeq nums = c_make(IDeq, {5434, 25, 245, 1, 654, 33, 543, 21}); - IDeq_push_front(&nums, 23); - IDeq_push_front(&nums, 321); - - IDeq_sort(&nums); - - for (c_each (i, IDeq, nums)) - printf(" %d", *i.ref); - puts(""); - - isize idx = IDeq_binary_search(&nums, 25); - if (idx != c_NPOS) printf("found: %d\n", *IDeq_at(&nums, idx)); - - idx = IDeq_lower_bound(&nums, 200); - if (idx != c_NPOS) printf("found lower 200: %d\n", *IDeq_at(&nums, idx)); - - IDeq_drop(&nums); -} -*/ -#ifndef _i_template - #include "priv/linkage.h" - #include "common.h" - - #define _i_is_array - #if defined T && !defined i_type - #define i_type T - #endif - #if defined i_type && !defined i_key - #define Self c_GETARG(1, i_type) - #define i_key c_GETARG(2, i_type) - #elif defined i_type - #define Self i_type - #else - #define Self c_JOIN(i_key, s) - #endif - - typedef i_key Self; - typedef Self c_JOIN(Self, _value), c_JOIN(Self, _raw); - #define i_at(arr, idx) (&(arr)[idx]) - #define i_at_mut i_at - #include "priv/template.h" // IWYU pragma: keep -#endif - -#include "priv/sort_prv.h" - -#ifdef _i_is_array - #undef _i_is_array - #include "priv/linkage2.h" - #include "priv/template2.h" -#endif -#undef i_at -#undef i_at_mut diff --git a/src/finchlite/codegen/stc/include/stc/sortedmap.h b/src/finchlite/codegen/stc/include/stc/sortedmap.h deleted file mode 100644 index f293122d..00000000 --- a/src/finchlite/codegen/stc/include/stc/sortedmap.h +++ /dev/null @@ -1,46 +0,0 @@ -/* 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. - */ - -// Sorted map - implemented as an AA-tree (balanced binary tree). -/* -#include - -#define T Intmap, int, int -#include // sorted map of int - -int main(void) { - Intmap map = {0}; - Intmap_insert(&map, 5, 25); - Intmap_insert(&map, 8, 38); - Intmap_insert(&map, 3, 43); - Intmap_insert(&map, 5, 55); - - for (c_each_kv(k, v, Intmap, map)) - printf(" %d -> %d\n", *k, *v); - - Intmap_drop(&map); -} -*/ - -#define _i_prefix smap_ -#include "smap.h" diff --git a/src/finchlite/codegen/stc/include/stc/sortedset.h b/src/finchlite/codegen/stc/include/stc/sortedset.h deleted file mode 100644 index 17c847e9..00000000 --- a/src/finchlite/codegen/stc/include/stc/sortedset.h +++ /dev/null @@ -1,47 +0,0 @@ -/* 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. - */ - -// Sorted set - implemented as an AA-tree (balanced binary tree). -/* -#include - -#define T Intset, int -#include // sorted set of int - -int main(void) { - Intset set = {0}; - Intset_insert(&set, 5); - Intset_insert(&set, 8); - Intset_insert(&set, 3); - Intset_insert(&set, 5); - - for (c_each(k, Intset, set)) - printf(" %d\n", *k.ref); - - Intset_drop(&set); -} -*/ - -#define _i_prefix sset_ -#define _i_is_set -#include "smap.h" diff --git a/src/finchlite/codegen/stc/include/stc/sset.h b/src/finchlite/codegen/stc/include/stc/sset.h deleted file mode 100644 index 6558a1af..00000000 --- a/src/finchlite/codegen/stc/include/stc/sset.h +++ /dev/null @@ -1,46 +0,0 @@ -/* 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. - */ - -// Sorted set - implemented as an AA-tree (balanced binary tree). -/* -#include - -#define T Intset, int -#include // sorted set of int - -int main(void) { - Intset s = {0}; - Intset_insert(&s, 5); - Intset_insert(&s, 8); - Intset_insert(&s, 3); - Intset_insert(&s, 5); - - for (c_each(k, Intset, s)) - printf("set %d\n", *k.ref); - Intset_drop(&s); -} -*/ - -#define _i_prefix sset_ -#define _i_is_set -#include "smap.h" diff --git a/src/finchlite/codegen/stc/include/stc/stack.h b/src/finchlite/codegen/stc/include/stc/stack.h deleted file mode 100644 index 871b0c75..00000000 --- a/src/finchlite/codegen/stc/include/stc/stack.h +++ /dev/null @@ -1,285 +0,0 @@ -/* 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. - */ -#include "priv/linkage.h" -#include "types.h" - -// Stack - a simplified vec type without linear search and insert/erase inside the stack. - -#ifndef STC_STACK_H_INCLUDED -#define STC_STACK_H_INCLUDED -#include "common.h" -#include -#endif // STC_STACK_H_INCLUDED - -#ifndef _i_prefix - #define _i_prefix stack_ -#endif -#include "priv/template.h" -#ifndef i_declared - #if c_NUMARGS(i_type) == 4 - #define i_capacity i_val - #endif - #ifdef i_capacity - #define i_no_clone - _c_DEFTYPES(declare_stack_fixed, Self, i_key, i_capacity); - #else - _c_DEFTYPES(_declare_stack, Self, i_key, _i_aux_def); - #endif -#endif -typedef i_keyraw _m_raw; - -#ifdef i_capacity - STC_INLINE void _c_MEMB(_init)(Self* news) - { news->size = 0; } - - STC_INLINE isize _c_MEMB(_capacity)(const Self* self) - { (void)self; return i_capacity; } - - STC_INLINE bool _c_MEMB(_reserve)(Self* self, isize n) - { (void)self; return n <= i_capacity; } -#else - STC_INLINE Self _c_MEMB(_move)(Self *self) { - Self m = *self; - self->capacity = self->size = 0; - self->data = NULL; - return m; - } - - STC_INLINE isize _c_MEMB(_capacity)(const Self* self) - { return self->capacity; } - - STC_INLINE bool _c_MEMB(_reserve)(Self* self, isize n) { - if (n > self->capacity || (n && n == self->size)) { - _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; - } -#endif // i_capacity - -STC_INLINE 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_INLINE void _c_MEMB(_drop)(const Self* cself) { - Self* self = (Self*)cself; - _c_MEMB(_clear)(self); -#ifndef i_capacity - _i_free_n(self->data, self->capacity); -#endif -} - -STC_INLINE void _c_MEMB(_take)(Self *self, Self unowned) { - _c_MEMB(_drop)(self); - *self = unowned; -} - -STC_INLINE isize _c_MEMB(_size)(const Self* self) - { return self->size; } - -STC_INLINE bool _c_MEMB(_is_empty)(const Self* self) - { return !self->size; } - -STC_INLINE void _c_MEMB(_value_drop)(const Self* self, _m_value* val) - { (void)self; i_keydrop(val); } - -STC_INLINE _m_value* _c_MEMB(_append_uninit)(Self *self, isize n) { - isize len = self->size; - if (len + n >= _c_MEMB(_capacity)(self)) - if (!_c_MEMB(_reserve)(self, len*3/2 + n)) - return NULL; - self->size += n; - return self->data + len; -} - -STC_INLINE void _c_MEMB(_shrink_to_fit)(Self* self) - { _c_MEMB(_reserve)(self, self->size); } - -STC_INLINE const _m_value* _c_MEMB(_front)(const Self* self) - { return &self->data[0]; } -STC_INLINE _m_value* _c_MEMB(_front_mut)(Self* self) - { return &self->data[0]; } - -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 const _m_value* _c_MEMB(_top)(const Self* self) - { return _c_MEMB(_back)(self); } -STC_INLINE _m_value* _c_MEMB(_top_mut)(Self* self) - { return _c_MEMB(_back_mut)(self); } - -STC_INLINE _m_value* _c_MEMB(_push)(Self* self, _m_value val) { - if (self->size == _c_MEMB(_capacity)(self)) - if (!_c_MEMB(_reserve)(self, self->size*3/2 + 4)) - return NULL; - _m_value* vp = self->data + self->size++; - *vp = val; return vp; -} - -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]; } - -#ifndef _i_no_put -STC_INLINE void _c_MEMB(_put_n)(Self* self, const _m_raw* raw, isize n) - { while (n--) _c_MEMB(_push)(self, i_keyfrom((*raw))), ++raw; } -#endif - -#if !defined _i_aux_alloc && !defined i_capacity - STC_INLINE Self _c_MEMB(_init)(void) - { Self out = {0}; return out; } - - STC_INLINE Self _c_MEMB(_with_capacity)(isize cap) - { Self out = {_i_new_n(_m_value, cap), 0, cap}; return out; } - - STC_INLINE Self _c_MEMB(_with_size_uninit)(isize size) - { Self out = {_i_new_n(_m_value, size), size, size}; return out; } - - STC_INLINE Self _c_MEMB(_with_size)(isize 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 n) { - Self out = _c_MEMB(_with_capacity)(n); - _c_MEMB(_put_n)(&out, raw, n); return out; - } - #endif -#endif - -STC_INLINE const _m_value* _c_MEMB(_at)(const Self* self, isize idx) - { c_assert(c_uless(idx, self->size)); return self->data + idx; } - -STC_INLINE _m_value* _c_MEMB(_at_mut)(Self* self, isize idx) - { c_assert(c_uless(idx, self->size)); return self->data + idx; } - -#ifndef i_no_emplace -STC_INLINE _m_value* _c_MEMB(_emplace)(Self* self, _m_raw raw) - { return _c_MEMB(_push)(self, i_keyfrom(raw)); } -#endif // !i_no_emplace - -#ifndef i_no_clone -STC_INLINE Self _c_MEMB(_clone)(Self stk) { - Self out = stk, *self = &out; (void)self; // i_keyclone may use self via i_aux - out.data = NULL; out.size = out.capacity = 0; - _c_MEMB(_reserve)(&out, stk.size); - out.size = stk.size; - for (c_range(i, stk.size)) - out.data[i] = i_keyclone(stk.data[i]); - return out; -} - -STC_INLINE void _c_MEMB(_copy)(Self *self, const Self* other) { - if (self == other) return; - _c_MEMB(_clear)(self); - _c_MEMB(_reserve)(self, other->size); - for (c_range(i, other->size)) - self->data[self->size++] = i_keyclone((other->data[i])); -} - -STC_INLINE _m_value _c_MEMB(_value_clone)(const Self* self, _m_value val) - { (void)self; return i_keyclone(val); } - -STC_INLINE _m_raw _c_MEMB(_value_toraw)(const _m_value* val) - { return i_keytoraw(val); } -#endif // !i_no_clone - -// 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 _c_MEMB(_index)(const Self* self, _m_iter it) - { return (it.ref - self->data); } - -STC_INLINE void _c_MEMB(_adjust_end_)(Self* self, isize n) - { self->size += n; } - -#if defined _i_has_cmp -#include "priv/sort_prv.h" -#endif // _i_has_cmp - -#if defined _i_has_eq -STC_INLINE _m_iter _c_MEMB(_find_in)(const Self* self, _m_iter i1, _m_iter i2, _m_raw raw) { - (void)self; - const _m_value* p2 = i2.ref ? i2.ref : i1.end; - 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; -} - -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(_eq)(const Self* self, const Self* other) { - if (self->size != other->size) return false; - for (isize 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 // _i_has_eq -#include "sys/finalize.h" diff --git a/src/finchlite/codegen/stc/include/stc/sys/crange.h b/src/finchlite/codegen/stc/include/stc/sys/crange.h deleted file mode 100644 index c71cef61..00000000 --- a/src/finchlite/codegen/stc/include/stc/sys/crange.h +++ /dev/null @@ -1,118 +0,0 @@ -/* 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. -*/ -/* -#include -#include - -int main(void) -{ - crange r1 = crange_make(80, 90); - for (c_each(i, crange, r1)) - printf(" %d", *i.ref); - puts(""); - - c_filter(crange, c_iota(100, INT_MAX, 10), true - && c_flt_skip(25) - && c_flt_take(3) - && printf(" %d", *value) - ); - puts(""); -} -*/ -// IWYU pragma: private, include "stc/algorithm.h" -#ifndef STC_CRANGE_H_INCLUDED -#define STC_CRANGE_H_INCLUDED - -#include "../priv/linkage.h" -#include "../common.h" - -// crange: isize range ----- - -typedef isize crange_value; -typedef struct { crange_value start, end, step, value; } crange; -typedef struct { crange_value *ref, end, step; } crange_iter; - -STC_INLINE crange crange_make_3(crange_value start, crange_value stop, crange_value step) - { crange r = {start, stop - (step > 0), step}; return r; } - -#define crange_make(...) c_MACRO_OVERLOAD(crange_make, __VA_ARGS__) -#define crange_make_1(stop) crange_make_3(0, stop, 1) // NB! arg is stop -#define crange_make_2(start, stop) crange_make_3(start, stop, 1) - -STC_INLINE crange_iter crange_begin(crange* self) { - self->value = self->start; - crange_iter it = {&self->value, self->end, self->step}; - return it; -} - -STC_INLINE void crange_next(crange_iter* it) { - if ((it->step > 0) == ((*it->ref += it->step) > it->end)) - it->ref = NULL; -} - -STC_INLINE crange_iter crange_advance(crange_iter it, size_t n) { - if ((it.step > 0) == ((*it.ref += it.step*(isize)n) > it.end)) - it.ref = NULL; - return it; -} - -// iota: c++-like std::iota, use in iterations on-the-fly ----- -// Note: c_iota() does not compile with c++, crange does. -#define c_iota(...) c_MACRO_OVERLOAD(c_iota, __VA_ARGS__) -#define c_iota_1(start) c_iota_3(start, INTPTR_MAX, 1) // NB! arg is start. -#define c_iota_2(start, stop) c_iota_3(start, stop, 1) -#define c_iota_3(start, stop, step) ((crange[]){crange_make_3(start, stop, step)})[0] - - -// crange32 ----- - -typedef int32_t crange32_value; -typedef struct { crange32_value start, end, step, value; } crange32; -typedef struct { crange32_value *ref, end, step; } crange32_iter; - -STC_INLINE crange32 crange32_make_3(crange32_value start, crange32_value stop, crange32_value step) - { crange32 r = {start, stop - (step > 0), step}; return r; } - -#define crange32_make(...) c_MACRO_OVERLOAD(crange32_make, __VA_ARGS__) -#define crange32_make_1(stop) crange32_make_3(0, stop, 1) // NB! arg is stop -#define crange32_make_2(start, stop) crange32_make_3(start, stop, 1) - -STC_INLINE crange32_iter crange32_begin(crange32* self) { - self->value = self->start; - crange32_iter it = {&self->value, self->end, self->step}; - return it; -} - -STC_INLINE void crange32_next(crange32_iter* it) { - if ((it->step > 0) == ((*it->ref += it->step) > it->end)) - it->ref = NULL; -} - -STC_INLINE crange32_iter crange32_advance(crange32_iter it, uint32_t n) { - if ((it.step > 0) == ((*it.ref += it.step*(int32_t)n) > it.end)) - it.ref = NULL; - return it; -} - -#include "../priv/linkage2.h" -#endif // STC_CRANGE_H_INCLUDE diff --git a/src/finchlite/codegen/stc/include/stc/sys/filter.h b/src/finchlite/codegen/stc/include/stc/sys/filter.h deleted file mode 100644 index 512e68db..00000000 --- a/src/finchlite/codegen/stc/include/stc/sys/filter.h +++ /dev/null @@ -1,185 +0,0 @@ -/* 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. -*/ -/* -#include -#define T Vec, int -#include -#include - -int main(void) -{ - Vec vec = c_make(Vec, {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10, 11, 12, 5}); - - c_filter(Vec, vec, true - && c_flt_skipwhile(*value < 3) // skip leading values < 3 - && (*value & 1) == 1 // then use odd values only - && c_flt_map(*value * 2) // multiply by 2 - && c_flt_takewhile(*value < 20) // stop if mapped *value >= 20 - && printf(" %d", *value) // print value - ); - // 6 10 14 2 6 18 - puts(""); - Vec_drop(&vec); -} -*/ -// IWYU pragma: private, include "stc/algorithm.h" -#ifndef STC_FILTER_H_INCLUDED -#define STC_FILTER_H_INCLUDED - -#include "../common.h" - -// ------- c_filter -------- -#define c_flt_take(n) _flt_take(&fltbase, n) -#define c_flt_skip(n) (c_flt_counter() > (n)) -#define c_flt_takewhile(pred) _flt_takewhile(&fltbase, pred) -#define c_flt_skipwhile(pred) (fltbase.sb[fltbase.sb_top++] |= !(pred)) -#define c_flt_counter() (++fltbase.sn[++fltbase.sn_top]) -#define c_flt_getcount() (fltbase.sn[fltbase.sn_top]) -#define c_flt_map(expr) (_mapped = (expr), value = &_mapped) -#define c_flt_src _it.ref - -#define c_filter(C, cnt, pred) \ - _c_filter(C, C##_begin(&cnt), _, pred) - -#define c_filter_from(C, start, pred) \ - _c_filter(C, start, _, pred) - -#define c_filter_reverse(C, cnt, pred) \ - _c_filter(C, C##_rbegin(&cnt), _r, pred) - -#define c_filter_reverse_from(C, start, pred) \ - _c_filter(C, start, _r, pred) - -#define _c_filter(C, start, rev, pred) do { \ - struct _flt_base fltbase = {0}; \ - C##_iter _it = start; \ - C##_value *value = _it.ref, _mapped = {0}; \ - for ((void)_mapped ; !fltbase.done & (_it.ref != NULL) ; \ - C##rev##next(&_it), value = _it.ref, fltbase.sn_top=0, fltbase.sb_top=0) \ - (void)(pred); \ -} while (0) - -// ------- c_filter_zip -------- -#define c_filter_zip(...) c_MACRO_OVERLOAD(c_filter_zip, __VA_ARGS__) -#define c_filter_zip_4(C, cnt1, cnt2, pred) \ - c_filter_zip_5(C, cnt1, C, cnt2, pred) -#define c_filter_zip_5(C1, cnt1, C2, cnt2, pred) \ - _c_filter_zip(C1, C1##_begin(&cnt1), C2, C2##_begin(&cnt2), _, pred) - -#define c_filter_reverse_zip(...) c_MACRO_OVERLOAD(c_filter_reverse_zip, __VA_ARGS__) -#define c_filter_reverse_zip_4(C, cnt1, cnt2, pred) \ - c_filter_reverse_zip_5(C, cnt1, C, cnt2, pred) -#define c_filter_reverse_zip_5(C1, cnt1, C2, cnt2, pred) \ - _c_filter_zip(C1, C1##_rbegin(&cnt1), C2, C2##_rbegin(&cnt2), _r, pred) - -#define c_filter_pairwise(C, cnt, pred) \ - _c_filter_zip(C, C##_begin(&cnt), C, C##_advance(_it1, 1), _, pred) - -#define c_flt_map1(expr) (_mapped1 = (expr), value1 = &_mapped1) -#define c_flt_map2(expr) (_mapped2 = (expr), value2 = &_mapped2) -#define c_flt_src1 _it1.ref -#define c_flt_src2 _it2.ref - -#define _c_filter_zip(C1, start1, C2, start2, rev, pred) do { \ - struct _flt_base fltbase = {0}; \ - C1##_iter _it1 = start1; \ - C2##_iter _it2 = start2; \ - C1##_value* value1 = _it1.ref, _mapped1; (void)_mapped1; \ - C2##_value* value2 = _it2.ref, _mapped2; (void)_mapped2; \ - for (; !fltbase.done & (_it1.ref != NULL) & (_it2.ref != NULL); \ - C1##rev##next(&_it1), value1 = _it1.ref, C2##rev##next(&_it2), value2 = _it2.ref, \ - fltbase.sn_top=0, fltbase.sb_top=0) \ - (void)(pred); \ -} while (0) - -// ------- c_ffilter -------- -// c_ffilter allows to execute imperative statements for each element -// in a for-loop, e.g., calling nested generic statements instead -// of defining a function/expression for it: -/* - Vec vec = ..., vec2 = ...; - for (c_ffilter(i, Vec, vec, true - && c_fflt_skipwhile(i, *i.ref < 3) // skip leading values < 3 - && (*i.ref & 1) == 1 // then use odd values only - && c_fflt_map(i, *i.ref * 2) // multiply by 2 - && c_fflt_takewhile(i, *i.ref < 20) // stop if mapped *i.ref >= 20 - )){ - c_eraseremove_if(Vec, &vec2, *value == *i.ref); - } -*/ -#define c_fflt_take(i, n) _flt_take(&i.base, n) -#define c_fflt_skip(i, n) (c_fflt_counter(i) > (n)) -#define c_fflt_takewhile(i, pred) _flt_takewhile(&i.base, pred) -#define c_fflt_skipwhile(i, pred) (i.base.sb[i.base.sb_top++] |= !(pred)) -#define c_fflt_counter(i) (++i.base.sn[++i.base.sn_top]) -#define c_fflt_getcount(i) (i.base.sn[i.base.sn_top]) -#define c_fflt_map(i, expr) (i.mapped = (expr), i.ref = &i.mapped) -#define c_fflt_src(i) i.iter.ref - -#define c_forfilter(...) for (c_ffilter(__VA_ARGS__)) -#define c_forfilter_from(...) for (c_ffilter_from(__VA_ARGS__)) -#define c_forfilter_reverse(...) for (c_ffilter_reverse(__VA_ARGS__)) -#define c_forfilter_reverse_from(...) for (c_ffilter_reverse_from(__VA_ARGS__)) - -#define c_ffilter(i, C, cnt, pred) \ - _c_ffilter(i, C, C##_begin(&cnt), _, pred) - -#define c_ffilter_from(i, C, start, pred) \ - _c_ffilter(i, C, start, _, pred) - -#define c_ffilter_reverse(i, C, cnt,pred) \ - _c_ffilter(i, C, C##_rbegin(&cnt), _r, pred) - -#define c_ffilter_reverse_from(i, C, start, pred) \ - _c_ffilter(i, C, start, _r, pred) - -#define _c_ffilter(i, C, start, rev, pred) \ - struct {C##_iter iter; C##_value *ref, mapped; struct _flt_base base;} \ - i = {.iter=start, .ref=i.iter.ref} ; !i.base.done & (i.iter.ref != NULL) ; \ - C##rev##next(&i.iter), i.ref = i.iter.ref, i.base.sn_top=0, i.base.sb_top=0) \ - if (!(pred)) ; else if (1 - -// ------------------------ private ------------------------- -#ifndef c_NFILTERS -#define c_NFILTERS 20 -#endif - -struct _flt_base { - uint8_t sn_top, sb_top; - bool done, sb[c_NFILTERS]; - uint32_t sn[c_NFILTERS]; -}; - -static inline bool _flt_take(struct _flt_base* base, uint32_t n) { - uint32_t k = ++base->sn[++base->sn_top]; - base->done |= (k >= n); - return n > 0; -} - -static inline bool _flt_takewhile(struct _flt_base* base, bool pred) { - bool skip = (base->sb[base->sb_top++] |= !pred); - base->done |= skip; - return !skip; -} - -#endif // STC_FILTER_H_INCLUDED diff --git a/src/finchlite/codegen/stc/include/stc/sys/finalize.h b/src/finchlite/codegen/stc/include/stc/sys/finalize.h deleted file mode 100644 index e7271fa4..00000000 --- a/src/finchlite/codegen/stc/include/stc/sys/finalize.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef i_extend - #include "../priv/linkage2.h" - #include "../priv/template2.h" -#endif -#undef i_extend diff --git a/src/finchlite/codegen/stc/include/stc/sys/sumtype.h b/src/finchlite/codegen/stc/include/stc/sys/sumtype.h deleted file mode 100644 index 747a1064..00000000 --- a/src/finchlite/codegen/stc/include/stc/sys/sumtype.h +++ /dev/null @@ -1,172 +0,0 @@ -/* 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. - */ -/* -// https://stackoverflow.com/questions/70935435/how-to-create-variants-in-rust -#include -#include -#include - -c_union (Action, - (ActionSpeak, cstr), - (ActionQuit, bool), - (ActionRunFunc, struct { - int32_t (*func)(int32_t, int32_t); - int32_t v1, v2; - }) -); - -void Action_drop(Action* self) { - if (c_is(self, ActionSpeak, s)) - cstr_drop(s); -} - -void action(Action* action) { - c_when (action) { - c_is(ActionSpeak, s) { - printf("Asked to speak: %s\n", cstr_str(s)); - } - c_is(ActionQuit) { - printf("Asked to quit!\n"); - } - c_is(ActionRunFunc, r) { - int32_t res = r->func(r->v1, r->v2); - printf("v1: %d, v2: %d, res: %d\n", r->v1, r->v2, res); - } - c_otherwise assert(!"no match"); - } -} - -int32_t add(int32_t a, int32_t b) { - return a + b; -} - -int main(void) { - Action act1 = c_variant(ActionSpeak, cstr_from("Hello")); - Action act2 = c_variant(ActionQuit, 1); - Action act3 = c_variant(ActionRunFunc, {add, 5, 6}); - - action(&act1); - action(&act2); - action(&act3); - - c_drop(Action, &act1, &act2, &act3); -} -*/ -#ifndef STC_SUMTYPE_H_INCLUDED -#define STC_SUMTYPE_H_INCLUDED - -#include "../common.h" - -#define _c_EMPTY() -#define _c_LOOP_INDIRECTION() c_LOOP -#define _c_LOOP_END_1 ,_c_LOOP1 -#define _c_LOOP0(f,T,x,...) f c_EXPAND((T, c_EXPAND x)) _c_LOOP_INDIRECTION _c_EMPTY()()(f,T,__VA_ARGS__) -#define _c_LOOP1(...) -#define _c_CHECK(x,...) c_TUPLE_AT_1(__VA_ARGS__,x,) -#define _c_E0(...) __VA_ARGS__ -#define _c_E1(...) _c_E0(_c_E0(_c_E0(_c_E0(_c_E0(_c_E0(__VA_ARGS__)))))) -#define _c_E2(...) _c_E1(_c_E1(_c_E1(_c_E1(_c_E1(_c_E1(__VA_ARGS__)))))) -#define c_EVAL(...) _c_E2(_c_E2(_c_E2(__VA_ARGS__))) // currently supports up to 130 variants -#define c_LOOP(f,T,x,...) _c_CHECK(_c_LOOP0, c_JOIN(_c_LOOP_END_, c_NUMARGS(c_EXPAND x)))(f,T,x,__VA_ARGS__) - - -#define _c_enum_1(x,...) (x=__LINE__*1000, __VA_ARGS__) -#define _c_vartuple_tag(T, Tag, ...) Tag, -#define _c_vartuple_type(T, Tag, ...) typedef __VA_ARGS__ Tag##_type; typedef T Tag##_sumtype; -#define _c_vartuple_var(T, Tag, ...) struct { enum enum_##T tag; Tag##_type get; } Tag; - -#define c_union(T, ...) \ - typedef union T T; \ - enum enum_##T { c_EVAL(c_LOOP(_c_vartuple_tag, T, _c_enum_1 __VA_ARGS__, (0),)) }; \ - c_EVAL(c_LOOP(_c_vartuple_type, T, __VA_ARGS__, (0),)) \ - union T { \ - struct { enum enum_##T tag; } _any_; \ - c_EVAL(c_LOOP(_c_vartuple_var, T, __VA_ARGS__, (0),)) \ - } -#define c_sumtype c_union - -#if defined STC_HAS_TYPEOF && STC_HAS_TYPEOF - #define c_when(varptr) \ - for (__typeof__(varptr) _vp1 = (varptr); _vp1; _vp1 = NULL) \ - switch (_vp1->_any_.tag) - - #define c_is_2(Tag, x) \ - break; case Tag: \ - for (__typeof__(_vp1->Tag.get)* x = &_vp1->Tag.get; x; x = NULL) - - #define c_is_3(varptr, Tag, x) \ - false) ; else for (__typeof__(varptr) _vp2 = (varptr); _vp2; _vp2 = NULL) \ - if (c_is_variant(_vp2, Tag)) \ - for (__typeof__(_vp2->Tag.get) *x = &_vp2->Tag.get; x; x = NULL -#else - typedef union { struct { int tag; } _any_; } _c_any_variant; - #define c_when(varptr) \ - for (_c_any_variant* _vp1 = (_c_any_variant *)(varptr); \ - _vp1; _vp1 = NULL, (void)sizeof((varptr)->_any_.tag)) \ - switch (_vp1->_any_.tag) - - #define c_is_2(Tag, x) \ - break; case Tag: \ - for (Tag##_type *x = &((Tag##_sumtype *)_vp1)->Tag.get; x; x = NULL) - - #define c_is_3(varptr, Tag, x) \ - false) ; else for (Tag##_sumtype* _vp2 = c_const_cast(Tag##_sumtype*, varptr); _vp2; _vp2 = NULL) \ - if (c_is_variant(_vp2, Tag)) \ - for (Tag##_type *x = &_vp2->Tag.get; x; x = NULL -#endif - -// Handling multiple tags with different payloads: -#define c_is(...) c_MACRO_OVERLOAD(c_is, __VA_ARGS__) -#define c_is_1(Tag) \ - break; case Tag: - -#define c_or_is(Tag) \ - ; case Tag: - -// Type checked multiple tags with same payload: -#define c_is_same(...) c_MACRO_OVERLOAD(c_is_same, __VA_ARGS__) -#define _c_chk(Tag1, Tag2) \ - case 1 ? Tag1 : sizeof((Tag1##_type*)0 == (Tag2##_type*)0): -#define c_is_same_2(Tag1, Tag2) \ - break; _c_chk(Tag1, Tag2) case Tag2: -#define c_is_same_3(Tag1, Tag2, Tag3) \ - break; _c_chk(Tag1, Tag2) _c_chk(Tag2, Tag3) case Tag3: -#define c_is_same_4(Tag1, Tag2, Tag3, Tag4) \ - break; _c_chk(Tag1, Tag2) _c_chk(Tag2, Tag3) _c_chk(Tag3, Tag4) case Tag4: - -#define c_otherwise \ - break; default: - -#define c_variant(Tag, ...) \ - (c_literal(Tag##_sumtype){.Tag={.tag=Tag, .get=__VA_ARGS__}}) - -#define c_is_variant(varptr, Tag) \ - ((varptr)->Tag.tag == Tag) - -#define c_get_if(varptr, Tag) \ - (c_is_variant(varptr, Tag) ? &(varptr)->Tag.get : NULL) - -#define c_variant_id(varptr) \ - ((int)(varptr)->_any_.tag) - -#endif // STC_SUMTYPE_H_INCLUDED diff --git a/src/finchlite/codegen/stc/include/stc/sys/utility.h b/src/finchlite/codegen/stc/include/stc/sys/utility.h deleted file mode 100644 index b4ed1b64..00000000 --- a/src/finchlite/codegen/stc/include/stc/sys/utility.h +++ /dev/null @@ -1,188 +0,0 @@ -/* 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. -*/ -// IWYU pragma: private, include "stc/algorithm.h" -#ifndef STC_UTILITY_H_INCLUDED -#define STC_UTILITY_H_INCLUDED - -// -------------------------------- -// c_find_if, c_find_reverse_if -// -------------------------------- - -#define c_find_if(...) c_MACRO_OVERLOAD(c_find_if, __VA_ARGS__) -#define c_find_if_4(C, cnt, outit_ptr, pred) \ - _c_find(C, C##_begin(&cnt), NULL, _, outit_ptr, pred) - -#define c_find_if_5(C, start, finish, outit_ptr, pred) \ - _c_find(C, start, (finish).ref, _, outit_ptr, pred) - -#define c_find_reverse_if(...) c_MACRO_OVERLOAD(c_find_reverse_if, __VA_ARGS__) -#define c_find_reverse_if_4(C, cnt, outit_ptr, pred) \ - _c_find(C, C##_rbegin(&cnt), NULL, _r, outit_ptr, pred) - -#define c_find_reverse_if_5(C, rstart, rfinish, outit_ptr, pred) \ - _c_find(C, rstart, (rfinish).ref, _r, outit_ptr, pred) - -// private -#define _c_find(C, start, endref, rev, outit_ptr, pred) do { \ - C##_iter* _out = outit_ptr; \ - const C##_value *value, *_endref = endref; \ - for (*_out = start; (value = _out->ref) != _endref; C##rev##next(_out)) \ - if (pred) goto c_JOIN(findif_, __LINE__); \ - _out->ref = NULL; c_JOIN(findif_, __LINE__):; \ -} while (0) - -// -------------------------------- -// c_reverse -// -------------------------------- - -#define c_reverse_array(array, n) do { \ - typedef struct { char d[sizeof 0[array]]; } _etype; \ - _etype* _arr = (_etype *)(array); \ - for (isize _i = 0, _j = (n) - 1; _i < _j; ++_i, --_j) \ - c_swap(_arr + _i, _arr + _j); \ -} while (0) - -// Compiles with vec, stack, and deque, and cspan container types: -#define c_reverse(CntType, self) do { \ - CntType* _self = self; \ - for (isize _i = 0, _j = CntType##_size(_self) - 1; _i < _j; ++_i, --_j) \ - c_swap(CntType##_at_mut(_self, _i), CntType##_at_mut(_self, _j)); \ -} while (0) - -// -------------------------------- -// c_erase_if -// -------------------------------- - -// Use with: list, hashmap, hashset, sortedmap, sortedset: -#define c_erase_if(C, cnt_ptr, pred) do { \ - C* _cnt = cnt_ptr; \ - const C##_value* value; \ - for (C##_iter _it = C##_begin(_cnt); (value = _it.ref); ) { \ - if (pred) _it = C##_erase_at(_cnt, _it); \ - else C##_next(&_it); \ - } \ -} while (0) - -// -------------------------------- -// c_eraseremove_if -// -------------------------------- - -// Use with: stack, vec, deque, queue: -#define c_eraseremove_if(C, cnt_ptr, pred) do { \ - C* _cnt = cnt_ptr; \ - isize _n = 0; \ - const C##_value* value; \ - C##_iter _i, _it = C##_begin(_cnt); \ - while ((value = _it.ref) && !(pred)) \ - C##_next(&_it); \ - for (_i = _it; (value = _it.ref); C##_next(&_it)) { \ - if (pred) C##_value_drop(_cnt, _it.ref), ++_n; \ - else *_i.ref = *_it.ref, C##_next(&_i); \ - } \ - C##_adjust_end_(_cnt, -_n); \ -} while (0) - -// -------------------------------- -// c_copy_to, c_copy_if -// -------------------------------- - -#define c_copy_to(...) c_MACRO_OVERLOAD(c_copy_to, __VA_ARGS__) -#define c_copy_to_3(C, outcnt_ptr, cnt) \ - _c_copy_if(C, outcnt_ptr, _, C, cnt, true) - -#define c_copy_to_4(C_out, outcnt_ptr, C, cnt) \ - _c_copy_if(C_out, outcnt_ptr, _, C, cnt, true) - -#define c_copy_if(...) c_MACRO_OVERLOAD(c_copy_if, __VA_ARGS__) -#define c_copy_if_4(C, outcnt_ptr, cnt, pred) \ - _c_copy_if(C, outcnt_ptr, _, C, cnt, pred) - -#define c_copy_if_5(C_out, outcnt_ptr, C, cnt, pred) \ - _c_copy_if(C_out, outcnt_ptr, _, C, cnt, pred) - -// private -#define _c_copy_if(C_out, outcnt_ptr, rev, C, cnt, pred) do { \ - C_out *_out = outcnt_ptr; \ - C _cnt = cnt; \ - const C##_value* value; \ - for (C##_iter _it = C##rev##begin(&_cnt); (value = _it.ref); C##rev##next(&_it)) \ - if (pred) C_out##_push(_out, C_out##_value_clone(_out, *_it.ref)); \ -} while (0) - -// -------------------------------- -// c_all_of, c_any_of, c_none_of -// -------------------------------- - -#define c_all_of(C, cnt, outbool_ptr, pred) do { \ - C##_iter _it; \ - c_find_if_4(C, cnt, &_it, !(pred)); \ - *(outbool_ptr) = _it.ref == NULL; \ -} while (0) - -#define c_any_of(C, cnt, outbool_ptr, pred) do { \ - C##_iter _it; \ - c_find_if_4(C, cnt, &_it, pred); \ - *(outbool_ptr) = _it.ref != NULL; \ -} while (0) - -#define c_none_of(C, cnt, outbool_ptr, pred) do { \ - C##_iter _it; \ - c_find_if_4(C, cnt, &_it, pred); \ - *(outbool_ptr) = _it.ref == NULL; \ -} while (0) - -// -------------------------------- -// c_min, c_max, c_min_n, c_max_n -// -------------------------------- -#define _c_minmax_call(fn, T, ...) \ - fn(c_make_array(T, {__VA_ARGS__}), c_sizeof((T[]){__VA_ARGS__})/c_sizeof(T)) - -#define c_min(...) _c_minmax_call(c_min_n, isize, __VA_ARGS__) -#define c_umin(...) _c_minmax_call(c_umin_n, size_t, __VA_ARGS__) -#define c_min32(...) _c_minmax_call(c_min32_n, int32_t, __VA_ARGS__) -#define c_fmin(...) _c_minmax_call(c_fmin_n, float, __VA_ARGS__) -#define c_dmin(...) _c_minmax_call(c_dmin_n, double, __VA_ARGS__) -#define c_max(...) _c_minmax_call(c_max_n, isize, __VA_ARGS__) -#define c_umax(...) _c_minmax_call(c_umax_n, size_t, __VA_ARGS__) -#define c_max32(...) _c_minmax_call(c_max32_n, int32_t, __VA_ARGS__) -#define c_fmax(...) _c_minmax_call(c_fmax_n, float, __VA_ARGS__) -#define c_dmax(...) _c_minmax_call(c_dmax_n, double, __VA_ARGS__) - -#define _c_minmax_def(fn, T, opr) \ - static inline T fn(const T a[], isize n) { \ - T x = a[0]; \ - for (isize i = 1; i < n; ++i) if (a[i] opr x) x = a[i]; \ - return x; \ - } -_c_minmax_def(c_min32_n, int32_t, <) -_c_minmax_def(c_min_n, isize, <) -_c_minmax_def(c_umin_n, size_t, <) -_c_minmax_def(c_fmin_n, float, <) -_c_minmax_def(c_dmin_n, double, <) -_c_minmax_def(c_max32_n, int32_t, >) -_c_minmax_def(c_max_n, isize, >) -_c_minmax_def(c_umax_n, size_t, >) -_c_minmax_def(c_fmax_n, float, >) -_c_minmax_def(c_dmax_n, double, >) - -#endif // STC_UTILITY_H_INCLUDED diff --git a/src/finchlite/codegen/stc/include/stc/types.h b/src/finchlite/codegen/stc/include/stc/types.h deleted file mode 100644 index 73af610c..00000000 --- a/src/finchlite/codegen/stc/include/stc/types.h +++ /dev/null @@ -1,223 +0,0 @@ -/* 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_TYPES_H_INCLUDED -#define STC_TYPES_H_INCLUDED - -#include -#include -#include - -#define declare_rc(C, KEY) declare_arc(C, KEY) -#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, KEY, VAL, c_true, c_false,) -#define declare_hashset(C, KEY) _declare_htable(C, KEY, KEY, c_false, c_true,) -#define declare_sortedmap(C, KEY, VAL) _declare_aatree(C, KEY, VAL, c_true, c_false,) -#define declare_sortedset(C, KEY) _declare_aatree(C, KEY, KEY, c_false, c_true,) - -#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, AUX) _declare_htable(C, KEY, VAL, c_true, c_false, AUX aux;) -#define declare_hashset_aux(C, KEY, AUX) _declare_htable(C, KEY, KEY, c_false, c_true, AUX aux;) -#define declare_sortedmap_aux(C, KEY, VAL, AUX) _declare_aatree(C, KEY, VAL, c_true, c_false, AUX aux;) -#define declare_sortedset_aux(C, KEY, AUX) _declare_aatree(C, KEY, KEY, c_false, c_true, AUX aux;) - -// csview : non-null terminated string view -typedef const char csview_value; -typedef struct csview { - csview_value* buf; - ptrdiff_t size; -} csview; - -typedef union { - csview_value* ref; - csview chr; - struct { csview chr; csview_value* end; } u8; -} csview_iter; - -#define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) -#define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal)) -#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 { - zsview_value* ref; - csview chr; -} 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_buf *a, *b, *c; } _dummy; - struct { cstr_value* data; uintptr_t size; uintptr_t ncap; } lon; - struct { cstr_value data[ sizeof(cstr_buf) - 1 ]; uint8_t size; } sml; -} cstr; - -typedef union { - csview chr; // utf8 character/codepoint - const cstr_value* ref; -} cstr_iter; - -#define c_true(...) __VA_ARGS__ -#define c_false(...) - -#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, KEY, VAL, MAP_ONLY, SET_ONLY, 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, KEY, VAL, MAP_ONLY, SET_ONLY, 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_stack_fixed(SELF, VAL, CAP) \ - typedef VAL SELF##_value; \ - typedef struct { SELF##_value *ref, *end; } SELF##_iter; \ - typedef struct SELF { SELF##_value data[CAP]; ptrdiff_t size; } 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 diff --git a/src/finchlite/codegen/stc/include/stc/utf8.h b/src/finchlite/codegen/stc/include/stc/utf8.h deleted file mode 100644 index 3f91b652..00000000 --- a/src/finchlite/codegen/stc/include/stc/utf8.h +++ /dev/null @@ -1,37 +0,0 @@ -/* 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. - */ -#include "priv/linkage.h" - -#ifndef STC_UTF8_H_INCLUDED -#define STC_UTF8_H_INCLUDED - -#include "common.h" // IWYU pragma: keep -#include "types.h" -#include "priv/utf8_prv.h" // IWYU pragma: keep - -#endif // STC_UTF8_H_INCLUDED - -#if defined i_implement - #include "priv/utf8_prv.c" -#endif -#include "priv/linkage2.h" diff --git a/src/finchlite/codegen/stc/include/stc/vec.h b/src/finchlite/codegen/stc/include/stc/vec.h deleted file mode 100644 index bf5f7faa..00000000 --- a/src/finchlite/codegen/stc/include/stc/vec.h +++ /dev/null @@ -1,397 +0,0 @@ -/* 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. - */ - -/* -#define i_implement -#include -#include - -declare_vec(vec_i32, int); - -typedef struct MyStruct { - vec_i32 int_vec; - cstr name; -} MyStruct; - -#define i_key float -#include - -#define i_keypro cstr // cstr is a "pro"-type -#include - -#define T vec_i32, int32_t, (c_declared) -#include - -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 - -#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 cap); -STC_API bool _c_MEMB(_resize)(Self* self, isize size, _m_value null); -STC_API _m_iter _c_MEMB(_erase_n)(Self* self, isize idx, isize n); -STC_API _m_iter _c_MEMB(_insert_uninit)(Self* self, isize idx, isize 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 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 idx, const _m_raw raw[], isize 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 idx, const _m_value arr[], isize 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 _c_MEMB(_size)(const Self* self) { return self->size; } -STC_INLINE isize _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 cap) - { Self out = {_i_new_n(_m_value, cap), 0, cap}; return out; } - - STC_INLINE Self _c_MEMB(_with_size_uninit)(isize size) - { Self out = {_i_new_n(_m_value, size), size, size}; return out; } - - STC_INLINE Self _c_MEMB(_with_size)(isize 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 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_MEMB(_size)(self)); } - -STC_INLINE _m_iter -_c_MEMB(_insert_n)(Self* self, const isize idx, const _m_value arr[], const isize 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 idx) { - c_assert(c_uless(idx, self->size)); return self->data + idx; -} - -STC_INLINE _m_value* _c_MEMB(_at_mut)(Self* self, const isize 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 _c_MEMB(_index)(const Self* self, _m_iter it) - { return (it.ref - self->data); } - -STC_INLINE void _c_MEMB(_adjust_end_)(Self* self, isize 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(_eq)(const Self* self, const Self* other) { - if (self->size != other->size) return false; - for (isize 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 // _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 cap) { - if (cap > self->capacity || (cap && cap == self->size)) { - _m_value* d = (_m_value*)_i_realloc_n(self->data, self->capacity, cap); - if (d == NULL) - return false; - self->data = d; - self->capacity = cap; - } - return self->data != NULL; -} - -STC_DEF bool -_c_MEMB(_resize)(Self* self, const isize len, _m_value null) { - if (!_c_MEMB(_reserve)(self, len)) - return false; - const isize n = self->size; - for (isize i = len; i < n; ++i) - { i_keydrop((self->data + i)); } - for (isize 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 idx, const isize 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 idx, const isize len) { - c_assert(idx + len <= self->size); - _m_value* d = self->data + idx, *p = d, *end = self->data + self->size; - for (isize 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 idx, - const _m_value arr[], const isize 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 idx, const _m_raw raw[], isize 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" diff --git a/src/finchlite/codegen/stc/include/stc/zsview.h b/src/finchlite/codegen/stc/include/stc/zsview.h deleted file mode 100644 index 8afb73a6..00000000 --- a/src/finchlite/codegen/stc/include/stc/zsview.h +++ /dev/null @@ -1,173 +0,0 @@ -/* 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. - */ - -// zsview is a zero-terminated string view. - -#ifndef STC_ZSVIEW_H_INCLUDED -#define STC_ZSVIEW_H_INCLUDED - -#include "common.h" -#include "types.h" -#include "priv/utf8_prv.h" - -#define zsview_init() c_zv("") -#define zsview_clone(zs) c_default_clone(zs) -#define zsview_drop(self) c_default_drop(self) -#define zsview_toraw(self) (self)->str - -STC_INLINE zsview zsview_from(const char* str) - { return c_literal(zsview){str, c_strlen(str)}; } -STC_INLINE void zsview_clear(zsview* self) { *self = c_zv(""); } -STC_INLINE csview zsview_sv(zsview zs) { return c_sv_2(zs.str, zs.size); } - -STC_INLINE isize zsview_size(zsview zs) { return zs.size; } -STC_INLINE bool zsview_is_empty(zsview zs) { return zs.size == 0; } - -STC_INLINE bool zsview_equals(zsview zs, const char* str) { - isize n = c_strlen(str); - return zs.size == n && !c_memcmp(zs.str, str, n); -} - -STC_INLINE isize zsview_find(zsview zs, const char* search) { - const char* res = strstr(zs.str, search); - return res ? (res - zs.str) : c_NPOS; -} - -STC_INLINE bool zsview_contains(zsview zs, const char* str) - { return zsview_find(zs, str) != c_NPOS; } - -STC_INLINE bool zsview_starts_with(zsview zs, const char* str) { - isize n = c_strlen(str); - return n <= zs.size && !c_memcmp(zs.str, str, n); -} - -STC_INLINE bool zsview_ends_with(zsview zs, const char* str) { - isize n = c_strlen(str); - return n <= zs.size && !c_memcmp(zs.str + zs.size - n, str, n); -} - -STC_INLINE zsview zsview_from_pos(zsview zs, isize pos) { - if (pos > zs.size) pos = zs.size; - zs.str += pos; zs.size -= pos; return zs; -} - -STC_INLINE csview zsview_subview(zsview zs, isize pos, isize len) { - c_assert(((size_t)pos <= (size_t)zs.size) & (len >= 0)); - if (pos + len > zs.size) len = zs.size - pos; - return c_literal(csview){zs.str + pos, len}; -} - -STC_INLINE zsview zsview_tail(zsview zs, isize len) { - c_assert(len >= 0); - if (len > zs.size) len = zs.size; - zs.str += zs.size - len; zs.size = len; - return zs; -} - -/* utf8 */ - -STC_INLINE zsview zsview_u8_from_pos(zsview zs, isize u8pos) - { return zsview_from_pos(zs, utf8_to_index(zs.str, u8pos)); } - -STC_INLINE zsview zsview_u8_tail(zsview zs, isize u8len) { - const char* p = &zs.str[zs.size]; - while (u8len && p != zs.str) - u8len -= (*--p & 0xC0) != 0x80; - zs.size -= p - zs.str, zs.str = p; - return zs; -} - -STC_INLINE csview zsview_u8_subview(zsview zs, isize u8pos, isize u8len) - { return utf8_subview(zs.str, u8pos, u8len); } - -STC_INLINE zsview_iter zsview_u8_at(zsview zs, isize u8pos) { - csview sv; - sv.buf = utf8_at(zs.str, u8pos); - sv.size = utf8_chr_size(sv.buf); - return c_literal(zsview_iter){.chr = sv}; -} - -STC_INLINE isize zsview_u8_size(zsview zs) - { return utf8_count(zs.str); } - -STC_INLINE bool zsview_u8_valid(zsview zs) // requires linking with utf8 symbols - { return utf8_valid_n(zs.str, zs.size); } - -/* utf8 iterator */ - -STC_INLINE zsview_iter zsview_begin(const zsview* self) { - zsview_iter it = {.chr = {self->str, utf8_chr_size(self->str)}}; return it; -} - -STC_INLINE zsview_iter zsview_end(const zsview* self) { - (void)self; zsview_iter it = {0}; return it; -} - -STC_INLINE void zsview_next(zsview_iter* it) { - it->ref += it->chr.size; - it->chr.size = utf8_chr_size(it->ref); - if (*it->ref == '\0') it->ref = NULL; -} - -STC_INLINE zsview_iter zsview_advance(zsview_iter it, isize u8pos) { - it.ref = utf8_offset(it.ref, u8pos); - it.chr.size = utf8_chr_size(it.ref); - if (*it.ref == '\0') it.ref = NULL; - return it; -} - -/* ---- Container helper functions ---- */ - -STC_INLINE size_t zsview_hash(const zsview *self) - { return c_hash_str(self->str); } - -STC_INLINE int zsview_cmp(const zsview* x, const zsview* y) - { return strcmp(x->str, y->str); } - -STC_INLINE bool zsview_eq(const zsview* x, const zsview* y) - { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } - -STC_INLINE int zsview_icmp(const zsview* x, const zsview* y) - { return utf8_icmp(x->str, y->str); } - -STC_INLINE bool zsview_ieq(const zsview* x, const zsview* y) - { return x->size == y->size && !utf8_icmp(x->str, y->str); } - -/* ---- case insensitive ---- */ - -STC_INLINE bool zsview_iequals(zsview zs, const char* str) - { return c_strlen(str) == zs.size && !utf8_icmp(zs.str, str); } - -STC_INLINE bool zsview_istarts_with(zsview zs, const char* str) - { return c_strlen(str) <= zs.size && !utf8_icmp(zs.str, str); } - -STC_INLINE bool zsview_iends_with(zsview zs, const char* str) { - isize n = c_strlen(str); - return n <= zs.size && !utf8_icmp(zs.str + zs.size - n, str); -} - -#endif // STC_ZSVIEW_H_INCLUDED - -#if defined i_import - #include "priv/utf8_prv.c" -#endif diff --git a/src/finchlite/codegen/stc/meson.build b/src/finchlite/codegen/stc/meson.build deleted file mode 100644 index bbc7c6d2..00000000 --- a/src/finchlite/codegen/stc/meson.build +++ /dev/null @@ -1,175 +0,0 @@ -project( - 'stc', - 'c', - version: '5.0-dev', - license: 'MIT', - default_options: ['c_std=c11', 'warning_level=3', 'default_library=static'], - meson_version: '>=1.1', -) - -stcversion = 5 -cc = meson.get_compiler('c') - -if cc.get_argument_syntax() == 'gcc' - add_project_arguments( - cc.get_supported_arguments( - '-Wno-missing-field-initializers', - '-Wno-double-promotion', - '-Wno-stringop-overflow', - '-Wno-clobbered', - ), - language: ['c', 'cpp'], - ) -elif cc.get_argument_syntax() == 'msvc' - # no "unsecure" funcs warnings - add_project_arguments( - cc.get_supported_arguments( - '-wd4996', - ), - language: ['c', 'cpp'], - ) -endif - -libsrc = files( - 'src/cregex.c', - 'src/cspan.c', - 'src/cstr_core.c', - 'src/cstr_io.c', - 'src/cstr_utf8.c', - 'src/csview.c', - 'src/fmt.c', - 'src/random.c', - 'src/stc_core.c', -) - -inc = include_directories('include') - -if cc.get_id() == 'msvc' - # only static library for MSVC atm. - stc_lib = static_library( - 'stc', - libsrc, - name_prefix: '', - name_suffix: 'lib', - include_directories: inc, - install: true, - ) -else - m_dep = cc.find_library('m', required: false) - - stc_lib = library( - 'stc', - libsrc, - dependencies: [m_dep], - soversion: stcversion, - include_directories: inc, - install: true, - ) - - import('pkgconfig').generate( - stc_lib, - name: 'stc', - description: 'A modern, user friendly, generic, type-safe and fast C99 container library.', - url: 'https://github.com/stclib/STC', - ) -endif - -install_headers( - 'include/stc/algorithm.h', - 'include/stc/arc.h', - 'include/stc/box.h', - 'include/stc/cbits.h', - 'include/stc/common.h', - 'include/stc/coption.h', - 'include/stc/coroutine.h', - 'include/stc/cregex.h', - 'include/stc/cspan.h', - 'include/stc/cstr.h', - 'include/stc/csview.h', - 'include/stc/deque.h', - 'include/stc/hmap.h', - 'include/stc/hset.h', - 'include/stc/hashmap.h', - 'include/stc/hashset.h', - 'include/stc/list.h', - 'include/stc/pqueue.h', - 'include/stc/queue.h', - 'include/stc/random.h', - 'include/stc/rc.h', - 'include/stc/smap.h', - 'include/stc/sset.h', - 'include/stc/sortedmap.h', - 'include/stc/sortedset.h', - 'include/stc/sort.h', - 'include/stc/stack.h', - 'include/stc/types.h', - 'include/stc/utf8.h', - 'include/stc/vec.h', - 'include/stc/zsview.h', - subdir: 'stc', -) - -install_headers( - 'include/stc/sys/crange.h', - 'include/stc/sys/filter.h', - 'include/stc/sys/sumtype.h', - 'include/stc/sys/utility.h', - subdir: 'stc/sys', -) - -install_headers( - 'include/stc/priv/cstr_prv.h', - 'include/stc/priv/linkage.h', - 'include/stc/priv/linkage2.h', - 'include/stc/priv/queue_prv.h', - 'include/stc/priv/sort_prv.h', - 'include/stc/priv/template.h', - 'include/stc/priv/template2.h', - 'include/stc/priv/utf8_prv.h', - subdir: 'stc/priv', -) - -install_headers( - 'include/c11/fmt.h', - subdir: 'c11', -) - -stc_dep = declare_dependency( - link_with: [stc_lib], - include_directories: inc, -) - -meson.override_dependency('stc', stc_dep) - -flex_exe = find_program('flex', 'win_flex', required: get_option('checkscoped')) -if flex_exe.found() - lex_src = custom_target( - 'checkscoped_lex', - command: [flex_exe, '-o', '@OUTPUT@', files('src/checkscoped.l')], - output: 'lex.yy.c', - ) - checkscoped_exe = executable( - 'checkscoped', - lex_src, - native: true, - ) - meson.override_find_program('checkscoped', checkscoped_exe) -endif - -root = not meson.is_subproject() -subdir('tests') -subdir('examples') - -if root - datadir = get_option('datadir') - docdir = get_option('docdir') - if docdir == '' - docdir = datadir / 'doc' / meson.project_name() - endif - - install_subdir( - 'docs', - install_dir: docdir, - strip_directory: true, - ) -endif diff --git a/src/finchlite/codegen/stc/meson_options.txt b/src/finchlite/codegen/stc/meson_options.txt deleted file mode 100644 index e5a737ef..00000000 --- a/src/finchlite/codegen/stc/meson_options.txt +++ /dev/null @@ -1,20 +0,0 @@ -option( - 'checkscoped', - type: 'feature', - value: 'auto', - description: 'Build checkscoped tool for c_guard* blocks', -) -option( - 'tests', - type: 'feature', - value: 'auto', - description: 'Build tests and ctest', -) -option( - 'examples', - type: 'feature', - value: 'auto', - description: 'Build examples', -) - -option('docdir', type: 'string', description: 'documentation directory') diff --git a/src/finchlite/codegen/stc/src/checkscoped.l b/src/finchlite/codegen/stc/src/checkscoped.l deleted file mode 100644 index 652264de..00000000 --- a/src/finchlite/codegen/stc/src/checkscoped.l +++ /dev/null @@ -1,131 +0,0 @@ -/* Check for illegal return/break/continue usage inside a STC-lib c_defer/c_with block (RAII). - * Copyright Tyge Løvset, (c) 2025. - */ -%{ -#include -enum Block { LOOP=1<<0, DEFER=1<<1 }; -enum State { NORMAL, BRACES, BRACESDONE }; -static int braces_lev = 0, block_lev = 0; -static enum State state = NORMAL; -static unsigned char block[64] = {0}, block_type = 0; -const char* fname; -int errors = 0, warnings = 0; -%} - -ID [_a-zA-Z][_a-zA-Z0-9]* -STR \"([^"\\]|\\.)*\" - -%option never-interactive noyymore noyywrap nounistd -%x cmt -%x prep - -%% -\/\/.* ; // line cmt -\/\* BEGIN(cmt); -\n ++yylineno; -\*\/ BEGIN(INITIAL); -. ; -^[ \t]*#.*\\\n { ++yylineno; BEGIN(prep); } -.*\\\n ++yylineno; -.* BEGIN(INITIAL); -^[ \t]*#.* ; -{STR} ; -'\\?.' ; -c_foreach_reverse | -c_foreach_kv | -c_foreach | -c_forrange | -c_forrange32 | -c_forrange_t | -c_fortoken_sv | -c_fortoken | -c_formatch | -c_forfilter_reverse_from | -c_forfilter_reverse | -c_forfilter_from | -c_forfilter | -for | -while | -switch { block_type |= LOOP; state = BRACES; } -do { block_type |= LOOP; state = BRACESDONE; } -c_with | -c_defer { block_type = DEFER; state = BRACES; } -\( { if (state == BRACES) ++braces_lev; } -\) { if (state == BRACES && --braces_lev == 0) - state = BRACESDONE; - } -if { if (state == BRACESDONE) { - if (block_type == DEFER) { - printf("%s:%d: warning: 'if' after c_defer/c_with not enclosed in curly braces.\n" - " Make sure to enclose 'if - else' statement in { } after c_defer/c_with.\n", - fname, yylineno); - ++warnings; - } - state = BRACES; - } - } -;[ \t]*else ; -; { if (state == BRACESDONE) { - block_type = block[block_lev]; - state = NORMAL; - } - } -\{ { if (state != BRACES) { block[++block_lev] = block_type; state = NORMAL; } } -\} { if (state != BRACES) block_type = block[--block_lev]; } -return { if (block_type == DEFER) { - printf("%s:%d: error: 'return' used inside a c_defer/c_with scope.\n" - " Use 'continue' to exit the current c_defer/c_with before return.\n" - , fname, yylineno); - ++errors; - } else if (block_type & DEFER) { - printf("%s:%d: error: 'return' used in a loop inside a c_defer/c_with scope.\n" - " Use 'break' to exit loop, then 'continue' to exit c_defer/c_with.\n" - , fname, yylineno); - ++errors; - } - } -break { if (block_type == DEFER) { - printf("%s:%d: error: 'break' used inside a c_defer/c_with scope.\n" - " Use 'continue' to exit the current c_defer/c_with.\n" - , fname, yylineno); - ++errors; - } - } -{ID} ; -\n ++yylineno; -. ; - -%% - -#include - -int main(int argc, char **argv) -{ - if (argc == 1 || strcmp(argv[1], "--help") == 0) { - printf("C-language source code checker for correct usage of STClib c_defer() / c_with().\n"); - printf("Usage: %s {C-file... | -}\n", argv[0]); - return 0; - } - - for (int i=1; i= 201112L - #define i_implement - #include "../include/c11/fmt.h" -#endif diff --git a/src/finchlite/codegen/stc/src/random.c b/src/finchlite/codegen/stc/src/random.c deleted file mode 100644 index 8764aed3..00000000 --- a/src/finchlite/codegen/stc/src/random.c +++ /dev/null @@ -1,2 +0,0 @@ -#define i_implement -#include "../include/stc/random.h" diff --git a/src/finchlite/codegen/stc/src/singleheader.py b/src/finchlite/codegen/stc/src/singleheader.py deleted file mode 100644 index a062c88d..00000000 --- a/src/finchlite/codegen/stc/src/singleheader.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python3 - -import re -import sys -import os -from os.path import dirname, join as path_join, abspath, basename, exists - -top_dir = dirname(abspath(__file__)) -extra_paths = [path_join(top_dir, 'include'), path_join(top_dir, '..', 'include')] - -def find_file(included_name, current_file): - current_dir = dirname(abspath(current_file)) - for idir in [current_dir] + extra_paths: - try_path = path_join(idir, included_name) - if exists(try_path): - return abspath(try_path) - return None - - -def process_file( - file_path, - out_lines=[], - processed_files=[], -): - out_lines += "// ### BEGIN_FILE_INCLUDE: " + basename(file_path) + '\n' - comment_block = False - with open(file_path, "r", encoding="utf-8") as f: - for line in f: - is_comment = comment_block - if re.search('/\\*.*?\\*/', line): - pass - elif re.search('^\\s*/\\*', line): - comment_block, is_comment = True, True - elif re.search('\\*/', line): - comment_block = False - - if is_comment: - continue - - m_inc = re.search('^\\s*# *include\\s*[<"](.+)[>"]', line) if not is_comment else False - if m_inc: - inc_name = m_inc.group(1) - inc_path = find_file(inc_name, file_path) - if inc_path not in processed_files: - if inc_path is not None: - processed_files += [inc_path] - process_file( - inc_path, - out_lines, - processed_files, - ) - else: - # assume it's a system header - out_lines += [line] - continue - m_once = re.match('^\\s*# *pragma once\\s*', line) if not is_comment else False - # ignore pragma once; we're handling it here - if m_once: - continue - # otherwise, just add the line to the output - if line[-1] != '\n': - line += '\n' - out_lines += [line] - out_lines += "// ### END_FILE_INCLUDE: " + basename(file_path) + '\n' - return ( - "".join(out_lines) - ) - - -if __name__ == "__main__": - with open(sys.argv[2], "w", newline='\n', encoding="utf-8") as f: - print( - process_file( - abspath(sys.argv[1]), - [], - # We use an include guard instead of `#pragma once` because Godbolt will - # cause complaints about `#pragma once` when they are used in URL includes. - [abspath(sys.argv[1])], - ), - file=f - ) diff --git a/src/finchlite/codegen/stc/src/singleupdate.sh b/src/finchlite/codegen/stc/src/singleupdate.sh deleted file mode 100644 index 39f024bf..00000000 --- a/src/finchlite/codegen/stc/src/singleupdate.sh +++ /dev/null @@ -1,29 +0,0 @@ -d=$(git rev-parse --show-toplevel) -mkdir -p $d/../stcsingle/c11 -python singleheader.py $d/include/c11/fmt.h $d/../stcsingle/c11/fmt.h -python singleheader.py $d/include/stc/algorithm.h $d/../stcsingle/stc/algorithm.h -python singleheader.py $d/include/stc/coroutine.h $d/../stcsingle/stc/coroutine.h -python singleheader.py $d/include/stc/sort.h $d/../stcsingle/stc/sort.h -python singleheader.py $d/include/stc/random.h $d/../stcsingle/stc/random.h -python singleheader.py $d/include/stc/arc.h $d/../stcsingle/stc/arc.h -python singleheader.py $d/include/stc/cbits.h $d/../stcsingle/stc/cbits.h -python singleheader.py $d/include/stc/box.h $d/../stcsingle/stc/box.h -python singleheader.py $d/include/stc/common.h $d/../stcsingle/stc/common.h -python singleheader.py $d/include/stc/deque.h $d/../stcsingle/stc/deque.h -python singleheader.py $d/include/stc/list.h $d/../stcsingle/stc/list.h -python singleheader.py $d/include/stc/hmap.h $d/../stcsingle/stc/hmap.h -python singleheader.py $d/include/stc/coption.h $d/../stcsingle/stc/coption.h -python singleheader.py $d/include/stc/pqueue.h $d/../stcsingle/stc/pqueue.h -python singleheader.py $d/include/stc/queue.h $d/../stcsingle/stc/queue.h -python singleheader.py $d/include/stc/cregex.h $d/../stcsingle/stc/cregex.h -python singleheader.py $d/include/stc/hset.h $d/../stcsingle/stc/hset.h -python singleheader.py $d/include/stc/smap.h $d/../stcsingle/stc/smap.h -python singleheader.py $d/include/stc/cspan.h $d/../stcsingle/stc/cspan.h -python singleheader.py $d/include/stc/sset.h $d/../stcsingle/stc/sset.h -python singleheader.py $d/include/stc/stack.h $d/../stcsingle/stc/stack.h -python singleheader.py $d/include/stc/cstr.h $d/../stcsingle/stc/cstr.h -python singleheader.py $d/include/stc/csview.h $d/../stcsingle/stc/csview.h -python singleheader.py $d/include/stc/zsview.h $d/../stcsingle/stc/zsview.h -python singleheader.py $d/include/stc/vec.h $d/../stcsingle/stc/vec.h -python singleheader.py $d/include/stc/types.h $d/../stcsingle/stc/types.h -echo "$d/../stcsingle headers updated" diff --git a/src/finchlite/codegen/stc/src/stc_core.c b/src/finchlite/codegen/stc/src/stc_core.c deleted file mode 100644 index 792293fe..00000000 --- a/src/finchlite/codegen/stc/src/stc_core.c +++ /dev/null @@ -1,2 +0,0 @@ -#define STC_IMPLEMENT -#include "../include/stc/coroutine.h" diff --git a/src/finchlite/codegen/stc/src/utf8_tab.py b/src/finchlite/codegen/stc/src/utf8_tab.py deleted file mode 100644 index 3b17643e..00000000 --- a/src/finchlite/codegen/stc/src/utf8_tab.py +++ /dev/null @@ -1,166 +0,0 @@ -#!python -# To generate "include/stc/priv/utf8_tab.c" file. - -import pandas as pd -import numpy as np - -_UNICODE_DIR = "https://www.unicode.org/Public/15.0.0/ucd" - - -def read_unidata(casetype='lowcase', category='Lu', bitrange=16): - df = pd.read_csv(_UNICODE_DIR+'/UnicodeData.txt', sep=';', converters={0: lambda x: int(x, base=16)}, - names=['code', 'name', 'category', 'canclass', 'bidircat', 'chrdecomp', - 'decdig', 'digval', 'numval', 'mirrored', 'uc1name', 'comment', - 'upcase', 'lowcase', 'titlecase'], - usecols=['code', 'name', 'category', 'bidircat', 'upcase', 'lowcase', 'titlecase']) - if bitrange == 16: - df = df[df['code'] < (1<<16)] - else: - df = df[df['code'] >= (1<<16)] - - if category: - df = df[df['category'] == category] - df = df.replace(np.nan, '0') - for k in ['upcase', 'lowcase', 'titlecase']: - df[k] = df[k].apply(int, base=16) - - if casetype: # 'lowcase', 'upcase', 'titlecase' - df = df[df[casetype] != 0] # remove mappings to 0 - return df - - -def read_casefold(bitrange): - df = pd.read_csv(_UNICODE_DIR+'/CaseFolding.txt', engine='python', sep='; #? ?', comment='#', - converters={0: lambda x: int(x, base=16)}, - names=['code', 'status', 'lowcase', 'name']) # comment => 'name' - if bitrange == 16: - df = df[df['code'] < (1<<16)] - else: - df = df[df['code'] >= (1<<16)] - - df = df[df.status.isin(['S', 'C'])] - df['lowcase'] = df['lowcase'].apply(int, base=16) - return df - - -def make_caselist(df, casetype): - caselist=[] - for idx, row in df.iterrows(): - caselist.append((row['code'], row[casetype], row['name'])) - return caselist - - -def make_table(caselist): - prev_a, prev_b = 0, 0 - diff_a, diff_b = 0, 0 - prev_offs = 0 - n_1 = len(caselist) - 1 - - table = [] - for j in range(0, len(caselist)): - a, b, name = caselist[j] - offset = b - a - - if abs(diff_a) > 2 or a - prev_a != diff_a or b - prev_b != diff_b or prev_offs != offset: - if j > 0: # and start_a not in [0xAB70, 0x13F8]: # BUG in CaseFolding.txt V14 - table.append([start_a, prev_a, prev_b, start_name]) - if j < n_1: - diff_a = caselist[j+1][0] - a - diff_b = caselist[j+1][1] - b - start_a = a - start_name = name - - prev_a, prev_b = a, b - prev_offs = offset - - table.append((start_a, a, b, start_name)) - return table - - -def print_table(name, table, style=1, bitrange=16): - r32 = '32' if bitrange == 32 else '' - print('#include \n') - print('struct CaseMapping%s { uint%d_t c1, c2, m2; };\n' % (r32, bitrange)) - print('static struct CaseMapping%s %s%s[] = {' % (r32, name, r32)) - for a,b,c,t in table: - if style == 1: # first char with name - d = b - a + 1 if abs(c - b) != 1 else (b - a)/2 + 1 - print(' {0x%04X, 0x%04X, 0x%04X}, // %s %s (%2d) %s' % (a, b, c, chr(a), chr(a + c - b), d, t)) - elif style == 2: # all chars - print(' {0x%04X, 0x%04X, 0x%04X}, // ' % (a, b, c), end='') - n = 0 - for k in range(a, b+1, 2 if c - b == 1 else 1): - n += 1 - if n % 17 == 0: - print('\n // ', end='') - print('%s %s, ' % (chr(k), chr(k + c - b)), end='') - print('') - print('}; // %d\n' % (len(table))) - - -def print_index_table(name, indtab): - print('\nstatic uint8_t %s[%d] = {\n ' % (name, len(indtab)), end='') - for i in range(len(indtab)): - print(" %d," % (indtab[i]), end='\n ' if (i+1) % 20 == 0 else '') - print('\n};') - - -def compile_table(casetype='lowcase', category=None, bitrange=16): - if category: - df = read_unidata(casetype, category, bitrange) - else: - df = read_casefold(bitrange) - caselist = make_caselist(df, casetype) - table = make_table(caselist) - return table - - -def main(): - bitrange = 16 - - casemappings = compile_table('lowcase', None, bitrange) # CaseFolding.txt - upcase = compile_table('lowcase', 'Lu', bitrange) # UnicodeData.txt uppercase - lowcase = compile_table('upcase', 'Ll', bitrange) # UnicodeData.txt lowercase - - casefolding_len = len(casemappings) - - # add additional Lu => Ll mappings from UnicodeData.txt - # create upcase_ind: lower => upper index list sorted by mapped lowercase values: - upcase_ind = [] - for v in upcase: - try: - upcase_ind.append(casemappings.index(v)) - except: - upcase_ind.append(len(casemappings)) - casemappings.append(v) - - # add additional Ll => Lu mappings from UnicodeData.txt - # create lowcase_ind: upper => lower index list sorted by uppercase values: - lowcase_ind = [] - for u in lowcase: - v = (u[2] - (u[1] - u[0]), u[2], u[1], '') - try: - j = next(i for i,x in enumerate(casemappings) if x[0]==v[0] and x[1]==v[1] and x[2]==v[2]) - lowcase_ind.append(j) - except: - lowcase_ind.append(len(casemappings)) - casemappings.append(v) - - print_table('casemappings', casemappings, style=1, bitrange=bitrange) - print('enum { casefold_len = %d };' % casefolding_len) - - # upcase => low - upcase_ind.sort(key=lambda i: casemappings[i][0]) - print_index_table('upcase_ind', upcase_ind) - - # lowcase => up. add "missing" SHARP S caused by https://www.unicode.org/policies/stability_policy.html#Case_Pair - if bitrange == 16: - lowcase_ind.append(next(i for i,x in enumerate(casemappings) if x[0]==ord('ẞ'))) - lowcase_ind.sort(key=lambda i: casemappings[i][2] - (casemappings[i][1] - casemappings[i][0])) - print_index_table('lowcase_ind', lowcase_ind) - - -########### main: - -if __name__ == "__main__": - main() diff --git a/src/finchlite/codegen/stc/tests/algorithm_test.c b/src/finchlite/codegen/stc/tests/algorithm_test.c deleted file mode 100644 index 00ca7a38..00000000 --- a/src/finchlite/codegen/stc/tests/algorithm_test.c +++ /dev/null @@ -1,149 +0,0 @@ -// https://mariusbancila.ro/blog/2019/01/20/cpp-code-samples-before-and-after-ranges/ - -#define T IVec, int -#include - -#include -#include -#include -use_cspan(ISpan, int); - -#include "ctest.h" - - -static cstr to_roman(int value) -{ - cstr result = {0}; - struct roman { int d; const char* r; }; - - for (c_items(i, struct roman, { - {1000, "M"}, {900, "CM"}, - {500, "D"}, {400, "CD"}, - {100, "C"}, {90, "XC"}, - {50, "L"}, {40, "XL"}, - {10, "X"}, {9, "IX"}, - {5, "V"}, {4, "IV"}, - {1, "I"} - })){ - while (value >= i.ref->d) { - cstr_append(&result, i.ref->r); - value -= i.ref->d; - } - } - return result; -} - -TEST(algorithm, cstr_append) -{ - c_with (cstr s = to_roman(2024), cstr_drop(&s)) - { - EXPECT_STREQ("MMXXIV", cstr_str(&s)); - } -} - - -TEST(algorithm, c_find_if) -{ - ISpan nums = c_make(ISpan, {1,1,2,3,5,8,13,21,34}); - - ISpan_iter it; - c_find_if(ISpan, nums, &it, *value == 13); - - EXPECT_EQ(13, *it.ref); -} - - -TEST(algorithm, c_filter) -{ - IVec vec = c_make(IVec, {1,1,2,3,5,8,13,21,34,10}); - #define f_is_even(v) ((v & 1) == 0) - #define f_is_odd(v) ((v & 1) == 1) - - isize sum = 0; - c_filter(IVec, vec - , c_flt_skipwhile(f_is_odd(*value)) - && c_flt_skip(1) - && f_is_even(*value) - && c_flt_take(2) - && (sum += *value)); - - EXPECT_EQ(42, sum); - - uint64_t hash = 0; - c_filter(IVec, vec, hash = c_hash_mix(hash, (uint64_t)*value)); - EXPECT_EQ(658, (isize)hash); - - hash = 0; - c_filter_reverse(IVec, vec, hash = c_hash_mix(hash, (uint64_t)*value)); - EXPECT_EQ(10897, (isize)hash); - - sum = 0; - c_filter(IVec, vec, sum += *value); - EXPECT_EQ(98, sum); - - sum = 0; - c_filter_reverse(IVec, vec, sum += *value); - EXPECT_EQ(98, sum); - - sum = 0; - c_filter_zip(IVec, vec, crange, c_iota(-6), sum += *value1 * *value2); - EXPECT_EQ(73, sum); - - IVec_drop(&vec); -} - -// TEST tagged_union: - -c_union (Action, - (ActionSpeak, cstr), - (ActionQuit, bool), - (ActionRunFunc, struct { - int (*func)(int, int); - int v1, v2; - }), -); - -void Action_drop(Action* self) { - if (c_is(self, ActionSpeak, s)) - cstr_drop(s); -} - -static void action(Action* action, cstr* out) { - c_when (action) { - c_is(ActionSpeak, s) { - cstr_printf(out, "Asked to speak: %s\n", cstr_str(s)); - } - c_is(ActionQuit) { - cstr_printf(out, "Asked to quit!\n"); - } - c_is(ActionRunFunc, r) { - int res = r->func(r->v1, r->v2); - cstr_printf(out, "v1: %d, v2: %d, res: %d\n", r->v1, r->v2, res); - } - c_otherwise assert("no match" == NULL); - } -} - -static int add(int a, int b) { - return a + b; -} - -TEST(algorithm, c_union) { - Action act1 = c_variant(ActionSpeak, cstr_from("Hello")); - Action act2 = c_variant(ActionQuit, 1); - Action act3 = c_variant(ActionRunFunc, {add, 5, 6}); - - cstr res = {0}; - action(&act1, &res); - EXPECT_STREQ(cstr_str(&res), "Asked to speak: Hello\n"); - action(&act2, &res); - EXPECT_STREQ(cstr_str(&res), "Asked to quit!\n"); - action(&act3, &res); - EXPECT_STREQ(cstr_str(&res), "v1: 5, v2: 6, res: 11\n"); - - EXPECT_TRUE(c_is_variant(&act1, ActionSpeak)); - EXPECT_STREQ(cstr_str(&act1.ActionSpeak.get), "Hello"); - - c_drop(Action, &act1, &act2, &act3); - c_drop(cstr, &res); -} diff --git a/src/finchlite/codegen/stc/tests/cregex_test.c b/src/finchlite/codegen/stc/tests/cregex_test.c deleted file mode 100644 index 165195d9..00000000 --- a/src/finchlite/codegen/stc/tests/cregex_test.c +++ /dev/null @@ -1,339 +0,0 @@ -#include -#include -#include -#include -#include "ctest.h" -#include - -#define M_START(m) ((m).buf - input) -#define M_END(m) (M_START(m) + (m).size) - - -TEST(cregex, ISO8601_parse_result) -{ - const char* pattern = "(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)"; - const char* input = "2024-02-28"; - csview match[4]; - EXPECT_EQ(cregex_match_aio(pattern, input, match), CREG_OK); - EXPECT_TRUE(csview_equals(match[1], "2024")); - EXPECT_TRUE(csview_equals(match[2], "02")); - EXPECT_TRUE(csview_equals(match[3], "28")); -} - -TEST(cregex, compile_match_char) -{ - const char* input; - cregex re = cregex_from("äsdf"); - EXPECT_EQ(re.error, 0); - - csview match; - EXPECT_EQ(cregex_match(&re, input="äsdf", &match, CREG_FULLMATCH), CREG_OK); - EXPECT_EQ(M_START(match), 0); - EXPECT_EQ(M_END(match), 5); // ä is two bytes wide - - EXPECT_EQ(cregex_match(&re, input="zäsdf", &match), CREG_OK); - EXPECT_EQ(M_START(match), 1); - EXPECT_EQ(M_END(match), 6); - - cregex_drop(&re); -} - -TEST(cregex, compile_match_anchors) -{ - const char* input; - cregex re = cregex_from(input="^äs.f$"); - EXPECT_EQ(re.error, 0); - - csview match; - EXPECT_EQ(cregex_match(&re, input="äsdf", &match), CREG_OK); - EXPECT_EQ(M_START(match), 0); - EXPECT_EQ(M_END(match), 5); - - EXPECT_TRUE(cregex_is_match(&re, "äs♥f")); - EXPECT_TRUE(cregex_is_match(&re, "äsöf")); - - cregex_drop(&re); -} - -TEST(cregex, compile_match_quantifiers1) -{ - const char* input; - c_with (cregex re = {0}, cregex_drop(&re)) { - re = cregex_from("ä+"); - EXPECT_EQ(re.error, 0); - - csview match; - EXPECT_EQ(cregex_match(&re, input="ääb", &match), CREG_OK); - EXPECT_EQ(M_START(match), 0); - EXPECT_EQ(M_END(match), 4); - - EXPECT_EQ(cregex_match(&re, input="bäbb", &match), CREG_OK); - EXPECT_EQ(M_START(match), 1); - EXPECT_EQ(M_END(match), 3); - - EXPECT_EQ(cregex_match(&re, "bbb", &match), CREG_NOMATCH); - } -} - -TEST(cregex, compile_match_quantifiers2) -{ - const char* input; - c_with (cregex re = {0}, cregex_drop(&re)) { - re = cregex_from("bä*"); - EXPECT_EQ(re.error, 0); - - csview match; - EXPECT_EQ(cregex_match(&re, input="bääb", &match), CREG_OK); - EXPECT_EQ(M_START(match), 0); - EXPECT_EQ(M_END(match), 5); - - EXPECT_EQ(cregex_match(&re, input="bäbb", &match), CREG_OK); - EXPECT_EQ(M_START(match), 0); - EXPECT_EQ(M_END(match), 3); - - EXPECT_EQ(cregex_match(&re, input="bbb", &match), CREG_OK); - EXPECT_EQ(M_START(match), 0); - EXPECT_EQ(M_END(match), 1); - } -} - -TEST(cregex, compile_match_escaped_chars) -{ - cregex re = cregex_from("\\n\\r\\t\\{"); - EXPECT_EQ(re.error, 0); - - csview match; - EXPECT_EQ(cregex_match(&re, "\n\r\t{", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "\n\r\t", &match), CREG_NOMATCH); - - cregex_drop(&re); -} - -TEST(cregex, compile_match_class_simple) -{ - cregex re1 = cregex_from("\\s"); - cregex re2 = cregex_from("\\w"); - cregex re3 = cregex_from("\\D"); - c_defer( - cregex_drop(&re1), cregex_drop(&re2), cregex_drop(&re3) - ){ - EXPECT_EQ(re1.error, 0); - EXPECT_EQ(re2.error, 0); - EXPECT_EQ(re3.error, 0); - - csview match; - EXPECT_EQ(cregex_match(&re1, " " , &match), CREG_OK); - EXPECT_EQ(cregex_match(&re1, "\r", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re1, "\n", &match), CREG_OK); - - EXPECT_EQ(cregex_match(&re2, "a", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re2, "0", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re2, "_", &match), CREG_OK); - - EXPECT_EQ(cregex_match(&re3, "k", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re3, "0", &match), CREG_NOMATCH); - } -} - -TEST(cregex, compile_match_or) -{ - cregex re, re2; - c_defer( - cregex_drop(&re), cregex_drop(&re2) - ){ - re = cregex_from("as|df"); - EXPECT_EQ(re.error, 0); - - csview match[4]; - EXPECT_EQ(cregex_match(&re, "as", match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "df", match), CREG_OK); - - re2 = cregex_from("(as|df)"); - EXPECT_EQ(re2.error, 0); - - EXPECT_EQ(cregex_match(&re2, "as", match), CREG_OK); - EXPECT_EQ(cregex_match(&re2, "df", match), CREG_OK); - } -} - -TEST(cregex, compile_match_class_complex_0) -{ - cregex re = cregex_from("[asdf]"); - EXPECT_EQ(re.error, 0); - - csview match; - EXPECT_EQ(cregex_match(&re, "a", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "s", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "d", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "f", &match), CREG_OK); - - cregex_drop(&re); -} - -TEST(cregex, compile_match_class_complex_1) -{ - cregex re = cregex_from("[a-zä0-9öA-Z]"); - EXPECT_EQ(re.error, 0); - - csview match; - EXPECT_EQ(cregex_match(&re, "a", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "5", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "A", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "ä", &match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "ö", &match), CREG_OK); - - cregex_drop(&re); -} - -TEST(cregex, compile_match_cap) -{ - cregex re = cregex_from("(abc)d"); - EXPECT_EQ(re.error, 0); - - csview match[4]; - EXPECT_EQ(cregex_match(&re, "abcd", match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "llljabcdkk", match), CREG_OK); - EXPECT_EQ(cregex_match(&re, "abc", match), CREG_NOMATCH); - - cregex_drop(&re); -} - -TEST(cregex, search_all) -{ - const char* input; - c_with (cregex re = {0}, cregex_drop(&re)) - { - re = cregex_from("ab"); - csview m = {0}; - int res; - EXPECT_EQ(re.error, CREG_OK); - input="ab,ab|,ab"; - res = cregex_match(&re, input, &m, CREG_NEXT); - EXPECT_EQ(M_START(m), 0); - res = cregex_match(&re, input, &m, CREG_NEXT); - EXPECT_EQ(res, CREG_OK); - EXPECT_EQ(M_START(m), 3); - res = cregex_match(&re, input, &m, CREG_NEXT); - EXPECT_EQ(M_START(m), 7); - res = cregex_match(&re, input, &m, CREG_NEXT); - EXPECT_NE(res, CREG_OK); - } -} - -TEST(cregex, captures_len) -{ - c_with (cregex re = {0}, cregex_drop(&re)) { - re = cregex_from("(ab(cd))(ef)"); - EXPECT_EQ(cregex_captures(&re), 3); - } -} - -TEST(cregex, captures_cap) -{ - const char* input; - c_with (cregex re = {0}, cregex_drop(&re)) { - re = cregex_from("(ab)((cd)+)"); - EXPECT_EQ(cregex_captures(&re), 3); - - csview cap[5]; - EXPECT_EQ(cregex_match(&re, input="xxabcdcde", cap), CREG_OK); - EXPECT_TRUE(csview_equals(cap[0], "abcdcd")); - - EXPECT_EQ(M_END(cap[0]), 8); - EXPECT_EQ(M_START(cap[1]), 2); - EXPECT_EQ(M_END(cap[1]), 4); - EXPECT_EQ(M_START(cap[2]), 4); - EXPECT_EQ(M_END(cap[2]), 8); - - EXPECT_TRUE(cregex_is_match(&re, "abcdcde")); - EXPECT_TRUE(cregex_is_match(&re, "abcdcdcd")); - } -} - -static bool add_10_years(int i, csview match, cstr* out) { - if (i == 1) { // group 1 matches year - int year; - sscanf(match.buf, "%4d", &year); // scan 4 chars only - cstr_printf(out, "%04d", year + 10); - return true; - } - return false; -} - -TEST(cregex, replace) -{ - const char* pattern = "\\b(\\d\\d\\d\\d)-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])\\b"; - const char* input = "start date: 2015-12-31, end date: 2022-02-28"; - cstr str = {0}; - cregex re = {0}; - c_defer( - cstr_drop(&str), cregex_drop(&re) - ){ - // replace with a fixed string, extended all-in-one call: - cstr_take(&str, cregex_replace_aio(pattern, input, "YYYY-MM-DD")); - EXPECT_STREQ(cstr_str(&str), "start date: YYYY-MM-DD, end date: YYYY-MM-DD"); - - // US date format, and add 10 years to dates: - cstr_take(&str, cregex_replace_aio_sv(pattern, csview_from(input), "$1/$3/$2", .xform=add_10_years)); - EXPECT_STREQ(cstr_str(&str), "start date: 2025/31/12, end date: 2032/28/02"); - - // Wrap only the first date inside []: - cstr_take(&str, cregex_replace_aio_sv(pattern, csview_from(input), "[$0]", .count=1)); - EXPECT_STREQ(cstr_str(&str), "start date: [2015-12-31], end date: 2022-02-28"); - - // Wrap all words in ${} - cstr_take(&str, cregex_replace_aio("[a-z]+", "52 apples and 31 mangoes", "$${$0}")); - EXPECT_STREQ(cstr_str(&str), "52 ${apples} ${and} 31 ${mangoes}"); - - // Compile RE separately - re = cregex_from(pattern); - EXPECT_EQ(cregex_captures(&re), 3); - - // European date format. - cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); - EXPECT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022"); - - // Strip out everything but the matches - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", .flags=CREG_STRIP)); - EXPECT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;"); - } -} - -TEST(cregex, hex_range_char_class) -{ - EXPECT_EQ(cregex_make("\\x{12", 0).error, CREG_UNMATCHEDRIGHTPARENTHESIS); - - csview match[16]; - EXPECT_EQ(cregex_match_aio("[\\x{0100}-\\x{0200}]", "aĂb", match), CREG_OK); - EXPECT_EQ(cregex_match_aio("[\\x{0100}-\\x{0200}]", "ȁbc", match), CREG_NOMATCH); - EXPECT_EQ(cregex_match_aio("[\\x{0100}-\\x{0200}\\x{1}-\\x{7f}]", "ȁbc", match), CREG_OK); -} - -TEST(cregex, utf8_bad_string) -{ - csview match[16]; - const char *bad = "this is bad \xE0\xC0string"; - EXPECT_EQ(cregex_match_aio("bad.*string", bad, match), CREG_OK); - EXPECT_EQ(cregex_match_aio("bad [\\x{FFFD}]+string", bad, match), CREG_OK); - EXPECT_EQ(cregex_match_aio("bad [\xC8\x80\xE0\xC0]+string", bad, match), CREG_OK); - EXPECT_EQ(cregex_match_aio("\\bstring", bad, match), CREG_OK); - EXPECT_EQ(cregex_match_aio("\\wstring", bad, match), CREG_NOMATCH); - EXPECT_EQ(cregex_match_aio("\\x{FFFD}\\bstring", bad, match), CREG_OK); - - EXPECT_EQ(0, utf8_icmp(bad, "tHiS iS bAd ��StRiNg")); - EXPECT_EQ(0, utf8_icmp("tHiS iS bAd ��StRiNg", bad)); - EXPECT_GT(0, utf8_icmp("tHiS iS bAd ��StRiN", bad)); - EXPECT_GT(0, utf8_icmp(bad, "tHiS iS bAd ��StRiNgX")); - EXPECT_FALSE(utf8_valid(bad)); - EXPECT_TRUE(utf8_valid_n(bad, 12)); -} - -TEST(cregex, match_csview_without_match_array) -{ - c_with (cregex re = {0}, cregex_drop(&re)) { - re = cregex_from("^second$"); - const char* buffer = "only second word is in csview"; - csview input = c_sv(buffer + 5, 6); - EXPECT_EQ(cregex_match_sv(&re, input), CREG_OK); - } -} diff --git a/src/finchlite/codegen/stc/tests/cspan_test.c b/src/finchlite/codegen/stc/tests/cspan_test.c deleted file mode 100644 index 3494bb91..00000000 --- a/src/finchlite/codegen/stc/tests/cspan_test.c +++ /dev/null @@ -1,158 +0,0 @@ -#include -#include -#include "ctest.h" - -use_cspan3_with_eq(Span, int, c_default_eq); - -TEST(cspan, subdim) { - int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - Span3 m = cspan_md(array, 2, 2, 3); - - for (c_range(i, m.shape[0])) { - Span2 sub_i = cspan_submd3(&m, i); - for (c_range(j, m.shape[1])) { - Span sub_i_j = cspan_submd2(&sub_i, j); - for (c_range(k, m.shape[2])) { - EXPECT_EQ(*cspan_at(&sub_i_j, k), *cspan_at(&m, i, j, k)); - } - } - } -} - - -TEST(cspan, slice) { - int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - Span2 m1 = cspan_md(array, 3, 4); - - int sum1 = 0; - for (c_range(i, m1.shape[0])) { - for (c_range(j, m1.shape[1])) { - sum1 += *cspan_at(&m1, i, j); - } - } - - Span2 m2 = cspan_slice(&m1, Span2, {c_ALL}, {2,4}); - - int sum2 = 0; - for (c_range(i, m2.shape[0])) { - for (c_range(j, m2.shape[1])) { - sum2 += *cspan_at(&m2, i, j); - } - } - EXPECT_EQ(78, sum1); - EXPECT_EQ(45, sum2); -} - - -#define T Stack, int -#include - -TEST(cspan, slice2) { - c_with (Stack stack = {0}, Stack_drop(&stack)) - { - for (c_range32(i, 10 * 20 * 30)) - Stack_push(&stack, i); - - Span3 ms3 = cspan_md(stack.data, 10, 20, 30); - ms3 = cspan_slice(&ms3, Span3, {1,4}, {3,7}, {20,24}); - - int sum = 0; - for (c_range(i, ms3.shape[0])) { - for (c_range(j, ms3.shape[1])) { - for (c_range(k, ms3.shape[2])) { - sum += *cspan_at(&ms3, i, j, k); - } - } - } - EXPECT_EQ(65112, sum); - - sum = 0; - for (c_each(i, Span3, ms3)) - sum += *i.ref; - EXPECT_EQ(65112, sum); - } -} - - -TEST(cspan, equality) { - Span base = c_make(Span, { - 3, 1, 2, 3, 1, - 2, 4, 5, 6, 2, - 1, 7, 8, 9, 3, - 1, 3, 1, 2, 3, - 2, 2, 4, 5, 6, - 3, 1, 7, 8, 9, - }); - Span2 base2 = cspan_md(base.data, 6, 5); - - Span test = c_make(Span, { - 1, 2, 3, - 4, 5, 6, - 7, 8, 9, - }); - Span2 test2 = cspan_md(test.data, 3, 3); - - //puts(""); cspan_print(Span2, cspan_slice(&base2, Span2, {0, 3}, {1, 4}), "%d"); - - // Test every 3x3 subtile in base2 against the test2 tile. - for (c_range(y, base2.shape[0] - 3 + 1)) { - for (c_range(x, base2.shape[1] - 3 + 1)) { - bool expect_eq = (y == 0 && x == 1) || (y == 3 && x == 2); - EXPECT_EQ(expect_eq, Span2_equals(test2, cspan_slice(&base2, Span2, {y, y+3}, {x, x+3}))); - } - } - - // Check that the two 3x4 tiles are equal. - EXPECT_TRUE(Span2_equals(cspan_slice(&base2, Span2, {0, 3}, {0, 4}), - cspan_slice(&base2, Span2, {3, 6}, {1, 5}))); -} - - -#define T Tiles, Span3 -#include - -TEST_FIXTURE(cspan_cube) { - Stack stack; - Tiles tiles; -}; - -TEST_SETUP(cspan_cube, fixt) { - enum {TSIZE = 4, CUBE = 64, N = CUBE*CUBE*CUBE}; - - fixt->stack = Stack_init(); - fixt->tiles = Tiles_init(); - - Stack_reserve(&fixt->stack, N); - for (c_range32(i, N)) - Stack_push(&fixt->stack, i+1); - - Span3 ms3 = cspan_md(fixt->stack.data, CUBE, CUBE, CUBE); - - for (c_range(i, 0, ms3.shape[0], TSIZE)) { - for (c_range(j, 0, ms3.shape[1], TSIZE)) { - for (c_range(k, 0, ms3.shape[2], TSIZE)) { - Span3 tile = cspan_slice(&ms3, Span3, {i, i + TSIZE}, {j, j + TSIZE}, {k, k + TSIZE}); - Tiles_push(&fixt->tiles, tile); - } - } - } -} - -// Optional teardown function for suite, called after every test in suite -TEST_TEARDOWN(cspan_cube, fixt) { - Stack_drop(&fixt->stack); - Tiles_drop(&fixt->tiles); -} - - -TEST_F(cspan_cube, slice3, fixt) { - int64 n = Stack_size(&fixt->stack); - int64 sum = 0; - - // iterate each 3d tile in sequence - for (c_each(tile, Tiles, fixt->tiles)) - for (c_each(i, Span3, *tile.ref)) - sum += *i.ref; - - EXPECT_EQ(sum, n*(n + 1)/2); -} diff --git a/src/finchlite/codegen/stc/tests/ctest.h b/src/finchlite/codegen/stc/tests/ctest.h deleted file mode 100644 index 8ffbdf7a..00000000 --- a/src/finchlite/codegen/stc/tests/ctest.h +++ /dev/null @@ -1,639 +0,0 @@ -/* Copyright 2011-2023 Bas van den Berg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CTEST_H -#define CTEST_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __GNUC__ -#define CTEST_IMPL_FORMAT_PRINTF(a, b) __attribute__ ((format(printf, a, b))) -#else -#define CTEST_IMPL_FORMAT_PRINTF(a, b) -#endif - -#include /* intmax_t, uintmax_t, PRI* */ -#include /* bool, true, false */ -#include /* size_t */ - -typedef void (*ctest_nullary_run_func)(void); -typedef void (*ctest_unary_run_func)(void*); -typedef void (*ctest_setup_func)(void*); -typedef void (*ctest_teardown_func)(void*); - -union ctest_run_func_union { - ctest_nullary_run_func nullary; - ctest_unary_run_func unary; -}; - -#define CTEST_IMPL_PRAGMA(x) _Pragma (#x) -#define CTEST_CONTAINER_OF(p, T, m) \ - ((T*)((char*)(p) + 0*sizeof((p) == &((T*)0)->m) - offsetof(T, m))) - -#if defined(__GNUC__) -#if defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -/* the GCC argument will work for both gcc and clang */ -#define CTEST_IMPL_DIAG_PUSH_IGNORED(w) \ - CTEST_IMPL_PRAGMA(GCC diagnostic push) \ - CTEST_IMPL_PRAGMA(GCC diagnostic ignored "-W" #w) -#define CTEST_IMPL_DIAG_POP() \ - CTEST_IMPL_PRAGMA(GCC diagnostic pop) -#else -/* the push/pop functionality wasn't in gcc until 4.6, fallback to "ignored" */ -#define CTEST_IMPL_DIAG_PUSH_IGNORED(w) \ - CTEST_IMPL_PRAGMA(GCC diagnostic ignored "-W" #w) -#define CTEST_IMPL_DIAG_POP() -#endif -#else -/* leave them out entirely for non-GNUC compilers */ -#define CTEST_IMPL_DIAG_PUSH_IGNORED(w) -#define CTEST_IMPL_DIAG_POP() -#endif - -struct ctest { - uint32_t magic0, padding; - - const char* ssname; // suite name - const char* ttname; // test name - union ctest_run_func_union run; - - void* data; - ctest_setup_func* setup; - ctest_teardown_func* teardown; - - int32_t skip; - uint32_t magic1; -}; - -#define CTEST_IMPL_NAME(name) ctest_##name -#define CTEST_IMPL_FNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_run) -#define CTEST_IMPL_TNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname) -#define CTEST_IMPL_DATA_SNAME(sname) CTEST_IMPL_NAME(sname##_data) -#define CTEST_IMPL_DATA_TNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_data) -#define CTEST_IMPL_SETUP_FNAME(sname) CTEST_IMPL_NAME(sname##_setup) -#define CTEST_IMPL_SETUP_FPNAME(sname) CTEST_IMPL_NAME(sname##_setup_ptr) -#define CTEST_IMPL_SETUP_TPNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_setup_ptr) -#define CTEST_IMPL_TEARDOWN_FNAME(sname) CTEST_IMPL_NAME(sname##_teardown) -#define CTEST_IMPL_TEARDOWN_FPNAME(sname) CTEST_IMPL_NAME(sname##_teardown_ptr) -#define CTEST_IMPL_TEARDOWN_TPNAME(sname, tname) CTEST_IMPL_NAME(sname##_##tname##_teardown_ptr) - -#ifdef __APPLE__ -#ifdef __arm64__ -#define CTEST_IMPL_SECTION __attribute__ ((used, section ("__DATA, .ctest"), aligned(8))) -#else -#define CTEST_IMPL_SECTION __attribute__ ((used, section ("__DATA, .ctest"), aligned(1))) -#endif -#elif !defined _MSC_VER -#define CTEST_IMPL_SECTION __attribute__ ((used, section (".ctest"), aligned(1))) -#else -#pragma section(".ctest", read) -#define CTEST_IMPL_SECTION __declspec(allocate(".ctest")) __declspec(align(1)) -#endif - -#define CTEST_IMPL_STRUCT(sname, tname, tskip, tdata, tsetup, tteardown) \ - static CTEST_IMPL_SECTION struct ctest CTEST_IMPL_TNAME(sname, tname) = { \ - 0xBADCAFE0, 0, \ - #sname, \ - #tname, \ - { (ctest_nullary_run_func) CTEST_IMPL_FNAME(sname, tname) }, \ - tdata, \ - (ctest_setup_func*) tsetup, \ - (ctest_teardown_func*) tteardown, \ - tskip, \ - 0xBADCAFE1, \ - } - -#ifdef __cplusplus - -#define CTEST_SETUP(sname, fixt) \ - template <> void CTEST_IMPL_SETUP_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* fixt) - -#define CTEST_TEARDOWN(sname, fixt) \ - template <> void CTEST_IMPL_TEARDOWN_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* fixt) - -#define CTEST_FIXTURE(sname) \ - template void CTEST_IMPL_SETUP_FNAME(sname)(T* self) { } \ - template void CTEST_IMPL_TEARDOWN_FNAME(sname)(T* self) { } \ - struct CTEST_IMPL_DATA_SNAME(sname) - -#define CTEST_IMPL_CTEST(sname, tname, tskip) \ - static void CTEST_IMPL_FNAME(sname, tname)(void); \ - CTEST_IMPL_STRUCT(sname, tname, tskip, NULL, NULL, NULL); \ - static void CTEST_IMPL_FNAME(sname, tname)(void) - -#define CTEST_IMPL_CTEST_F(sname, tname, tskip, fixt) \ - static struct CTEST_IMPL_DATA_SNAME(sname) CTEST_IMPL_DATA_TNAME(sname, tname); \ - static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* fixt); \ - static void (*CTEST_IMPL_SETUP_TPNAME(sname, tname))(struct CTEST_IMPL_DATA_SNAME(sname)*) = &CTEST_IMPL_SETUP_FNAME(sname); \ - static void (*CTEST_IMPL_TEARDOWN_TPNAME(sname, tname))(struct CTEST_IMPL_DATA_SNAME(sname)*) = &CTEST_IMPL_TEARDOWN_FNAME(sname); \ - CTEST_IMPL_STRUCT(sname, tname, tskip, &CTEST_IMPL_DATA_TNAME(sname, tname), &CTEST_IMPL_SETUP_TPNAME(sname, tname), &CTEST_IMPL_TEARDOWN_TPNAME(sname, tname)); \ - static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* fixt) - -#else - -#define CTEST_SETUP(sname, fixt) \ - static void CTEST_IMPL_SETUP_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* fixt); \ - static void (*CTEST_IMPL_SETUP_FPNAME(sname))(struct CTEST_IMPL_DATA_SNAME(sname)*) = &CTEST_IMPL_SETUP_FNAME(sname); \ - static void CTEST_IMPL_SETUP_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* fixt) - -#define CTEST_TEARDOWN(sname, fixt) \ - static void CTEST_IMPL_TEARDOWN_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* fixt); \ - static void (*CTEST_IMPL_TEARDOWN_FPNAME(sname))(struct CTEST_IMPL_DATA_SNAME(sname)*) = &CTEST_IMPL_TEARDOWN_FNAME(sname); \ - static void CTEST_IMPL_TEARDOWN_FNAME(sname)(struct CTEST_IMPL_DATA_SNAME(sname)* fixt) - -#define CTEST_FIXTURE(sname) \ - struct CTEST_IMPL_DATA_SNAME(sname); \ - static void (*CTEST_IMPL_SETUP_FPNAME(sname))(struct CTEST_IMPL_DATA_SNAME(sname)*); \ - static void (*CTEST_IMPL_TEARDOWN_FPNAME(sname))(struct CTEST_IMPL_DATA_SNAME(sname)*); \ - struct CTEST_IMPL_DATA_SNAME(sname) - -#define CTEST_IMPL_CTEST(sname, tname, tskip) \ - static void CTEST_IMPL_FNAME(sname, tname)(void); \ - CTEST_IMPL_STRUCT(sname, tname, tskip, NULL, NULL, NULL); \ - static void CTEST_IMPL_FNAME(sname, tname)(void) - -#define CTEST_IMPL_CTEST_F(sname, tname, tskip, fixt) \ - static struct CTEST_IMPL_DATA_SNAME(sname) CTEST_IMPL_DATA_TNAME(sname, tname); \ - static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* fixt); \ - CTEST_IMPL_STRUCT(sname, tname, tskip, &CTEST_IMPL_DATA_TNAME(sname, tname), &CTEST_IMPL_SETUP_FPNAME(sname), &CTEST_IMPL_TEARDOWN_FPNAME(sname)); \ - static void CTEST_IMPL_FNAME(sname, tname)(struct CTEST_IMPL_DATA_SNAME(sname)* fixt) - -#endif - -void assert_str(int diag, const char* cmp, const char* exp, const char* real, const char* caller, int line); -void assert_wstr(int diag, const char* cmp, const wchar_t *exp, const wchar_t *real, const char* caller, int line); -void assert_compare(int diag, const char* cmp, intmax_t exp, intmax_t real, const char* caller, int line); -void assert_interval(int diag, intmax_t low, intmax_t high, intmax_t real, const char* caller, int line); -void assert_pointers(int diag, const char* cmp, const void* exp, const void* real, const char* caller, int line); -void assert_bool(int diag, bool exp, bool real, const char* caller, int line); -void assert_dbl_compare(int diag, const char* cmp, double exp, double real, double tol, const char* caller, int line); -void assert_fail(const char* caller, int line); - -#define CTEST_FLT_EPSILON 1e-5 -#define CTEST_DBL_EPSILON 1e-12 - -#define CTEST(sname, tname) CTEST_IMPL_CTEST(sname, tname, 0) -#define CTEST_F(sname, tname, fixt) CTEST_IMPL_CTEST_F(sname, tname, 0, fixt) -#define CTEST_SKIP(sname, tname) CTEST_IMPL_CTEST(sname, tname, 1) -#define CTEST_F_SKIP(sname, tname, fixt) CTEST_IMPL_CTEST_F(sname, tname, 1, fixt) - -// Aliases, more like gtest: -#define TEST(sname, tname) CTEST(sname, tname) -#define TEST_SKIP(sname, tname) CTEST_SKIP(sname, tname) - -#define TEST_FIXTURE(sname) CTEST_FIXTURE(sname) -#define TEST_SETUP(sname, fixt) CTEST_SETUP(sname, fixt) -#define TEST_TEARDOWN(sname, fixt) CTEST_TEARDOWN(sname, fixt) -#define TEST_F(sname, tname, fixt) CTEST_F(sname, tname, fixt) -#define TEST_F_SKIP(sname, tname, fixt) CTEST_F_SKIP(sname, tname, fixt) - -// private -#define _CHECK_STREQ(diag, exp, real) assert_str(diag, "==", exp, real, __FILE__, __LINE__) -#define _CHECK_STRNE(diag, exp, real) assert_str(diag, "!=", exp, real, __FILE__, __LINE__) -#define _CHECK_SUBSTR(diag, substr, real) assert_str(diag, "=~", substr, real, __FILE__, __LINE__) -#define _CHECK_NOT_SUBSTR(diag, substr, real) assert_str(diag, "!~", substr, real, __FILE__, __LINE__) -#define _CHECK_WSTREQ(diag, exp, real) assert_wstr(diag, "==", exp, real, __FILE__, __LINE__) -#define _CHECK_WSTRNE(diag, exp, real) assert_wstr(diag, "!=", exp, real, __FILE__, __LINE__) -#define _CHECK_EQ(diag, v1, v2) assert_compare(diag, "==", v1, v2, __FILE__, __LINE__) -#define _CHECK_NE(diag, v1, v2) assert_compare(diag, "!=", v1, v2, __FILE__, __LINE__) -#define _CHECK_LT(diag, v1, v2) assert_compare(diag, "<", v1, v2, __FILE__, __LINE__) -#define _CHECK_LE(diag, v1, v2) assert_compare(diag, "<=", v1, v2, __FILE__, __LINE__) -#define _CHECK_GT(diag, v1, v2) assert_compare(diag, ">", v1, v2, __FILE__, __LINE__) -#define _CHECK_GE(diag, v1, v2) assert_compare(diag, ">=", v1, v2, __FILE__, __LINE__) -#define _CHECK_INTERVAL(diag, low, high, real) assert_interval(diag, low, high, real, __FILE__, __LINE__) -#define _CHECK_PTR_EQ(diag, exp, real) ((void)sizeof((exp) == (real)), assert_pointers(diag, "==", exp, real, __FILE__, __LINE__)) -#define _CHECK_PTR_NE(diag, exp, real) ((void)sizeof((exp) != (real)), assert_pointers(diag, "!=", exp, real, __FILE__, __LINE__)) -#define _CHECK_BOOL(diag, exp, real) assert_bool(diag, exp, real, __FILE__, __LINE__) -#define _CHECK_NEAR(diag, exp, real, tol) assert_dbl_compare(diag, "==", exp, real, tol, __FILE__, __LINE__) -#define _CHECK_NOT_NEAR(diag, exp, real, tol) assert_dbl_compare(diag, "!=", exp, real, tol, __FILE__, __LINE__) -#define _CHECK_DOUBLE_EQ(diag, exp, real) assert_dbl_compare(diag, "==", exp, real, -CTEST_DBL_EPSILON, __FILE__, __LINE__) -#define _CHECK_DOUBLE_NE(diag, exp, real) assert_dbl_compare(diag, "!=", exp, real, -CTEST_DBL_EPSILON, __FILE__, __LINE__) -#define _CHECK_DOUBLE_LT(diag, v1, v2) assert_dbl_compare(diag, "<", v1, v2, 0.0, __FILE__, __LINE__) -#define _CHECK_DOUBLE_GT(diag, v1, v2) assert_dbl_compare(diag, ">", v1, v2, 0.0, __FILE__, __LINE__) -#define _CHECK_FLOAT_EQ(diag, v1, v2) assert_dbl_compare(diag, "==", v1, v2, -CTEST_FLT_EPSILON, __FILE__, __LINE__) -#define _CHECK_FLOAT_NE(diag, v1, v2) assert_dbl_compare(diag, "!=", v1, v2, -CTEST_FLT_EPSILON, __FILE__, __LINE__) -#define _CHECK_FLOAT_LT(diag, v1, v2) assert_dbl_compare(diag, "<", (float)(v1), (float)(v2), 0.0, __FILE__, __LINE__) -#define _CHECK_FLOAT_GT(diag, v1, v2) assert_dbl_compare(diag, ">", (float)(v1), (float)(v2), 0.0, __FILE__, __LINE__) - -// EXPECT ===================================== - -#define EXPECT_STREQ(exp, real) _CHECK_STREQ(1, exp, real) -#define EXPECT_STRNE(exp, real) _CHECK_STRNE(1, exp, real) -#define EXPECT_SUBSTR(substr, real) _CHECK_SUBSTR(1, substr, real) -#define EXPECT_NOT_SUBSTR(substr, real) _CHECK_NOT_SUBSTR(1, substr, real) -#define EXPECT_WSTREQ(exp, real) _CHECK_WSTREQ(1, exp, real) -#define EXPECT_WSTRNE(exp, real) _CHECK_WSTRNE(1, exp, real) -#define EXPECT_EQ(v1, v2) _CHECK_EQ(1, v1, v2) -#define EXPECT_NE(v1, v2) _CHECK_NE(1, v1, v2) -#define EXPECT_LT(v1, v2) _CHECK_LT(1, v1, v2) -#define EXPECT_LE(v1, v2) _CHECK_LE(1, v1, v2) -#define EXPECT_GT(v1, v2) _CHECK_GT(1, v1, v2) -#define EXPECT_GE(v1, v2) _CHECK_GE(1, v1, v2) -#define EXPECT_INTERVAL(low, high, real) _CHECK_INTERVAL(1, low, high, real) -#define EXPECT_PTR_EQ(exp, real) _CHECK_PTR_EQ(1, exp, real) -#define EXPECT_PTR_NE(exp, real) _CHECK_PTR_NE(1, exp, real) -#define EXPECT_NULL(real) _CHECK_PTR_EQ(1, NULL, real) -#define EXPECT_NOT_NULL(real) _CHECK_PTR_NE(1, NULL, real) -#define EXPECT_TRUE(real) _CHECK_BOOL(1, true, real) -#define EXPECT_FALSE(real) _CHECK_BOOL(1, false, real) -#define EXPECT_NEAR(exp, real, tol) _CHECK_NEAR(1, exp, real, tol) -#define EXPECT_NOT_NEAR(exp, real, tol) _CHECK_NOT_NEAR(1, exp, real, tol) -#define EXPECT_DOUBLE_EQ(exp, real) _CHECK_DOUBLE_EQ(1, exp, real) -#define EXPECT_DOUBLE_NE(exp, real) _CHECK_DOUBLE_NE(1, exp, real) -#define EXPECT_DOUBLE_LT(v1, v2) _CHECK_DOUBLE_LT(1, v1, v2) -#define EXPECT_DOUBLE_GT(v1, v2) _CHECK_DOUBLE_GT(1, v1, v2) -#define EXPECT_FLOAT_EQ(v1, v2) _CHECK_FLOAT_EQ(1, v1, v2) -#define EXPECT_FLOAT_NE(v1, v2) _CHECK_FLOAT_NE(1, v1, v2) -#define EXPECT_FLOAT_LT(v1, v2) _CHECK_FLOAT_LT(1, v1, v2) -#define EXPECT_FLOAT_GT(v1, v2) _CHECK_FLOAT_GT(1, v1, v2) - -// ASSERT ===================================== - -#define ASSERT_STREQ(exp, real) _CHECK_STREQ(2, exp, real) -#define ASSERT_STRNE(exp, real) _CHECK_STRNE(2, exp, real) -#define ASSERT_SUBSTR(substr, real) _CHECK_SUBSTR(2, substr, real) -#define ASSERT_NOT_SUBSTR(substr, real) _CHECK_NOT_SUBSTR(2, substr, real) -#define ASSERT_WSTREQ(exp, real) _CHECK_WSTREQ(2, exp, real) -#define ASSERT_WSTRNE(exp, real) _CHECK_WSTRNE(2, exp, real) -#define ASSERT_EQ(v1, v2) _CHECK_EQ(2, v1, v2) -#define ASSERT_NE(v1, v2) _CHECK_NE(2, v1, v2) -#define ASSERT_LT(v1, v2) _CHECK_LT(2, v1, v2) -#define ASSERT_LE(v1, v2) _CHECK_LE(2, v1, v2) -#define ASSERT_GT(v1, v2) _CHECK_GT(2, v1, v2) -#define ASSERT_GE(v1, v2) _CHECK_GE(2, v1, v2) -#define ASSERT_INTERVAL(low, high, real) _CHECK_INTERVAL(2, low, high, real) -#define ASSERT_PTR_EQ(exp, real) _CHECK_PTR_EQ(2, exp, real) -#define ASSERT_PTR_NE(exp, real) _CHECK_PTR_NE(2, exp, real) -#define ASSERT_NULL(real) _CHECK_PTR_EQ(2, NULL, real) -#define ASSERT_NOT_NULL(real) _CHECK_PTR_NE(2, NULL, real) -#define ASSERT_TRUE(real) _CHECK_BOOL(2, true, real) -#define ASSERT_FALSE(real) _CHECK_BOOL(2, false, real) -#define ASSERT_NEAR(exp, real, tol) _CHECK_NEAR(2, exp, real, tol) -#define ASSERT_NOT_NEAR(exp, real, tol) _CHECK_NOT_NEAR(2, exp, real, tol) -#define ASSERT_DOUBLE_EQ(exp, real) _CHECK_DOUBLE_EQ(2, exp, real) -#define ASSERT_DOUBLE_NE(exp, real) _CHECK_DOUBLE_NE(2, exp, real) -#define ASSERT_DOUBLE_LT(v1, v2) _CHECK_DOUBLE_LT(2, v1, v2) -#define ASSERT_DOUBLE_GT(v1, v2) _CHECK_DOUBLE_GT(2, v1, v2) -#define ASSERT_FLOAT_EQ(v1, v2) _CHECK_FLOAT_EQ(2, v1, v2) -#define ASSERT_FLOAT_NE(v1, v2) _CHECK_FLOAT_NE(2, v1, v2) -#define ASSERT_FLOAT_LT(v1, v2) _CHECK_FLOAT_LT(2, v1, v2) -#define ASSERT_FLOAT_GT(v1, v2) _CHECK_FLOAT_GT(2, v1, v2) -#define ASSERT_FAIL() assert_fail(__FILE__, __LINE__) - -#ifdef CTEST_MAIN - -#include -#include -#include -#include -#include -#if !defined(_WIN32) || defined(__GNUC__) -#include -#elif defined(_WIN32) -#include -#endif -#include -#include -#include - -static int ctest_failed; -static size_t ctest_errorsize; -static char* ctest_errormsg; -#define MSG_SIZE 4096 -static char ctest_errorbuffer[MSG_SIZE]; -static jmp_buf ctest_err; -static int color_output = 1; -static const char* suite_name; - -typedef int (*ctest_filter_func)(struct ctest*); - -#define ANSI_BLACK "\033[0;30m" -#define ANSI_RED "\033[0;31m" -#define ANSI_GREEN "\033[0;32m" -#define ANSI_YELLOW "\033[0;33m" -#define ANSI_BLUE "\033[0;34m" -#define ANSI_MAGENTA "\033[0;35m" -#define ANSI_CYAN "\033[0;36m" -#define ANSI_GREY "\033[0;37m" -#define ANSI_DARKGREY "\033[01;30m" -#define ANSI_BRED "\033[01;31m" -#define ANSI_BGREEN "\033[01;32m" -#define ANSI_BYELLOW "\033[01;33m" -#define ANSI_BBLUE "\033[01;34m" -#define ANSI_BMAGENTA "\033[01;35m" -#define ANSI_BCYAN "\033[01;36m" -#define ANSI_WHITE "\033[01;37m" -#define ANSI_NORMAL "\033[0m" - -CTEST(suite, test) { } - -static void vprint_errormsg(const char* const fmt, va_list ap) CTEST_IMPL_FORMAT_PRINTF(1, 0); -static void print_errormsg(const char* const fmt, ...) CTEST_IMPL_FORMAT_PRINTF(1, 2); - -static void vprint_errormsg(const char* const fmt, va_list ap) { - // (v)snprintf returns the number that would have been written - const int ret = vsnprintf(ctest_errormsg, ctest_errorsize, fmt, ap); - if (ret < 0) { - ctest_errormsg[0] = 0x00; - } else { - const size_t size = (size_t) ret; - const size_t s = (ctest_errorsize <= size ? size -ctest_errorsize : size); - // ctest_errorsize may overflow at this point - ctest_errorsize -= s; - ctest_errormsg += s; - } -} - -static void print_errormsg(const char* const fmt, ...) { - va_list argp; - va_start(argp, fmt); - vprint_errormsg(fmt, argp); - va_end(argp); -} - -static void msg_start(const char* color, const char* title) { - if (color_output) { - print_errormsg("%s", color); - } - print_errormsg(" %s: ", title); -} - -static void msg_end(void) { - if (color_output) { - print_errormsg(ANSI_NORMAL); - } - print_errormsg("\n"); -} - -CTEST_IMPL_DIAG_PUSH_IGNORED(missing-noreturn) - -static void ctest_print(int diag, const char* fmt, ...) CTEST_IMPL_FORMAT_PRINTF(2, 3); // may not return -static void ctest_print(int diag, const char* fmt, ...) -{ - va_list argp; - switch (diag) { - case 0: msg_start(ANSI_BLUE, "LOG"); break; - case 1: msg_start(ANSI_YELLOW, "ERR"); break; - case 2: msg_start(ANSI_BYELLOW, "ERR"); break; - } - va_start(argp, fmt); - vprint_errormsg(fmt, argp); - va_end(argp); - - msg_end(); - - if (diag == 2) - longjmp(ctest_err, 1); - ctest_failed = 1; -} - -CTEST_IMPL_DIAG_POP() - -void assert_str(int diag, const char* cmp, const char* exp, const char* real, const char* caller, int line) { - if ((!exp ^ !real) || (exp && ( - (cmp[1] == '=' && ((cmp[0] == '=') ^ (strcmp(real, exp) == 0))) || - (cmp[1] == '~' && ((cmp[0] == '=') ^ (strstr(real, exp) != NULL))) - ))) { - ctest_print(diag, "%s:%d assertion failed, '%s' %s '%s'", caller, line, exp, cmp, real); - } -} - -void assert_wstr(int diag, const char* cmp, const wchar_t *exp, const wchar_t *real, const char* caller, int line) { - if ((!exp ^ !real) || (exp && ( - (cmp[1] == '=' && ((cmp[0] == '=') ^ (wcscmp(real, exp) == 0))) || - (cmp[1] == '~' && ((cmp[0] == '=') ^ (wcsstr(real, exp) != NULL))) - ))) { - ctest_print(diag, "%s:%d assertion failed, '%ls' %s '%ls'", caller, line, exp, cmp, real); - } -} - -static bool get_compare_result(const char* cmp, int c3, bool eq) { - if (cmp[0] == '<') - return c3 < 0 || ((cmp[1] == '=') & eq); - if (cmp[0] == '>') - return c3 > 0 || ((cmp[1] == '=') & eq); - return (cmp[0] == '=') == eq; -} - -void assert_compare(int diag, const char* cmp, intmax_t exp, intmax_t real, const char* caller, int line) { - int c3 = (real < exp) - (exp < real); - - if (!get_compare_result(cmp, c3, c3 == 0)) { - ctest_print(diag, "%s:%d assertion failed, %" PRIdMAX " %s %" PRIdMAX "", caller, line, exp, cmp, real); - } -} - -void assert_interval(int diag, intmax_t low, intmax_t high, intmax_t real, const char* caller, int line) { - if (real < low || real > high) { - ctest_print(diag, "%s:%d expected %" PRIdMAX "-%" PRIdMAX ", got %" PRIdMAX, caller, line, low, high, real); - } -} - -static bool approximately_equal(double a, double b, double epsilon) { - double d = a - b; - if (d < 0) d = -d; - if (a < 0) a = -a; - if (b < 0) b = -b; - return d <= (a > b ? a : b)*epsilon; /* D.Knuth */ -} - -/* tol < 0 means it is an epsilon, else absolute error */ -void assert_dbl_compare(int diag, const char* cmp, double exp, double real, double tol, const char* caller, int line) { - double diff = exp - real; - double absdiff = diff < 0 ? -diff : diff; - int c3 = (real < exp) - (exp < real); - bool eq = tol < 0 ? approximately_equal(exp, real, -tol) : absdiff <= tol; - - if (!get_compare_result(cmp, c3, eq)) { - const char* tolstr = "tol"; - if (tol < 0) { - tolstr = "eps"; - tol = -tol; - } - ctest_print(diag, "%s:%d assertion failed, %.8g %s %.8g (diff %.4g, %s %.4g)", caller, line, exp, cmp, real, diff, tolstr, tol); - } -} - -void assert_pointers(int diag, const char* cmp, const void* exp, const void* real, const char* caller, int line) { - if ((exp == real) != (cmp[0] == '=')) { - ctest_print(diag, "%s:%d assertion failed (0x%02llx) %s (0x%02llx)", caller, line, - (unsigned long long)(uintptr_t)exp , cmp, (unsigned long long)(uintptr_t)real); - } -} - -void assert_bool(int diag, bool exp, bool real, const char* caller, int line) { - if (exp != real) { - ctest_print(diag, "%s:%d should be %s", caller, line, exp ? "true" : "false"); - } -} - -void assert_fail(const char* caller, int line) { - ctest_print(2, "%s:%d shouldn't come here", caller, line); -} - - -static int suite_all(struct ctest* t) { - (void) t; // avoid unused parameter warning - return 1; -} - -static int suite_filter(struct ctest* t) { - return strncmp(suite_name, t->ssname, strlen(suite_name)) == 0; -} - -static void color_print(const char* color, const char* text) { - if (color_output) - printf("%s%s" ANSI_NORMAL "\n", color, text); - else - printf("%s\n", text); -} - -#ifndef CTEST_NO_SEGFAULT -#include -static void sighandler(int signum) -{ - const char msg_color[] = ANSI_BRED "[SIGSEGV: Segmentation fault]" ANSI_NORMAL "\n"; - const char msg_nocolor[] = "[SIGSEGV: Segmentation fault]\n"; - - const char* msg = color_output ? msg_color : msg_nocolor; - intptr_t n = write(1, msg, (unsigned int)strlen(msg)); - (void)n; - /* "Unregister" the signal handler and send the signal back to the process - * so it can terminate as expected */ - signal(signum, SIG_DFL); -#if !defined(_WIN32) || defined(__CYGWIN__) - //kill(getpid(), signum); -#endif -} -#endif - -int ctest_main(int argc, const char *argv[]); -#ifdef __GNUC__ -__attribute__((no_sanitize_address)) -#endif -int ctest_main(int argc, const char *argv[]) -{ - static int total = 0; - static int num_ok = 0; - static int num_fail = 0; - static int num_skip = 0; - static int idx = 1; - static ctest_filter_func filter = suite_all; - -#ifndef CTEST_NO_SEGFAULT - signal(SIGSEGV, sighandler); -#endif - - if (argc == 2) { - suite_name = argv[1]; - filter = suite_filter; - } -#ifdef CTEST_NO_COLORS - color_output = 0; -#else - color_output = isatty(1); -#endif - clock_t t1 = clock(); - - uint32_t* magic_begin = &CTEST_IMPL_TNAME(suite, test).magic1; - uint32_t* magic_end = &CTEST_IMPL_TNAME(suite, test).magic0, *m; - ptrdiff_t num_ints = sizeof(struct ctest)/sizeof *m; - -#if (defined __TINYC__ && defined __unix__) - #define CTEST_IMPL_MAGIC_SEEK 10 /* search 4*(1+10) bytes outside ctest entry bounds */ -#else - #define CTEST_IMPL_MAGIC_SEEK 0 /* access only 4 bytes outside outer ctest entry bounds */ -#endif - for (m = magic_begin; magic_begin - m <= num_ints + CTEST_IMPL_MAGIC_SEEK; --m) { - if (*m == 0xBADCAFE1) { - magic_begin = m; - m -= num_ints - 1; - } - } - for (m = magic_end; m - magic_end <= num_ints; ++m) { - if (*m == 0xBADCAFE0) { - magic_end = m; - m += num_ints - 1; - } - } - magic_begin = &CTEST_CONTAINER_OF(magic_begin, struct ctest, magic1)->magic0; - - static struct ctest* test; - for (m = magic_begin; m <= magic_end; m += num_ints) { - while (*m != 0xBADCAFE0) ++m; - test = CTEST_CONTAINER_OF(m, struct ctest, magic0); - if (test == &CTEST_IMPL_TNAME(suite, test)) continue; - if (filter(test)) total++; - } - - for (m = magic_begin; m <= magic_end; m += num_ints) { - while (*m != 0xBADCAFE0) ++m; - test = CTEST_CONTAINER_OF(m, struct ctest, magic0); - if (test == &CTEST_IMPL_TNAME(suite, test)) continue; - if (filter(test)) { - ctest_failed = 0; - ctest_errorbuffer[0] = 0; - ctest_errorsize = MSG_SIZE-1; - ctest_errormsg = ctest_errorbuffer; - printf("TEST %d/%d %s:%s ", idx, total, test->ssname, test->ttname); - fflush(stdout); - if (test->skip) { - color_print(ANSI_BYELLOW, "[SKIPPED]"); - num_skip++; - } else { - int result = setjmp(ctest_err); - if (result == 0) { - if (test->setup && *test->setup) (*test->setup)(test->data); - if (test->data) - test->run.unary(test->data); - else - test->run.nullary(); - if (test->teardown && *test->teardown) (*test->teardown)(test->data); - // if we got here it's ok - if (ctest_failed) longjmp(ctest_err, 1); -#ifdef CTEST_NO_COLOR_OK - printf("[OK]\n"); -#else - color_print(ANSI_BGREEN, "[OK]"); -#endif - num_ok++; - } else { - color_print(ANSI_BRED, "[FAIL]"); - num_fail++; - } - if (ctest_errorsize != MSG_SIZE-1) printf("%s", ctest_errorbuffer); - } - idx++; - } - } - clock_t t2 = clock(); - - const char* color = (num_fail) ? ANSI_BRED : ANSI_GREEN; - char results[80]; - snprintf(results, sizeof(results), "RESULTS: %d tests (%d ok, %d failed, %d skipped) ran in %.1f ms", - total, num_ok, num_fail, num_skip, (double)(t2 - t1)*1000.0/CLOCKS_PER_SEC); - color_print(color, results); - return num_fail; -} - -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/finchlite/codegen/stc/tests/deque_test.c b/src/finchlite/codegen/stc/tests/deque_test.c deleted file mode 100644 index af960c4a..00000000 --- a/src/finchlite/codegen/stc/tests/deque_test.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "ctest.h" - -#define T IDeq, int, (c_use_cmp) -#include - - -TEST(deque, basics) { - IDeq d = c_make(IDeq, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); - EXPECT_EQ(12, IDeq_size(&d)); - - for (c_range(5)) - IDeq_pop_front(&d); - for (c_range32(i, 2, 9)) - IDeq_push_back(&d, i*10); - - IDeq res1 = c_make(IDeq, {6, 7, 8, 9, 10, 11, 12, 20, 30, 40, 50, 60, 70, 80}); - EXPECT_TRUE(IDeq_eq(&res1, &d)); - EXPECT_EQ(14, IDeq_size(&d)); - - IDeq_erase_n(&d, 7, 4); - - IDeq res2 = c_make(IDeq, {6, 7, 8, 9, 10, 11, 12, 60, 70, 80}); - EXPECT_TRUE(IDeq_eq(&res2, &d)); - - int nums[] = {200, 300, 400, 500}; - IDeq_insert_n(&d, 7, nums, 4); - - IDeq res3 = c_make(IDeq, {6, 7, 8, 9, 10, 11, 12, 200, 300, 400, 500, 60, 70, 80}); - EXPECT_TRUE(IDeq_eq(&res3, &d)); - EXPECT_EQ(*IDeq_find(&res3, 400).ref, 400); - EXPECT_NULL(IDeq_find(&res3, 401).ref); - - EXPECT_EQ(14, IDeq_size(&d)); - EXPECT_EQ(200, *IDeq_at(&d, 7)); - - c_drop(IDeq, &d, &res1, &res2, &res3); -} diff --git a/src/finchlite/codegen/stc/tests/hmap_test.c b/src/finchlite/codegen/stc/tests/hmap_test.c deleted file mode 100644 index 58980919..00000000 --- a/src/finchlite/codegen/stc/tests/hmap_test.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include "ctest.h" - -#define T Intmap, int, int -#include - -TEST(hashmap, mapdemo1) -{ - Intmap nums = {0}; - Intmap_insert(&nums, 8, 64); - Intmap_insert(&nums, 11, 121); - EXPECT_EQ(64, *Intmap_at(&nums, 8)); - Intmap_drop(&nums); -} - -#define T SImap, cstr, int, (c_keypro) -#include - -TEST(hashmap, mapdemo2) -{ - SImap nums = {0}; - SImap_clear(&nums); - SImap_emplace_or_assign(&nums, "Hello", 64); - SImap_emplace_or_assign(&nums, "Groovy", 121); - SImap_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous - - EXPECT_EQ(200, *SImap_at(&nums, "Groovy")); - EXPECT_EQ(64, *SImap_at(&nums, "Hello")); - - SImap_drop(&nums); -} - - -#define T Strmap, cstr, cstr, (c_keypro | c_valpro) -#include - -TEST(hashmap, mapdemo3) -{ - Strmap map = {0}; - Strmap_emplace(&map, "Map", "test"); - Strmap_emplace(&map, "Make", "my"); - Strmap_emplace(&map, "Hello", "world"); - Strmap_emplace(&map, "Sunny", "day"); - - Strmap_iter it = Strmap_find(&map, "Make"); - Strmap_erase_at(&map, it); - Strmap_erase(&map, "Hello"); - - Strmap res1 = c_make(Strmap, {{"Map", ""}, {"Sunny", ""}}); - Strmap res2 = c_make(Strmap, {{"Sunny", ""}, {"Map", ""}}); - - EXPECT_TRUE(Strmap_eq(&res1, &map)); - EXPECT_TRUE(Strmap_eq(&res2, &map)); - - c_drop(Strmap, &map, &res1, &res2); -} diff --git a/src/finchlite/codegen/stc/tests/list_test.c b/src/finchlite/codegen/stc/tests/list_test.c deleted file mode 100644 index b3bc5882..00000000 --- a/src/finchlite/codegen/stc/tests/list_test.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include "ctest.h" - -#define T IList, int, (c_use_cmp) -#include - - -TEST(list, splice) -{ - IList list1 = c_make(IList, {1, 2, 3, 4, 5}); - IList list2 = c_make(IList, {10, 20, 30, 40, 50}); - IList_iter pos = IList_advance(IList_begin(&list1), 2); - - // splice list1 into list2 after pos: - pos = IList_splice(&list1, pos, &list2); - - IList res1 = c_make(IList, {1, 2, 10, 20, 30, 40, 50, 3, 4, 5}); - EXPECT_EQ(*pos.ref, 3); - EXPECT_TRUE(IList_eq(&res1, &list1)); - EXPECT_TRUE(IList_is_empty(&list2)); - - // splice items from pos to end of list1 into empty list2: - IList_splice_range(&list2, IList_begin(&list2), &list1, pos, IList_end(&list1)); - - IList res2 = c_make(IList, {1, 2, 10, 20, 30, 40, 50}); - EXPECT_TRUE(IList_eq(&res2, &list1)); - - IList res3 = c_make(IList, {3, 4, 5}); - EXPECT_TRUE(IList_eq(&res3, &list2)); - EXPECT_FALSE(IList_eq(&list1, &list2)); - - c_drop(IList, &list1, &list2, &res1, &res2, &res3); -} - -TEST(list, erase) -{ - IList L = c_make(IList, {10, 20, 30, 40, 50}); - - IList_iter it = IList_begin(&L); - IList_next(&it); - it = IList_erase_at(&L, it); - - IList res1 = c_make(IList, {10, 30, 40, 50}); - EXPECT_TRUE(IList_eq(&res1, &L)); - - IList_next(&it); - it = IList_erase_range(&L, it, IList_end(&L)); - - IList res2 = c_make(IList, {10, 30}); - EXPECT_TRUE(IList_eq(&res2, &L)); - - c_drop(IList, &L, &res1, &res2); -} - - -TEST(list, misc) -{ - IList nums = {0}, nums2 = {0}; - IList_clear(&nums); - - for (int i = 0; i < 10; ++i) - IList_push_back(&nums, i); - for (int i = 100; i < 110; ++i) - IList_push_back(&nums2, i); - - /* splice nums2 to front of nums */ - IList_splice(&nums, IList_begin(&nums), &nums2); - - IList res1 = c_make(IList, {100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); - EXPECT_TRUE(IList_eq(&res1, &nums)); - - *IList_find(&nums, 104).ref += 50; - IList_remove(&nums, 103); - IList res2 = c_make(IList, {100, 101, 102, 154, 105, 106, 107, 108, 109, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); - EXPECT_TRUE(IList_eq(&res2, &nums)); - - IList_iter it = IList_begin(&nums); - IList_erase_range(&nums, IList_advance(it, 5), IList_advance(it, 15)); - IList res3 = c_make(IList, {100, 101, 102, 154, 105, 6, 7, 8, 9}); - EXPECT_TRUE(IList_eq(&res3, &nums)); - - IList_pop_front(&nums); - IList_push_back(&nums, -99); - IList_sort(&nums); - IList res4 = c_make(IList, {-99, 6, 7, 8, 9, 101, 102, 105, 154}); - EXPECT_TRUE(IList_eq(&res4, &nums)); - - c_drop(IList, &nums, &nums2, &res1, &res2, &res3, &res4); -} diff --git a/src/finchlite/codegen/stc/tests/main.c b/src/finchlite/codegen/stc/tests/main.c deleted file mode 100644 index 2b8931c4..00000000 --- a/src/finchlite/codegen/stc/tests/main.c +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright 2011-2023 Bas van den Berg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#define CTEST_MAIN - -// uncomment lines below to enable/disable features. See README.md for details -//#define CTEST_NO_SEGFAULT -//#define CTEST_NO_COLORS -//#define CTEST_NO_COLOR_OK - -#include "ctest.h" - -int main(int argc, const char *argv[]) -{ - return ctest_main(argc, argv); -} - diff --git a/src/finchlite/codegen/stc/tests/meson.build b/src/finchlite/codegen/stc/tests/meson.build deleted file mode 100644 index 02c70113..00000000 --- a/src/finchlite/codegen/stc/tests/meson.build +++ /dev/null @@ -1,77 +0,0 @@ -tests = get_option('tests').enable_auto_if(root) - -if tests.enabled() - tests_deps = [ - stc_dep, - cc.find_library('m', required: false), - ] - foreach suite, filter : { - 'algorithm': [ - 'cstr_append', - 'c_find_if', - 'c_filter', - ], - 'cregex': [ - 'ISO8601_parse_result', - 'compile_match_char', - 'compile_match_anchors', - 'compile_match_quantifiers1', - 'compile_match_quantifiers2', - 'compile_match_escaped_chars', - 'compile_match_class_simple', - 'compile_match_or', - 'compile_match_class_complex_0', - 'compile_match_class_complex_1', - 'compile_match_cap', - 'search_all', - 'captures_len', - 'captures_cap', - 'replace', - ], - 'cspan': [ - 'subdim', - 'slice', - 'slice2', - 'equality', - ], - 'hmap': [ - 'mapdemo1', - 'mapdemo2', - 'mapdemo3', - ], - 'smap': [ - 'erase', - 'insert', - ], - 'vec': [ - 'basics', - ], - 'deque': [ - 'basics', - ], - 'list': [ - 'splice', - 'erase', - 'misc', - ], - } - test_exe = executable( - f'@suite@_test', - files(f'@suite@_test.c', 'main.c'), - include_directories: inc, - c_args: ['-D_GNU_SOURCE'], - dependencies: tests_deps, - install: false, - ) - foreach unit : filter - test( - unit, - test_exe, - args: [unit], - suite: suite, - ) - endforeach - endforeach - - install_headers('ctest.h', subdir: 'stc') -endif diff --git a/src/finchlite/codegen/stc/tests/mytests.c.txt b/src/finchlite/codegen/stc/tests/mytests.c.txt deleted file mode 100644 index 54413e42..00000000 --- a/src/finchlite/codegen/stc/tests/mytests.c.txt +++ /dev/null @@ -1,233 +0,0 @@ -/* Copyright 2011-2023 Bas van den Berg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "ctest.h" - -// basic test without setup/teardown -CTEST(suite1, test1) { -} - -// there are many different ASSERT macro's (see ctest.h) -CTEST(suite1, test2) { - ASSERT_EQ(1,2); -} - -CTEST(suite2, test1) { - ASSERT_STREQ("foo", "bar"); -} - -CTEST(suite3, test3) { -} - - -// A test suite with a setup/teardown function -// This is converted into a struct that's automatically passed to all tests in the suite -CTEST_FIXTURE(memtest) { - unsigned char* buffer; -}; - -// Optional setup function for suite, called before every test in suite -CTEST_SETUP(memtest) { - CTEST_LOG("%s() data=%p buffer=%p", __func__, (void*)self, (void*)self->buffer); - self->buffer = (unsigned char*)malloc(1024); -} - -// Optional teardown function for suite, called after every test in suite -CTEST_TEARDOWN(memtest) { - CTEST_LOG("%s() data=%p buffer=%p", __func__, (void*)self, (void*)self->buffer); - if (self->buffer) free(self->buffer); -} - -// These tests are called with the struct* (named self) as argument -CTEST_F(memtest, test1) { - CTEST_LOG("%s() data=%p buffer=%p", __func__, (void*)self, (void*)self->buffer); -} - -CTEST_F_SKIP(memtest, test3) { - (void)self; - ASSERT_FAIL(); -} - -CTEST_F(memtest, test2) { - CTEST_LOG("%s() data=%p buffer=%p", __func__, (void*)self, (void*)self->buffer); - ASSERT_FAIL(); -} - - -CTEST_FIXTURE(fail) { - int unused; -}; - -// Asserts can also be used in setup/teardown functions -CTEST_SETUP(fail) { - (void)self; - ASSERT_FAIL(); -} - -CTEST_F(fail, test1) { - (void)self; -} - - - -CTEST_FIXTURE(weaklinkage) { - int number; -}; - -// This suite has data, but no setup/teardown -CTEST_F(weaklinkage, test1) { - (void)self; - CTEST_LOG("%s()", __func__); -} - -CTEST_F(weaklinkage, test2) { - (void)self; - CTEST_LOG("%s()", __func__); -} - - -CTEST_FIXTURE(nosetup) { - int value; -}; - -CTEST_TEARDOWN(nosetup) { - (void)self; - CTEST_LOG("%s()", __func__); -} - -CTEST_F(nosetup, test1) { - (void)self; - CTEST_LOG("%s()", __func__); -} - - -// more ASSERT examples -CTEST(ctest, test_assert_str) { - ASSERT_STREQ("foo", "foo"); - ASSERT_STREQ("foo", "bar"); -} - -CTEST(ctest, test_assert_equal) { - ASSERT_EQ(123, 123); - ASSERT_EQ(123, 456); -} - -CTEST(ctest, test_assert_not_equal) { - ASSERT_NE(123, 456); - ASSERT_NE(123, 123); -} - -CTEST(ctest, test_assert_interval) { - ASSERT_INTERVAL(10, 20, 15); - ASSERT_INTERVAL(1000, 2000, 3000); -} - -CTEST(ctest, test_assert_null) { - ASSERT_NULL(NULL); - ASSERT_NULL((void*)0xdeadbeef); -} - -CTEST(ctest, test_assert_not_null_const) { - char *p = NULL; - ASSERT_PTR_NE(p, (const char*)"hallo"); -} - -CTEST(ctest, test_assert_true) { - ASSERT_TRUE(1); - ASSERT_TRUE(0); -} - -CTEST(ctest, test_assert_false) { - ASSERT_FALSE(0); - ASSERT_FALSE(1); -} - -CTEST_SKIP(ctest, test_skip) { - ASSERT_FAIL(); -} - -CTEST(ctest, test_assert_fail) { - ASSERT_FAIL(); -} - -/* Test that NULL-strings won't result in segv */ -CTEST(ctest, test_null_null) { - ASSERT_STREQ(NULL, NULL); -} - -CTEST(ctest, test_null_string) { - ASSERT_STREQ(NULL, "shouldfail"); -} - -CTEST(ctest, test_string_null) { - ASSERT_STREQ("shouldfail", NULL); -} - -CTEST(ctest, test_string_diff_ptrs) { - const char *str = "abc\0abc"; - ASSERT_STREQ(str, str+4); -} - -CTEST(ctest, test_large_numbers) { - unsigned long exp = 4200000000u; - ASSERT_EQ(exp, 4200000000u); - ASSERT_NE(exp, 1200000000u); -} - -CTEST(ctest, test_ctest_err) { - CTEST_ERR("error log"); -} - -CTEST(ctest, test_dbl_near) { - double a = 0.000111; - ASSERT_DOUBLE_EQ(0.0001, a); -} - -CTEST(ctest, test_dbl_near_tol) { - double a = 0.000111; - ASSERT_NEAR(0.0001, a, 1e-5); /* will fail */ -} - -CTEST(ctest, test_dbl_far) { - double a = 1.1; - ASSERT_DOUBLE_NE(1., a); - ASSERT_NOT_NEAR(1., a, 0.01); -} - -CTEST(ctest, test_assert_compare) { - ASSERT_LT(123, 456); - ASSERT_GE(123, 123); - ASSERT_GT(99, 100); -} - -CTEST(ctest, test_dbl_near2) { - float a = 0.000001000003f; - ASSERT_FLOAT_EQ(0.000001f, a); /* ok, uses float epsilon -1e-5 */ - ASSERT_NEAR(0.000001, a, -1e-5); /* ok, tol < 0 = relative err (epsilon) */ - ASSERT_DOUBLE_EQ(0.000001, a); /* fail, tol = -1e-12 (epsilon) */ -} - -CTEST(ctest, test_dbl_compare) { - float a = 0.000001000003f; - ASSERT_DOUBLE_LT(0.000001, a); - ASSERT_DOUBLE_GT(0.000001, a); /* fail */ -} - -CTEST(ctest, test_str_contains) { - ASSERT_STRNE("Hello", "World"); - ASSERT_SUBSTR("ello", "Hello"); - ASSERT_NOT_SUBSTR("Hell", "Hello"); -} diff --git a/src/finchlite/codegen/stc/tests/run.sh b/src/finchlite/codegen/stc/tests/run.sh deleted file mode 100644 index f2ad39ea..00000000 --- a/src/finchlite/codegen/stc/tests/run.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/bash -# tcc compiler: git://repo.or.cz/tinycc.git -# run tests - -cd $(dirname $(realpath $0)) -if [ -z "$CC" ]; then CC=gcc; fi -if [ ! -z "$1" ]; then CC=$1; fi - -os=$(uname -s) -if [ "$os" == "Linux" ]; then - platform=Linux -elif [ "$os" == "Darwin" ]; then - platform=Mac -else - platform=Windows -fi - -cd .. -make CC=$CC - -build/${platform}_${CC}/tests/test_all -echo "OS=$os, CC=$CC" diff --git a/src/finchlite/codegen/stc/tests/smap_test.c b/src/finchlite/codegen/stc/tests/smap_test.c deleted file mode 100644 index 8b6d057b..00000000 --- a/src/finchlite/codegen/stc/tests/smap_test.c +++ /dev/null @@ -1,145 +0,0 @@ -#include "ctest.h" -#include - -// map_erase.c -// From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16 -#define T Mymap, int, cstr, (c_use_eq | c_valpro) -#include - -TEST(sortedmap, erase) -{ - Mymap m1 = {0}; - Mymap res = {0}; - - // Fill in some data to test with, one at a time - Mymap_insert(&m1, 1, cstr_lit("A")); - Mymap_insert(&m1, 2, cstr_lit("B")); - Mymap_insert(&m1, 3, cstr_lit("C")); - Mymap_insert(&m1, 4, cstr_lit("D")); - Mymap_insert(&m1, 5, cstr_lit("E")); - - // Starting data of map m1 is: - Mymap_take(&res, c_make(Mymap, {{1, "A"}, {2, "B"}, {3, "C"}, {4, "D"}, {5, "E"}})); - EXPECT_TRUE(Mymap_eq(&res, &m1)); - // The 1st member function removes an element at a given position - Mymap_erase_at(&m1, Mymap_advance(Mymap_begin(&m1), 1)); - // After the 2nd element is deleted, the map m1 is: - Mymap_take(&res, c_make(Mymap, {{1, "A"}, {3, "C"}, {4, "D"}, {5, "E"}, })); - EXPECT_TRUE(Mymap_eq(&res, &m1)); - - // Fill in some data to test with - Mymap m2 = c_make(Mymap, { - {10, "Bob"}, - {11, "Rob"}, - {12, "Robert"}, - {13, "Bert"}, - {14, "Bobby"}, - }); - - // Starting data of map m2 is: - Mymap_iter it1 = Mymap_advance(Mymap_begin(&m2), 1); - Mymap_iter it2 = Mymap_find(&m2, Mymap_back(&m2)->first); - - // The 2nd member function removes elements - // in the range [First, Last) - Mymap_erase_range(&m2, it1, it2); - // After the middle elements are deleted, the map m2 is: - Mymap_take(&res, c_make(Mymap, {{10, "Bob"}, {14, "Bobby"}, })); - EXPECT_TRUE(Mymap_eq(&res, &m2)); - - Mymap m3 = {0}; - - // Fill in some data to test with, one at a time, using emplace - Mymap_emplace(&m3, 1, "red"); - Mymap_emplace(&m3, 2, "yellow"); - Mymap_emplace(&m3, 3, "blue"); - Mymap_emplace(&m3, 4, "green"); - Mymap_emplace(&m3, 5, "orange"); - Mymap_emplace(&m3, 6, "purple"); - Mymap_emplace(&m3, 7, "pink"); - - // Starting data of map m3 is: - Mymap_take(&res, c_make(Mymap, {{1, "red"}, {2, "yellow"}, {3, "blue"}, {4, "green"}, {5, "orange"}, {6, "purple"}, {7, "pink"}, })); - EXPECT_TRUE(Mymap_eq(&res, &m3)); - // The 3rd member function removes elements with a given Key - int count = Mymap_erase(&m3, 2); - // The 3rd member function also returns the number of elements removed: - EXPECT_EQ(1, count); - // After the element with a key of 2 is deleted, the map m3 is: - Mymap_take(&res, c_make(Mymap, {{1, "red"}, {3, "blue"}, {4, "green"}, {5, "orange"}, {6, "purple"}, {7, "pink"}})); - EXPECT_TRUE(Mymap_eq(&res, &m3)); - - c_drop(Mymap, &m1, &m2, &m3, &res); -} - - -// map_insert.c -// This implements the std::map insert c++ example at: -// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19 - -#define T Intmap, int, int, (c_use_eq) -#include - -#define T Pairvec, Intmap_raw -#include - -TEST(sortedmap, insert) -{ - // insert single values - Intmap m1 = {0}; - Intmap res = {0}; - - Intmap_insert(&m1, 1, 10); - Intmap_push(&m1, (Intmap_value){2, 20}); - - // The original key and mapped values of m1 are: - Intmap_take(&res, c_make(Intmap, {{1, 10}, {2, 20}})); - EXPECT_TRUE(Intmap_eq(&res, &m1)); - - // intentionally attempt a duplicate, single element - Intmap_result ret = Intmap_insert(&m1, 1, 111); - EXPECT_FALSE(ret.inserted); - - Intmap_insert(&m1, 3, 30); - // The modified key and mapped values of m1 are: - Intmap_take(&res, c_make(Intmap, {{1, 10}, {2, 20}, {3, 30}})); - EXPECT_TRUE(Intmap_eq(&res, &m1)); - - // The templatized version inserting a jumbled range - Intmap m2 = {0}; - Pairvec v = {0}; - Pairvec_push(&v, (Pairvec_value){43, 294}); - Pairvec_push(&v, (Pairvec_value){41, 262}); - Pairvec_push(&v, (Pairvec_value){45, 330}); - Pairvec_push(&v, (Pairvec_value){42, 277}); - Pairvec_push(&v, (Pairvec_value){44, 311}); - - // Inserting the following vector data into m2: - Intmap_put_n(&m2, v.data, Pairvec_size(&v)); - - // The modified key and mapped values of m2 are: - Intmap_take(&res, c_make(Intmap, {{41, 262}, {42, 277}, {43, 294}, {44, 311}, {45, 330}})); - EXPECT_TRUE(Intmap_eq(&res, &m2)); - - // The templatized versions move-constructing elements - Mymap m3 = {0}; - Mymap res3 = {0}; - - Mymap_value ip1 = {475, cstr_lit("blue")}, ip2 = {510, cstr_lit("green")}; - - // single element - Mymap_insert(&m3, ip1.first, cstr_move(&ip1.second)); - // After the first move insertion, m3 contains: - Mymap_take(&res3, c_make(Mymap, {{475, "blue"}})); - EXPECT_TRUE(Mymap_eq(&res3, &m3)); - - // single element - Mymap_insert(&m3, ip2.first, cstr_move(&ip2.second)); - // After the second move insertion, m3 contains: - Mymap_take(&res3, c_make(Mymap, {{475, "blue"}, {510, "green"}})); - EXPECT_TRUE(Mymap_eq(&res3, &m3)); - - c_drop(Intmap, &m1, &m2, &res); - c_drop(Mymap, &m3, &res3); - c_drop(Pairvec, &v); -} diff --git a/src/finchlite/codegen/stc/tests/utf8_test.c b/src/finchlite/codegen/stc/tests/utf8_test.c deleted file mode 100644 index 7a9baa9f..00000000 --- a/src/finchlite/codegen/stc/tests/utf8_test.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include -#include -#include "ctest.h" - -static uint32_t utf8_casefold_bruteforce(uint32_t c) { - for (int i=0; i < casefold_len; ++i) { - const struct CaseMapping entry = casemappings[i]; - if (c <= entry.c2) { - if (c < entry.c1) return c; - int d = entry.m2 - entry.c2; - if (d == 1) return c + ((entry.c2 & 1U) == (c & 1U)); - return (uint32_t)((int)c + d); - } - } - return c; -} - -static uint32_t utf8_tolower_bruteforce(uint32_t c) { - for (int i=0; i < (int)(sizeof upcase_ind/sizeof *upcase_ind); ++i) { - const struct CaseMapping entry = casemappings[upcase_ind[i]]; - if (c <= entry.c2) { - if (c < entry.c1) return c; - int d = entry.m2 - entry.c2; - if (d == 1) return c + ((entry.c2 & 1U) == (c & 1U)); - return (uint32_t)((int)c + d); - } - } - return c; -} - -static uint32_t utf8_toupper_bruteforce(uint32_t c) { - for (int i=0; i < (int)(sizeof lowcase_ind/sizeof *lowcase_ind); ++i) { - const struct CaseMapping entry = casemappings[lowcase_ind[i]]; - if (c <= entry.m2) { - int d = entry.m2 - entry.c2; - if (c < (uint32_t)(entry.c1 + d)) return c; - if (d == 1) return c - ((entry.m2 & 1U) == (c & 1U)); - return (uint32_t)((int)c - d); - } - } - return c; -} - -TEST(utf8, utf8_casefold) -{ - for (unsigned ch = 0; ch < 0x20000; ++ch) - EXPECT_EQ(utf8_casefold(ch), utf8_casefold_bruteforce(ch)); -} - -TEST(utf8, utf8_tolower) -{ - for (unsigned ch = 0; ch < 0x20000; ++ch) - EXPECT_EQ(utf8_tolower(ch), utf8_tolower_bruteforce(ch)); -} - -TEST(utf8, utf8_toupper) -{ - for (unsigned ch = 0; ch < 0x20000; ++ch) - EXPECT_EQ(utf8_toupper(ch), utf8_toupper_bruteforce(ch)); -} - -#if 0 -TEST(utf8, bench_utf8_casefold) -{ - long long t = cco_ticks(); - int repeats = 500; - for (int i = 0; i < repeats; i++) - for (unsigned ch = 1; ch < 65536; ++ch) - EXPECT_TRUE(utf8_casefold(ch)); - printf("binary=%lldus\n", (cco_ticks() - t) / repeats); - - t = cco_ticks(); - repeats = 100; - for (int i = 0; i < repeats; i++) - for (unsigned ch = 1; ch < 65536; ++ch) - EXPECT_TRUE(utf8_casefold_bruteforce(ch)); - printf("bruteforce=%lldus\n", (cco_ticks() - t) / repeats); -} -#endif diff --git a/src/finchlite/codegen/stc/tests/vec_test.c b/src/finchlite/codegen/stc/tests/vec_test.c deleted file mode 100644 index 7e07998b..00000000 --- a/src/finchlite/codegen/stc/tests/vec_test.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "ctest.h" - -#define T IVec, int, (c_use_eq) -#include - - -TEST(vec, basics) { - IVec d = c_make(IVec, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); - EXPECT_EQ(12, IVec_size(&d)); - - IVec_erase_n(&d, 0, 5); - for (c_range32(i, 2, 9)) - IVec_push_back(&d, i*10); - - IVec res = c_make(IVec, {6, 7, 8, 9, 10, 11, 12, 20, 30, 40, 50, 60, 70, 80}); - EXPECT_TRUE(IVec_eq(&res, &d)); - EXPECT_EQ(14, IVec_size(&d)); - - IVec_erase_n(&d, 7, 4); - - IVec_take(&res, c_make(IVec, {6, 7, 8, 9, 10, 11, 12, 60, 70, 80})); - EXPECT_TRUE(IVec_eq(&res, &d)); - - int nums[] = {200, 300, 400, 500}; - IVec_insert_n(&d, 7, nums, 4); - - IVec_take(&res, c_make(IVec, {6, 7, 8, 9, 10, 11, 12, 200, 300, 400, 500, 60, 70, 80})); - EXPECT_TRUE(IVec_eq(&res, &d)); - - EXPECT_EQ(14, IVec_size(&d)); - EXPECT_EQ(200, *IVec_at(&d, 7)); - - c_drop(IVec, &d, &res); -} diff --git a/src/finchlite/finch_assembly/__init__.py b/src/finchlite/finch_assembly/__init__.py index 59c0ac8a..daae8fc9 100644 --- a/src/finchlite/finch_assembly/__init__.py +++ b/src/finchlite/finch_assembly/__init__.py @@ -9,7 +9,6 @@ assembly_dataflow_analyze, assembly_dataflow_run, ) -from .dct import Dict, DictFType from .interpreter import AssemblyInterpreter, AssemblyInterpreterKernel from .nodes import ( AssemblyExpression, @@ -20,7 +19,6 @@ Break, BufferLoop, Call, - ExistsDict, ForLoop, Function, GetAttr, @@ -30,9 +28,7 @@ Length, Literal, Load, - LoadDict, Module, - Print, Repack, Resize, Return, @@ -40,7 +36,6 @@ Slot, Stack, Store, - StoreDict, Unpack, Variable, WhileLoop, @@ -73,9 +68,6 @@ "BufferFType", "BufferLoop", "Call", - "Dict", - "DictFType", - "ExistsDict", "ForLoop", "Function", "GetAttr", @@ -85,10 +77,8 @@ "Length", "Literal", "Load", - "LoadDict", "Module", "NumberedStatement", - "Print", "Repack", "Resize", "Return", @@ -96,7 +86,6 @@ "Slot", "Stack", "Store", - "StoreDict", "Unpack", "Variable", "WhileLoop", diff --git a/src/finchlite/finch_assembly/cfg_builder.py b/src/finchlite/finch_assembly/cfg_builder.py index 6a4eb282..bb21da0a 100644 --- a/src/finchlite/finch_assembly/cfg_builder.py +++ b/src/finchlite/finch_assembly/cfg_builder.py @@ -28,7 +28,6 @@ Literal, Load, Module, - Print, Repack, Resize, Return, @@ -220,18 +219,15 @@ def rw(x: AssemblyNode) -> AssemblyNode | None: nonlocal sid if isinstance( x, - ( - Unpack, - Repack, - Resize, - SetAttr, - Print, - Store, - Assign, - Assert, - Return, - Break, - ), + Unpack + | Repack + | Resize + | SetAttr + | Store + | Assign + | Assert + | Return + | Break, ): s = NumberedStatement(x, sid) sid += 1 diff --git a/src/finchlite/finch_assembly/dct.py b/src/finchlite/finch_assembly/dct.py deleted file mode 100644 index 67b27fd1..00000000 --- a/src/finchlite/finch_assembly/dct.py +++ /dev/null @@ -1,90 +0,0 @@ -from abc import ABC, abstractmethod - -import numpy as np - -from finchlite.algebra import FType, FTyped - - -class Dict(FTyped, ABC): - """ - Abstract base class for a map data structure. - Hash tables should be such that their bucket size can be resized, with Tree - maps turning that into a no-op. - """ - - @abstractmethod - def __init__( - self, key_len: int, value_len: int, map: "dict[tuple,tuple] | None" - ): ... - - @property - @abstractmethod - def ftype(self) -> "DictFType": ... - - @property - def value_type(self): - """ - Return type of values stored in the hash table - (probably some TupleFType) - """ - return self.ftype.value_type - - @property - def key_type(self): - """ - Return type of keys stored in the hash table - (probably some TupleFType) - """ - return self.ftype.key_type - - @abstractmethod - def load(self, idx: tuple): - """ - Method to access some element in the map. Will panic if the key doesn't exist. - """ - ... - - @abstractmethod - def exists(self, idx: tuple) -> np.bool: - """ - Method to check if the element exists in the map. - """ - ... - - @abstractmethod - def store(self, idx: tuple, val): - """ - Method to store elements in the map. Ideally it should just create new - elements. - """ - ... - - -class DictFType(FType): - """ - Abstract base class for an ftype corresponding to a map. - """ - - @abstractmethod - def __call__(self, *args, **kwargs): - """ - Create an instance of an object in this ftype with the given arguments. - """ - ... - - @property - @abstractmethod - def value_type(self): - """ - Return the type of elements stored in the map. - This is typically the same as the dtype used to create the map. - """ - ... - - @property - @abstractmethod - def key_type(self): - """ - Returns the type used for the length of the map. - """ - ... diff --git a/src/finchlite/finch_assembly/dev_doc.md b/src/finchlite/finch_assembly/dev_doc.md index 8327cb9d..66ee299f 100644 --- a/src/finchlite/finch_assembly/dev_doc.md +++ b/src/finchlite/finch_assembly/dev_doc.md @@ -11,7 +11,7 @@ The following is a rough grammar for FinchAssembly, written in terms of the curr EXPR := LITERAL | VARIABLE | SLOT | STACK | GETATTR | CALL | LOAD | LENGTH STMT := UNPACK | REPACK | ASSIGN | SETATTR | STORE | RESIZE | FORLOOP | BUFFERLOOP | WHILELOOP | IF | IFELSE | FUNCTION | RETURN | BREAK - | BLOCK | MODULE | LOADMAP | STOREMAP | EXISTSMAP + | BLOCK | MODULE NODE := EXPR | STMT LITERAL := Literal(val=VALUE) @@ -27,9 +27,6 @@ LOAD := Load(buffer=SLOT | STACK, index=EXPR) STORE := Store(buffer=SLOT | STACK, index=EXPR, value=EXPR) RESIZE := Resize(buffer=SLOT | STACK, new_size=EXPR) LENGTH := Length(buffer=SLOT | STACK) -LOADMAP := LoadMap(map=SLOT | STACK, index=EXPR) -STOREMAP := StoreMap(map=SLOT | STACK, index=EXPR, value=EXPR) -EXISTSMAP := ExistMap(map=SLOT | STACK, index=EXPR) STACK := Stack(obj=ANY, type=TYPE) FORLOOP := ForLoop(var=VARIABLE, start=EXPR, end=EXPR, body=NODE) BUFFERLOOP := BufferLoop(buffer=EXPR, var=VARIABLE, body=NODE) diff --git a/src/finchlite/finch_assembly/interpreter.py b/src/finchlite/finch_assembly/interpreter.py index 50b28449..e89feff1 100644 --- a/src/finchlite/finch_assembly/interpreter.py +++ b/src/finchlite/finch_assembly/interpreter.py @@ -223,16 +223,6 @@ def _dispatch(self, prgm): buf_e = self(buf) idx_e = self(idx) return buf_e.load(idx_e) - case asm.LoadDict(dct, idx): - assert isinstance(dct, asm.Slot) - map_e = self(dct) - idx_e = self(idx) - return map_e.load(idx_e) - case asm.ExistsDict(dct, idx): - assert isinstance(dct, asm.Slot) - map_e = self(dct) - idx_e = self(idx) - return map_e.exists(idx_e) case asm.Store(buf, idx, val): assert isinstance(buf, asm.Slot) buf_e = self(buf) @@ -240,12 +230,6 @@ def _dispatch(self, prgm): val_e = self(val) buf_e.store(idx_e, val_e) return None - case asm.StoreDict(dct, idx, val): - assert isinstance(dct, asm.Slot) - map_e = self(dct) - idx_e = self(idx) - val_e = self(val) - return map_e.store(idx_e, val_e) case asm.Resize(buf, len_): assert isinstance(buf, asm.Slot) buf_e = self(buf) @@ -370,12 +354,6 @@ def my_func(*args_e): f"Unrecognized function definition: {func}" ) return AssemblyInterpreterLibrary(self, kernels) - case asm.Print(args): - args_value_str = "" - for arg in args: - args_value_str = args_value_str + f"{self(arg)} " - print(args_value_str, file=self.stdout) - return None case asm.Stack(val): raise NotImplementedError( "AssemblyInterpreter does not support symbolic, no target language" diff --git a/src/finchlite/finch_assembly/nodes.py b/src/finchlite/finch_assembly/nodes.py index 93250597..f47af1df 100644 --- a/src/finchlite/finch_assembly/nodes.py +++ b/src/finchlite/finch_assembly/nodes.py @@ -2,7 +2,7 @@ from dataclasses import asdict, dataclass from typing import Any -from finchlite.algebra import ftype, ftypes, return_type +from finchlite.algebra import ftype, return_type from finchlite.algebra.ftypes import FType from finchlite.symbolic import Context, NamedTerm, Term, TermTree, literal_repr from finchlite.util import qual_str @@ -346,68 +346,6 @@ def children(self): return [self.buffer, self.index, self.value] -@dataclass(eq=True, frozen=True) -class ExistsDict(AssemblyExpression, AssemblyTree): - """ - Represents checking whether an integer tuple key is in a map. - - Attributes: - map: The map to load from. - index: The key to check for existence. - """ - - map: Slot | Stack - index: AssemblyExpression - - @property - def children(self): - return [self.map, self.index] - - def result_type(self): - return ftypes.bool - - -@dataclass(eq=True, frozen=True) -class LoadDict(AssemblyExpression, AssemblyTree): - """ - Represents loading a value from a map given an integer tuple key. - - Attributes: - map: The map to load from. - index: The key value - """ - - dct: Slot | Stack - index: AssemblyExpression - - @property - def children(self): - return [self.dct, self.index] - - def result_type(self): - return self.dct.result_type.value_type - - -@dataclass(eq=True, frozen=True) -class StoreDict(AssemblyTree, AssemblyStatement): - """ - Represents storing a value into a buffer given an integer tuple key. - - Attributes: - map: The map to load from. - index1: The first integer in the pair - index2: The second integer in the pair - """ - - map: Slot | Stack - index: AssemblyExpression - value: AssemblyExpression - - @property - def children(self): - return [self.map, self.index, self.value] - - @dataclass(eq=True, frozen=True) class Resize(AssemblyTree, AssemblyStatement): """ @@ -672,23 +610,6 @@ def from_children(cls, *funcs): return cls(funcs) -@dataclass(eq=True, frozen=True) -class Print(AssemblyTree, AssemblyStatement): - """ - Print values of give variables. - - Attributes: - args: list of variables to be printed. - """ - - args: tuple[Variable, ...] - - @property - def children(self): - """Returns the children of the node.""" - return [*self.args] - - class AssemblyPrinterContext(Context): def __init__(self, tab=" ", indent=0): super().__init__() @@ -747,18 +668,11 @@ def __call__(self, prgm: AssemblyNode, emit_calls: bool = False): return None case Load(buf, idx): return f"load({self(buf)}, {self(idx)})" - case LoadDict(map, idx): - return f"loadmap({self(map)}, {self(idx)})" - case ExistsDict(map, idx): - return f"existsmap({self(map)}, {self(idx)})" case Slot(name, type_): return f"slot({name}, {qual_str(type_)})" case Store(buf, idx, val): self.exec(f"{feed}store({self(buf)}, {self(idx)}, {self(val)})") return None - case StoreDict(map, idx, val): - self.exec(f"{feed}storemap({self(map)}, {self(idx)}, {self(val)})") - return None case Resize(buf, size): self.exec(f"{feed}resize({self(buf)}, {self(size)})") return None @@ -856,13 +770,6 @@ def __call__(self, prgm: AssemblyNode, emit_calls: bool = False): ) self(func) return None - case Print(args): - args_value_str = "" - for arg in args: - if isinstance(arg, Variable): - args_value_str = args_value_str + f"{{{self(arg)}}} " - self.exec(f"{feed}print(f'{args_value_str}')") - return None case Stack(obj, type_): self.exec(f"{feed}stack({self(obj)}, {str(type_)})") return None diff --git a/src/finchlite/finch_assembly/type_checker.py b/src/finchlite/finch_assembly/type_checker.py index d8d01733..846b2481 100644 --- a/src/finchlite/finch_assembly/type_checker.py +++ b/src/finchlite/finch_assembly/type_checker.py @@ -5,12 +5,10 @@ from finchlite import algebra from finchlite.algebra import FType, StructFType, ftype from finchlite.algebra.ftypes import FDTypeBoolean, FDTypeInteger, FDTypeNumeric -from finchlite.algebra.ftypes import bool as finch_bool from finchlite.symbolic import ScopedDict from . import nodes as asm from .buffer import BufferFType -from .dct import DictFType class AssemblyTypeError(Exception): @@ -85,12 +83,6 @@ def check_in_ctxt(self, var_n, var_t): f"The variable '{var_n}' is not defined in the current context." ) from KeyError - def check_dict(self, dct): - map_type = self.check_expr(dct) - if isinstance(map_type, DictFType): - return map_type - raise AssemblyTypeError(f"Expected map, got {map_type}.") - def check_buffer(self, buffer): buffer_type = self.check_expr(buffer) if isinstance(buffer_type, BufferFType): @@ -143,16 +135,6 @@ def check_expr(self, expr: asm.AssemblyExpression): case asm.Length(buffer): buffer_type = self.check_buffer(buffer) return buffer_type.length_type - case asm.ExistsDict(dct, index): - map_type = self.check_dict(dct) - index_type = self.check_expr(index) - check_type_match(map_type.key_type, index_type) - return finch_bool - case asm.LoadDict(dct, index): - map_type = self.check_dict(dct) - index_type = self.check_expr(index) - check_type_match(map_type.key_type, index_type) - return map_type.value_type case _: raise ValueError(f"Ill-formed AssemblyExpression: {type(expr)}.") @@ -200,13 +182,6 @@ def check_stmt(self, stmt: asm.AssemblyStatement): value_type = self.check_expr(value) check_type_match(buffer_type.element_type, value_type) return None - case asm.StoreDict(map, index, value): - map_type = self.check_dict(map) - index_type = self.check_expr(index) - value_type = self.check_expr(value) - check_type_match(map_type.key_type, index_type) - check_type_match(map_type.value_type, value_type) - return None case asm.Resize(buffer, new_size): buffer_type = self.check_buffer(buffer) new_size_type = self.check_expr(new_size) diff --git a/src/finchlite/finch_notation/interpreter.py b/src/finchlite/finch_notation/interpreter.py index 6f2e94d6..767f0510 100644 --- a/src/finchlite/finch_notation/interpreter.py +++ b/src/finchlite/finch_notation/interpreter.py @@ -429,20 +429,14 @@ def _dispatch(self, prgm: ntn.NotationNode | asm.AssemblyNode): assert isinstance(tns, ntn.Slot) tns_e = self(tns) idxs_e = [self(idx) for idx in idxs] - try: - match mode: - case ntn.Read(): - return access(tns_e, idxs_e) - case ntn.Update(op): - op_e = self(op) - return access(tns_e, idxs_e, op=op_e) - case _: - raise NotImplementedError( - f"Unrecognized access mode: {mode}" - ) - except Exception as e: - print(f"Error during tensor access {prgm}") - raise e + match mode: + case ntn.Read(): + return access(tns_e, idxs_e) + case ntn.Update(op): + op_e = self(op) + return access(tns_e, idxs_e, op=op_e) + case _: + raise NotImplementedError(f"Unrecognized access mode: {mode}") case ntn.Dimension(tns, r): assert isinstance(tns, ntn.Slot) @@ -453,11 +447,7 @@ def _dispatch(self, prgm: ntn.NotationNode | asm.AssemblyNode): case ntn.Increment(tns, val): tns_e = self(tns) val_e = self(val) - try: - increment(tns_e, val_e) - except Exception as e: - print(f"Error during tensor increment {prgm}") - raise e + increment(tns_e, val_e) return None case ntn.Block(bodies): for body in bodies: diff --git a/tests/reference/test_asm_print.txt b/tests/reference/test_asm_print.txt deleted file mode 100644 index bc911dfa..00000000 --- a/tests/reference/test_asm_print.txt +++ /dev/null @@ -1,5 +0,0 @@ -Point(x=np.float64(1.0), y=np.float64(2.0)) -(1, 4) -Point(x=np.float64(1.0), y=np.float64(2.0)) (1, 4) -9.0 -Point(x=np.float64(1.0), y=np.float64(2.0)) (1, 4) 9.0 diff --git a/tests/test_assembly_interpreter.py b/tests/test_assembly_interpreter.py index 35d01bac..0392f4fc 100644 --- a/tests/test_assembly_interpreter.py +++ b/tests/test_assembly_interpreter.py @@ -20,7 +20,6 @@ IfElse, Literal, Module, - Print, Return, Variable, ) @@ -228,71 +227,3 @@ def test_simple_struct(): result = mod.simple_struct(p, x) assert result == 9.0 - - -def test_asm_print(capsys, file_regression): - p_var_name = "p" - x_var_name = "x" - res_var_name = "res" - - Point = namedtuple("Point", ["x", "y"]) - p = Point(np.float64(1.0), np.float64(2.0)) - x = (1, 4) - - p_var = asm.Variable(p_var_name, ftype(p)) - x_var = asm.Variable(x_var_name, ftype(x)) - res_var = asm.Variable(res_var_name, finchlite.float64) - mod = AssemblyInterpreter()( - asm.Module( - ( - asm.Function( - asm.Variable("simple_struct", finchlite.float64), - (p_var, x_var), - asm.Block( - ( - asm.Print((p_var,)), - asm.Print((x_var,)), - asm.Print((p_var, x_var)), - asm.Assign( - res_var, - asm.Call( - asm.Literal(ffuncs.mul), - ( - asm.GetAttr(p_var, asm.Literal("x")), - asm.GetAttr(x_var, asm.Literal("element_0")), - ), - ), - ), - asm.Assign( - res_var, - asm.Call( - asm.Literal(ffuncs.add), - ( - res_var, - asm.Call( - asm.Literal(ffuncs.mul), - ( - asm.GetAttr(p_var, asm.Literal("y")), - asm.GetAttr( - x_var, asm.Literal("element_1") - ), - ), - ), - ), - ), - ), - asm.Print((res_var,)), - asm.Print((p_var, x_var, res_var)), - asm.Return(res_var), - ) - ), - ), - ), - ) - ) - - result = mod.simple_struct(p, x) - assert result == 9.0 - - capture = capsys.readouterr().out - file_regression.check(capture, extension=".txt") diff --git a/tests/test_assembly_type_checker.py b/tests/test_assembly_type_checker.py index 2b2016ee..ed516ac9 100644 --- a/tests/test_assembly_type_checker.py +++ b/tests/test_assembly_type_checker.py @@ -7,9 +7,8 @@ import finchlite import finchlite.finch_assembly as asm from finchlite import ffuncs -from finchlite.algebra import FType, TupleFType, ftype +from finchlite.algebra import FType, ftype from finchlite.codegen import NumpyBuffer -from finchlite.codegen.buffers import CHashTable, NumbaHashTable from finchlite.finch_assembly import assembly_check_types @@ -691,101 +690,3 @@ def test_simple_struct(): ) assembly_check_types(mod) - - -@pytest.mark.parametrize( - ["constructor"], - [(CHashTable,), (NumbaHashTable,)], -) -def test_hashtable(constructor): - table = constructor( - TupleFType.from_tuple((finchlite.int_, finchlite.int_)), - TupleFType.from_tuple((finchlite.int_, finchlite.int_, finchlite.int_)), - ) - - table_v = asm.Variable("a", ftype(table)) - table_slt = asm.Slot("a_", ftype(table)) - - key_type = table.ftype.key_type - val_type = table.ftype.value_type - key_v = asm.Variable("key", key_type) - val_v = asm.Variable("val", val_type) - - mod = asm.Module( - ( - asm.Function( - asm.Variable( - "setidx", - TupleFType.from_tuple(tuple(finchlite.int_ for _ in range(3))), - ), - (table_v, key_v, val_v), - asm.Block( - ( - asm.Unpack(table_slt, table_v), - asm.StoreDict( - table_slt, - key_v, - val_v, - ), - asm.Repack(table_slt), - asm.Return(asm.LoadDict(table_slt, key_v)), - ) - ), - ), - asm.Function( - asm.Variable("exists", finchlite.bool), - (table_v, key_v), - asm.Block( - ( - asm.Unpack(table_slt, table_v), - asm.Return(asm.ExistsDict(table_slt, key_v)), - ) - ), - ), - ) - ) - assembly_check_types(mod) - - -@pytest.mark.parametrize( - ["constructor"], - [(CHashTable,), (NumbaHashTable,)], -) -def test_hashtable_fail(constructor): - table = constructor( - TupleFType.from_tuple((finchlite.int_, finchlite.int_)), - TupleFType.from_tuple((finchlite.int_, finchlite.int_, finchlite.int_)), - ) - - table_v = asm.Variable("a", ftype(table)) - table_slt = asm.Slot("a_", ftype(table)) - - key_type = table.ftype.key_type - val_type = table.ftype.value_type - key_v = asm.Variable("key", key_type) - val_v = asm.Variable("val", val_type) - mod = asm.Module( - ( - asm.Function( - asm.Variable( - "setidx", - TupleFType.from_tuple(tuple(finchlite.int_ for _ in range(2))), - ), - (table_v, key_v, val_v), - asm.Block( - ( - asm.Unpack(table_slt, table_v), - asm.StoreDict( - table_slt, - key_v, - val_v, - ), - asm.Repack(table_slt), - asm.Return(asm.LoadDict(table_slt, key_v)), - ) - ), - ), - ) - ) - with pytest.raises(asm.AssemblyTypeError): - assembly_check_types(mod) diff --git a/tests/test_codegen.py b/tests/test_codegen.py index 00ae2d39..e9256c45 100644 --- a/tests/test_codegen.py +++ b/tests/test_codegen.py @@ -12,7 +12,7 @@ import finchlite import finchlite.finch_assembly as asm from finchlite import dense, element, ffuncs, fiber_tensor, ftype -from finchlite.algebra import TupleFType, ftypes +from finchlite.algebra import ftypes from finchlite.codegen import ( CCompiler, CGenerator, @@ -22,7 +22,7 @@ NumpyBufferFType, SafeBuffer, ) -from finchlite.codegen.buffers import CHashTable, MallocBuffer, NumbaHashTable +from finchlite.codegen.buffers import MallocBuffer from finchlite.codegen.c_codegen import ( construct_from_c, deserialize_from_c, @@ -980,191 +980,3 @@ def test_e2e_transpose_numba(a, dtype): wa = finchlite.lazy(finchlite.asarray(a)) result = finchlite.compute(finchlite.permute_dims(wa, axes=(1, 0))) finch_assert_equal(result, a.T) - - -@pytest.mark.parametrize( - ["compiler", "constructor"], - [ - ( - CCompiler(), - CHashTable, - ), - ( - asm.AssemblyInterpreter(), - CHashTable, - ), - ( - NumbaCompiler(), - NumbaHashTable, - ), - ( - asm.AssemblyInterpreter(), - NumbaHashTable, - ), - ], -) -def test_hashtable(compiler, constructor): - table = constructor( - TupleFType.from_tuple((ftypes.int_, ftypes.int_)), - TupleFType.from_tuple((ftypes.int_, ftypes.int_, ftypes.int_)), - ) - - table_v = asm.Variable("a", ftype(table)) - table_slt = asm.Slot("a_", ftype(table)) - - key_type = table.ftype.key_type - val_type = table.ftype.value_type - key_v = asm.Variable("key", key_type) - val_v = asm.Variable("val", val_type) - - module = asm.Module( - ( - asm.Function( - asm.Variable("setidx", val_type), - (table_v, key_v, val_v), - asm.Block( - ( - asm.Unpack(table_slt, table_v), - asm.StoreDict( - table_slt, - key_v, - val_v, - ), - asm.Repack(table_slt), - asm.Return(asm.LoadDict(table_slt, key_v)), - ) - ), - ), - asm.Function( - asm.Variable("exists", ftypes.bool), - (table_v, key_v), - asm.Block( - ( - asm.Unpack(table_slt, table_v), - asm.Return(asm.ExistsDict(table_slt, key_v)), - ) - ), - ), - ) - ) - compiled = compiler(module) - assert compiled.setidx( - table, - key_type.from_fields(1, 2), - val_type.from_fields(2, 3, 4), - ) == val_type.from_fields(2, 3, 4) - - assert compiled.setidx( - table, - key_type.from_fields(1, 4), - val_type.from_fields(3, 4, 1), - ) == val_type.from_fields(3, 4, 1) - - assert compiled.exists(table, key_type.from_fields(1, 2)) - - assert not compiled.exists(table, key_type.from_fields(1, 3)) - - assert not compiled.exists(table, val_type.from_fields(2, 3)) - - -@pytest.mark.parametrize( - ["compiler", "tabletype"], - [ - (CCompiler(), CHashTable), - (asm.AssemblyInterpreter(), CHashTable), - (NumbaCompiler(), NumbaHashTable), - (asm.AssemblyInterpreter(), NumbaHashTable), - ], -) -def test_multiple_hashtable(compiler, tabletype): - """ - This test exists because in the case of C, we might need to dump multiple - hash table definitions into the context. - - So I am not gonna touch heterogeneous structs right now because the hasher - hashes the padding bytes too (even though they are worse than useless) - """ - - def _int_tupletype(arity): - return TupleFType.from_tuple(tuple(ftypes.int_ for _ in range(arity))) - - def func(table, num: int): - key_type = table.ftype.key_type - val_type = table.ftype.value_type - key_v = asm.Variable("key", key_type) - val_v = asm.Variable("val", val_type) - table_v = asm.Variable("a", ftype(table)) - table_slt = asm.Slot("a_", ftype(table)) - return asm.Function( - asm.Variable(f"setidx_{num}", val_type), - (table_v, key_v, val_v), - asm.Block( - ( - asm.Unpack(table_slt, table_v), - asm.StoreDict( - table_slt, - key_v, - val_v, - ), - asm.Repack(table_slt), - asm.Return(asm.LoadDict(table_slt, key_v)), - ) - ), - ) - - table1 = tabletype(_int_tupletype(2), _int_tupletype(3)) - table2 = tabletype(_int_tupletype(1), _int_tupletype(4)) - table3 = tabletype( - TupleFType.from_tuple((ftypes.float_, ftypes.int_)), - TupleFType.from_tuple((ftypes.float_, ftypes.float_)), - ) - table4 = tabletype( - TupleFType.from_tuple( - (ftypes.float_, TupleFType.from_tuple((ftypes.int_, ftypes.float_))) - ), - TupleFType.from_tuple((ftypes.float_, ftypes.float_)), - ) - table5 = tabletype(ftypes.int_, ftypes.int_) - - mod = compiler( - asm.Module( - ( - func(table1, 1), - func(table2, 2), - func(table3, 3), - func(table4, 4), - func(table5, 5), - ) - ) - ) - - # what's important here is that you can call setidx_1 on table1 and - # setidx_2 on table2. - assert mod.setidx_1( - table1, - (1, 2), - (2, 3, 4), - ) == (2, 3, 4) - - assert mod.setidx_2( - table2, - (1,), - (2, 3, 4, 5), - ) == (2, 3, 4, 5) - - assert mod.setidx_3( - table3, - (0.1, 2), - (0.2, 0.2), - ) == (0.2, 0.2) - - assert mod.setidx_4( - table4, - ( - 0.1, - (1, 0.2), - ), - (0.2, 0.2), - ) == (0.2, 0.2) - - assert mod.setidx_5(table5, 3, 2) == 2