├── .gitattributes ├── .github └── workflows │ └── meson.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── docs ├── algorithm_api.md ├── arc_api.md ├── box_api.md ├── cbits_api.md ├── coption_api.md ├── coroutine_api.md ├── cregex_api.md ├── cspan_api.md ├── cstr_api.md ├── csview_api.md ├── deque_api.md ├── hmap_api.md ├── hset_api.md ├── list_api.md ├── pics │ ├── Figure_1.png │ ├── array.jpg │ ├── bitset.jpg │ ├── containers.jpg │ ├── coroutine.png │ ├── deque.jpg │ ├── list.jpg │ ├── map.jpg │ ├── queue.jpg │ ├── random.jpg │ ├── set.jpg │ ├── smap.jpg │ ├── sset.jpg │ ├── stack.jpg │ ├── string.jpg │ └── vector.jpg ├── pqueue_api.md ├── queue_api.md ├── random_api.md ├── smap_api.md ├── sset_api.md ├── stack_api.md ├── utf8_api.md ├── vec_api.md └── zsview_api.md ├── examples ├── README.md ├── algorithms │ ├── filterdemos.c │ ├── forloops.c │ ├── meson.build │ ├── random.c │ ├── shape.c │ └── shape.cpp ├── bitsets │ ├── bits.c │ ├── bits2.c │ ├── meson.build │ └── prime.c ├── coroutines │ ├── cointerleave.c │ ├── coread.c │ ├── coroutine_tasks.c │ ├── coroutines.c │ ├── dining_philosophers.c │ ├── fibonacci.c │ ├── filetask.c │ ├── generator.c │ ├── meson.build │ ├── producer.c │ ├── producer_task.c │ ├── scheduler.c │ └── triples.c ├── hashmaps │ ├── birthday.c │ ├── books.c │ ├── hashmap.c │ ├── mapmap.c │ ├── meson.build │ ├── new_map.c │ ├── phonebook.c │ ├── unordered_set.c │ └── vikings.c ├── linkedlists │ ├── intrusive.c │ ├── list_erase.c │ ├── list_splice.c │ ├── lists.c │ ├── meson.build │ └── new_list.c ├── make.sh ├── meson.build ├── mixed │ ├── astar.c │ ├── complex.c │ ├── convert.c │ ├── demos.c │ ├── inits.c │ ├── meson.build │ └── read.c ├── priorityqueues │ ├── functor.c │ ├── meson.build │ ├── new_pqueue.c │ └── priority.c ├── queues │ ├── meson.build │ ├── new_queue.c │ └── queue.c ├── regularexpressions │ ├── meson.build │ ├── regex1.c │ ├── regex2.c │ ├── regex_match.c │ └── regex_replace.c ├── smartpointers │ ├── arc_containers.c │ ├── arc_demo.c │ ├── arcvec_erase.c │ ├── box.c │ ├── box2.c │ ├── map_box.c │ ├── map_ptr.c │ ├── meson.build │ ├── music_arc.c │ └── person_arc.c ├── sortedmaps │ ├── gauss2.c │ ├── listmap.c │ ├── meson.build │ ├── multimap.c │ ├── new_smap.c │ ├── smap_erase.c │ ├── smap_find.c │ ├── smap_insert.c │ ├── sorted_map.c │ └── sset_erase.c ├── spans │ ├── matmult.c │ ├── mdspan.c │ ├── meson.build │ ├── multidim.c │ ├── printspan.c │ ├── span_demo.c │ └── submdspan.c ├── strings │ ├── cstr_match.c │ ├── meson.build │ ├── replace.c │ ├── splitstr.c │ ├── sso_map.c │ ├── sso_substr.c │ ├── sview_split.c │ ├── utf8replace_c.c │ └── utf8replace_rs.rs └── vectors │ ├── lower_bound.c │ ├── meson.build │ ├── new_vec.c │ └── stack.c ├── include ├── c11 │ └── fmt.h └── stc │ ├── algorithm.h │ ├── arc.h │ ├── box.h │ ├── cbits.h │ ├── common.h │ ├── coption.h │ ├── coroutine.h │ ├── cregex.h │ ├── cspan.h │ ├── cstr.h │ ├── csview.h │ ├── deque.h │ ├── hashmap.h │ ├── hashset.h │ ├── hmap.h │ ├── hset.h │ ├── list.h │ ├── pqueue.h │ ├── priv │ ├── cregex_prv.c │ ├── cstr_prv.c │ ├── cstr_prv.h │ ├── linkage.h │ ├── linkage2.h │ ├── queue_prv.h │ ├── sort_prv.h │ ├── template.h │ ├── template2.h │ ├── ucd_prv.c │ ├── utf8_prv.c │ ├── utf8_prv.h │ └── utf8_tab.c │ ├── queue.h │ ├── random.h │ ├── smap.h │ ├── sort.h │ ├── sortedmap.h │ ├── sortedset.h │ ├── sset.h │ ├── stack.h │ ├── sys │ ├── crange.h │ ├── filter.h │ ├── sumtype.h │ └── utility.h │ ├── types.h │ ├── utf8.h │ ├── vec.h │ └── zsview.h ├── meson.build ├── meson_options.txt ├── src ├── checkscoped.l ├── cregex.c ├── cspan.c ├── cstr_core.c ├── cstr_io.c ├── cstr_utf8.c ├── csview.c ├── fmt.c ├── random.c ├── singleheader.py ├── singleupdate.sh ├── stc_core.c └── utf8_tab.py └── tests ├── algorithm_test.c ├── cregex_test.c ├── cspan_test.c ├── ctest.h ├── deque_test.c ├── hmap_test.c ├── list_test.c ├── main.c ├── meson.build ├── mytests.c.txt ├── run.sh ├── smap_test.c └── vec_test.c /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.h linguist-language=C 4 | *.c linguist-language=C 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Folders 2 | stuff/* 3 | build*/ 4 | 5 | # Prerequisites 6 | *.d 7 | 8 | # Object files 9 | *.o 10 | *.ko 11 | *.obj 12 | *.elf 13 | 14 | # Linker output 15 | *.ilk 16 | *.map 17 | *.exp 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Libraries 24 | *.lib 25 | *.a 26 | *.la 27 | *.lo 28 | 29 | # Shared objects (inc. Windows DLLs) 30 | *.dll 31 | *.so 32 | *.so.* 33 | *.dylib 34 | 35 | # Executables 36 | *.exe 37 | *.out 38 | *.app 39 | *.i*86 40 | *.x86_64 41 | *.hex 42 | 43 | # Debug files 44 | *.dSYM/ 45 | *.su 46 | *.idb 47 | *.pdb 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Tyge Løvset 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # GNU Makefile for STC. Linux/Mac + Windows for gcc, clang and tcc (TinyC). 2 | # On Windows, makefile requires mkdir, rm, and printf, which are all 3 | # found in the C:\Program Files\Git\usr\bin folder. 4 | # Use 'make CC=gcc' (or clang or tcc), or set CC in the environment. 5 | # Currently only release build. 6 | 7 | ifeq ($(origin CC),default) 8 | CC := gcc 9 | endif 10 | ifeq ($(origin CXX),default) 11 | CXX := g++ 12 | endif 13 | 14 | CFLAGS ?= -std=c11 -Iinclude -MMD -O3 -Werror -Wpedantic -Wall -Wextra -Wconversion -Wno-missing-field-initializers 15 | CXXFLAGS ?= -std=c++20 -Iinclude -O3 -MMD -Wall 16 | LDFLAGS ?= -fopenmp 17 | ifeq ($(CC),tcc) 18 | AR_RCS ?= tcc -ar rcs 19 | else 20 | AR_RCS ?= ar rcs 21 | endif 22 | MKDIR_P ?= mkdir -p 23 | RM_F ?= rm -f 24 | 25 | ifeq ($(OS),Windows_NT) 26 | DOTEXE := .exe 27 | BUILDDIR := build/Windows_$(CC) 28 | else 29 | # CC_VER := $(shell $(CC) -dumpversion | cut -f1 -d.) 30 | BUILDDIR := build/$(shell uname)_$(CC) 31 | LDFLAGS += -lm 32 | ifneq ($(CC),clang) 33 | CFLAGS += -Wno-clobbered 34 | endif 35 | endif 36 | 37 | OBJ_DIR := $(BUILDDIR) 38 | 39 | LIB_NAME := stc 40 | LIB_LIST := cstr_core cstr_io cstr_utf8 cregex csview cspan fmt random stc_core 41 | LIB_SRCS := $(LIB_LIST:%=src/%.c) 42 | LIB_OBJS := $(LIB_SRCS:%.c=$(OBJ_DIR)/%.o) 43 | LIB_DEPS := $(LIB_SRCS:%.c=$(OBJ_DIR)/%.d) 44 | LIB_PATH := $(BUILDDIR)/lib$(LIB_NAME).a 45 | 46 | EX_SRCS := $(wildcard examples/*/*.c) 47 | EX_OBJS := $(EX_SRCS:%.c=$(OBJ_DIR)/%.o) 48 | EX_DEPS := $(EX_SRCS:%.c=$(OBJ_DIR)/%.d) 49 | EX_EXES := $(EX_SRCS:%.c=$(BUILDDIR)/%$(DOTEXE)) 50 | 51 | TEST_SRCS := $(wildcard tests/*_test.c) tests/main.c 52 | TEST_OBJS := $(TEST_SRCS:%.c=$(OBJ_DIR)/%.o) 53 | TEST_DEPS := $(TEST_SRCS:%.c=$(OBJ_DIR)/%.d) 54 | TEST_EXE := $(BUILDDIR)/tests/test_all$(DOTEXE) 55 | 56 | PROGRAMS := $(EX_EXES) $(TEST_EXE) 57 | 58 | fast: 59 | @$(MAKE) -j --no-print-directory all 60 | 61 | all: $(PROGRAMS) 62 | @echo 63 | 64 | $(PROGRAMS): $(LIB_PATH) 65 | 66 | clean: 67 | @$(RM_F) $(LIB_OBJS) $(EX_OBJS) $(TEST_OBJS) $(LIB_DEPS) $(EX_DEPS) $(TEST_DEPS) $(LIB_PATH) $(EX_EXES) $(TEST_EXE) 68 | @echo "Cleaned" 69 | 70 | distclean: 71 | @$(RM_F) -r build 72 | @echo "All Cleaned" 73 | 74 | lib: $(LIB_PATH) 75 | @echo 76 | 77 | $(LIB_PATH): $(LIB_OBJS) 78 | @printf "\r\e[2K%s" "$(AR_RCS) $@" 79 | @$(AR_RCS) $@ $(LIB_OBJS) 80 | 81 | $(OBJ_DIR)/%.o: %.c Makefile 82 | @$(MKDIR_P) $(@D) 83 | @printf "\r\e[2K%s" "$(CC) $( 43 | #include 44 | 45 | int main(int argc, char *argv[]) { 46 | coption_long longopts[] = { 47 | {"foo", coption_no_argument, 'f'}, 48 | {"bar", coption_required_argument, 'b'}, 49 | {"opt", coption_optional_argument, 'o'}, 50 | {0} 51 | }; 52 | const char* shortopts = "xy:z::123"; 53 | if (argc == 1) 54 | printf("Usage: program -x -y ARG -z [ARG] -1 -2 -3 --foo --bar ARG --opt [ARG] [ARGUMENTS]\n", argv[0]); 55 | coption opt = coption_init(); 56 | int c; 57 | while ((c = coption_get(&opt, argc, argv, shortopts, longopts)) != -1) { 58 | switch (c) { 59 | case '?': printf("error: unknown option: %s\n", opt.optstr); break; 60 | case ':': printf("error: missing argument for %s\n", opt.optstr); break; 61 | default: printf("option: %c [%s]\n", opt.opt, opt.arg ? opt.arg : ""); break; 62 | } 63 | } 64 | printf("\nNon-option arguments:"); 65 | for (int i = opt.ind; i < argc; ++i) 66 | printf(" %s", argv[i]); 67 | putchar('\n'); 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/pics/Figure_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/Figure_1.png -------------------------------------------------------------------------------- /docs/pics/array.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/array.jpg -------------------------------------------------------------------------------- /docs/pics/bitset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/bitset.jpg -------------------------------------------------------------------------------- /docs/pics/containers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/containers.jpg -------------------------------------------------------------------------------- /docs/pics/coroutine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/coroutine.png -------------------------------------------------------------------------------- /docs/pics/deque.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/deque.jpg -------------------------------------------------------------------------------- /docs/pics/list.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/list.jpg -------------------------------------------------------------------------------- /docs/pics/map.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/map.jpg -------------------------------------------------------------------------------- /docs/pics/queue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/queue.jpg -------------------------------------------------------------------------------- /docs/pics/random.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/random.jpg -------------------------------------------------------------------------------- /docs/pics/set.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/set.jpg -------------------------------------------------------------------------------- /docs/pics/smap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/smap.jpg -------------------------------------------------------------------------------- /docs/pics/sset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/sset.jpg -------------------------------------------------------------------------------- /docs/pics/stack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/stack.jpg -------------------------------------------------------------------------------- /docs/pics/string.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/string.jpg -------------------------------------------------------------------------------- /docs/pics/vector.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stclib/STC/bc64a2d3c53a28f577e16aa9880a9d5283934383/docs/pics/vector.jpg -------------------------------------------------------------------------------- /docs/utf8_api.md: -------------------------------------------------------------------------------- 1 | # STC [UTF8](../include/stc/utf8.h): string functionality 2 | ![String](pics/string.jpg) 3 | 4 | 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 5 | referred to as a ***rune***, and can be 1 to 4 bytes long. 6 | 7 | ## Header file 8 | 9 | This header file is rarely needed alone. It is included by all the string/view types mentioned above. 10 | 11 | ```c++ 12 | #include 13 | ``` 14 | ## Methods 15 | ```c++ 16 | isize utf8_count(const char *s); // number of utf8 runes in s 17 | isize utf8_count_n(const char *s, isize nbytes); // number of utf8 runes within n bytes 18 | isize utf8_to_index(const char* s, isize u8pos); // from utf8 pos to byte index 19 | int utf8_chr_size(const char* s); // utf8 character size: 1-4 20 | const char* utf8_at(const char *s, isize u8pos); // return the char* at u8pos 21 | csview utf8_subview(const char* s, isize u8pos, isize u8len); // return a csview as the span 22 | 23 | bool utf8_valid(const char* s); 24 | bool utf8_valid_n(const char* s, isize nbytes); 25 | uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, returns state. 26 | int utf8_encode(char *out, uint32_t codepoint); // encode unicode cp to out. returns nbytes. 27 | uint32_t utf8_peek(const char* s); // codepoint value at character pos s 28 | uint32_t utf8_peek_at(const char* s, isize u8offset); // codepoint at utf8 offset (may be negative) 29 | int utf8_icmp(const char* s1, const char* s2); // case-insensitive char* comparison 30 | int utf8_icompare(csview s1, csview s2); // case-insensitive csview comparison 31 | 32 | uint32_t utf8_casefold(uint32_t c); // fold to a non-unique lowercase char. 33 | uint32_t utf8_tolower(uint32_t c); 34 | uint32_t utf8_toupper(uint32_t c); 35 | 36 | bool utf8_isalpha(uint32_t c); 37 | bool utf8_isalnum(uint32_t c); 38 | bool utf8_isword(uint32_t c); 39 | bool utf8_iscased(uint32_t c); 40 | bool utf8_isblank(uint32_t c); 41 | bool utf8_isspace(uint32_t c); 42 | bool utf8_isupper(uint32_t c); 43 | bool utf8_islower(uint32_t c); 44 | bool utf8_isgroup(int group, uint32_t c); 45 | ``` 46 | 47 | ## Example: UTF8 iteration and case conversion 48 | ```c++ 49 | #include 50 | #include 51 | 52 | int main(void) 53 | { 54 | zsview say = c_zv("Liberté, égalité, fraternité."); 55 | printf("%s\n", zs.str); 56 | 57 | for (c_each(i, zsview, say)) 58 | printf(c_svfmt " ", c_svarg(i.chr)); 59 | puts(""); 60 | 61 | cstr upper = cstr_toupper_sv(zsview_sv(say)); 62 | printf("%s\n", cstr_str(&upper)); 63 | cstr_drop(&upper); 64 | } 65 | ``` 66 | Output: 67 | ``` 68 | Liberté, égalité, fraternité. 69 | L i b e r t é , é g a l i t é , f r a t e r n i t é . 70 | LIBERTÉ, ÉGALITÉ, FRATERNITÉ. 71 | ``` 72 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | Examples 2 | ======== 3 | This folder contains various examples of STC container usage. 4 | 5 | -------------------------------------------------------------------------------- /examples/algorithms/filterdemos.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define T IVec, int 8 | #include 9 | 10 | // filters and transforms: 11 | #define f_skipValue(x) (*value != (x)) 12 | #define f_isEven() ((*value & 1) == 0) 13 | #define f_square() (*value * *value) 14 | 15 | void demo1(void) 16 | { 17 | IVec vec = c_make(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80, 18 | 10, 11, 12, 13, 14, 15, 80, 16, 17}); 19 | 20 | c_filter(IVec, vec, f_skipValue(80) && printf(" %d", (int) *value)); 21 | puts(""); 22 | 23 | int sum = 0; 24 | c_filter(IVec, vec, true 25 | && c_flt_skipwhile(*value != 80) 26 | && c_flt_skip(1) 27 | && f_isEven() 28 | && f_skipValue(80) 29 | && (sum += f_square(), c_flt_take(5)) 30 | ); 31 | printf("\n sum: %d\n", sum); 32 | IVec_drop(&vec); 33 | } 34 | 35 | 36 | /* Rust: 37 | fn main() { 38 | let vector = (1..) // Infinite range of integers 39 | .skip_while(|x| *x != 11) // Skip initial numbers unequal 11 40 | .filter(|x| x % 2 != 0) // Collect odd numbers 41 | .take(5) // Only take five numbers 42 | .map(|x| x * x) // Square each number 43 | .collect::>(); // Return as a new Vec 44 | println!("{:?}", vector); // Print result 45 | } 46 | */ 47 | void demo2(void) 48 | { 49 | IVec vector = {0}; 50 | c_filter(crange, c_iota(0), true // Infinite range of integers 51 | && c_flt_skipwhile(*value != 11) // Skip initial numbers unequal 11 52 | && (*value % 2) != 0 // Collect odd numbers 53 | && (c_flt_map(*value * *value), // Square each number 54 | IVec_push(&vector, (int)*value), // Populate output IVec 55 | c_flt_take(5)) // Only take five numbers 56 | ); 57 | for (c_each(i, IVec, vector)) 58 | printf(" %d", *i.ref); // Print result 59 | puts(""); 60 | IVec_drop(&vector); 61 | } 62 | 63 | /* Rust: 64 | fn main() { 65 | let sentence = "This is a sentence in Rust."; 66 | let words: Vec<&str> = sentence 67 | .split_whitespace() 68 | .collect(); 69 | let words_containing_i: Vec<&str> = words 70 | .into_iter() 71 | .filter(|word| word.contains("i")) 72 | .collect(); 73 | println!("{:?}", words_containing_i); 74 | } 75 | */ 76 | // Bind and enable csview comparison functions for vec. 77 | #define T SVec, csview, (c_cmpclass | c_use_cmp) 78 | #include 79 | 80 | void demo3(void) 81 | { 82 | const char* sentence = "This is a sentence in C99."; 83 | SVec words = {0}; 84 | for (c_token(i, " ", sentence)) // split words 85 | SVec_push(&words, i.token); 86 | 87 | SVec words_containing_i = {0}; 88 | c_filter(SVec, words, true 89 | && csview_contains(*value, "i") 90 | && SVec_push(&words_containing_i, *value) 91 | ); 92 | for (c_each(w, SVec, words_containing_i)) 93 | printf(" " c_svfmt, c_svarg(*w.ref)); 94 | puts(""); 95 | 96 | 97 | SVec_iter it = SVec_find(&words, c_sv("sentence")); 98 | if (it.ref) printf("found: " c_svfmt "\n", c_svarg(*it.ref)); 99 | 100 | c_drop(SVec, &words, &words_containing_i); 101 | } 102 | 103 | void demo4(void) 104 | { 105 | // Keep only uppercase letters and convert them to lowercase: 106 | csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte 107 | cstr out = {0}; 108 | char chr[4]; 109 | 110 | c_filter(csview, s, true 111 | && utf8_isupper(utf8_peek(value)) 112 | && (utf8_encode(chr, utf8_tolower(utf8_peek(value))), 113 | cstr_push(&out, chr)) 114 | ); 115 | printf(" %s\n", cstr_str(&out)); 116 | cstr_drop(&out); 117 | } 118 | 119 | 120 | int main(void) 121 | { 122 | puts("demo1"); demo1(); 123 | puts("demo2"); demo2(); 124 | puts("demo3"); demo3(); 125 | puts("demo4"); demo4(); 126 | } 127 | -------------------------------------------------------------------------------- /examples/algorithms/forloops.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define T IVec, int 5 | #include 6 | 7 | #define T IMap, int, int 8 | #include 9 | 10 | 11 | int main(void) 12 | { 13 | puts("for c_range:"); 14 | for (c_range(30)) printf(" xx"); 15 | puts(""); 16 | 17 | for (c_range(i, 30)) printf(" %d", (int)i); 18 | puts(""); 19 | 20 | for (c_range(i, 30, 60)) printf(" %d", (int)i); 21 | puts(""); 22 | 23 | for (c_range(i, 30, 90, 2)) printf(" %d", (int)i); 24 | 25 | puts("\n\nc_forlist:"); 26 | for (c_items(i, int, {12, 23, 453, 65, 676})) 27 | printf(" %d", *i.ref); 28 | puts(""); 29 | 30 | for (c_items(i, const char*, {"12", "23", "453", "65", "676"})) 31 | printf(" %s", *i.ref); 32 | puts(""); 33 | 34 | IVec vec = c_make(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199}); 35 | IMap map = c_make(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}}); 36 | 37 | puts("\n\nc_foreach:"); 38 | for (c_each(i, IVec, vec)) 39 | printf(" %d", *i.ref); 40 | 41 | puts("\n\nc_foreach in map:"); 42 | for (c_each(i, IMap, map)) 43 | printf(" (%d %d)", i.ref->first, i.ref->second); 44 | 45 | puts("\n\nc_forpair:"); 46 | for (c_each_kv(key, val, IMap, map)) 47 | printf(" (%d %d)", *key, *val); 48 | 49 | #define f_isOdd() (*value & 1) 50 | 51 | puts("\n\nc_filter:"); 52 | c_filter(IVec, vec, true 53 | && f_isOdd() 54 | && c_flt_skip(4) 55 | && (printf(" %d", *value), c_flt_take(4)) 56 | ); 57 | 58 | IVec_drop(&vec); 59 | IMap_drop(&map); 60 | } 61 | -------------------------------------------------------------------------------- /examples/algorithms/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'filterdemos', 3 | 'forloops', 4 | 'random', 5 | 'shape', 6 | ] 7 | test( 8 | sample, 9 | executable( 10 | sample, 11 | files(f'@sample@.c'), 12 | dependencies: example_deps, 13 | install: false, 14 | ), 15 | suite: 'algorithm', 16 | ) 17 | endforeach 18 | -------------------------------------------------------------------------------- /examples/algorithms/random.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) 6 | { 7 | const long long N = 10000000, range = 1000000; 8 | const uint64_t seed = (uint64_t)time(NULL); 9 | crand64 rng = crand64_from(seed); 10 | clock_t t; 11 | 12 | printf("Compare speed of full and unbiased ranged random numbers...\n"); 13 | long long sum = 0; 14 | t = clock(); 15 | for (c_range(N)) { 16 | sum += (int32_t)crand64_uint_r(&rng, 1); 17 | } 18 | t = clock() - t; 19 | printf("full range\t\t: %f secs, %d, avg: %f\n", 20 | (double)t/CLOCKS_PER_SEC, (int)N, (double)(sum/N)); 21 | 22 | sum = 0; 23 | rng = crand64_from(seed); 24 | t = clock(); 25 | for (c_range(N)) { 26 | sum += (int32_t)crand64_uint_r(&rng, 1) % (range + 1); // biased 27 | } 28 | t = clock() - t; 29 | printf("biased 0-%d \t: %f secs, %d, avg: %f\n", 30 | (int)range, (double)t/CLOCKS_PER_SEC, (int)N, (double)(sum/N)); 31 | } 32 | -------------------------------------------------------------------------------- /examples/algorithms/shape.c: -------------------------------------------------------------------------------- 1 | // Demo of typesafe polymorphism in C99, using STC. 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define DYN_CAST(T, s) \ 8 | (&T##_api == (s)->api ? (T*)(s) : (T*)0) 9 | 10 | // Shape definition 11 | // ============================================================ 12 | 13 | typedef struct { 14 | float x, y; 15 | } Point; 16 | 17 | typedef struct Shape Shape; 18 | 19 | struct ShapeAPI { 20 | void (*drop)(Shape*); 21 | void (*draw)(const Shape*); 22 | }; 23 | 24 | struct Shape { 25 | struct ShapeAPI* api; 26 | uint32_t color; 27 | uint16_t style; 28 | uint8_t thickness; 29 | uint8_t hardness; 30 | }; 31 | 32 | void Shape_drop(Shape* shape) 33 | { 34 | (void)shape; 35 | printf("shape destructed\n"); 36 | } 37 | 38 | void Shape_delete(Shape* shape) 39 | { 40 | if (shape) { 41 | shape->api->drop(shape); 42 | free(shape); 43 | } 44 | } 45 | 46 | // Triangle implementation 47 | // ============================================================ 48 | 49 | typedef struct { 50 | Shape shape; 51 | Point p[3]; 52 | } Triangle; 53 | 54 | extern struct ShapeAPI Triangle_api; 55 | 56 | 57 | Triangle Triangle_from(Point a, Point b, Point c) { 58 | Triangle t = {{&Triangle_api}, {a, b, c}}; 59 | return t; 60 | } 61 | 62 | static void Triangle_draw(const Shape* shape) 63 | { 64 | const Triangle* self = DYN_CAST(Triangle, shape); 65 | printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n", 66 | (double)self->p[0].x, (double)self->p[0].y, 67 | (double)self->p[1].x, (double)self->p[1].y, 68 | (double)self->p[2].x, (double)self->p[2].y); 69 | } 70 | 71 | struct ShapeAPI Triangle_api = { 72 | .drop = Shape_drop, 73 | .draw = Triangle_draw, 74 | }; 75 | 76 | // Polygon implementation 77 | // ============================================================ 78 | 79 | #define T PointVec, Point 80 | #include 81 | 82 | typedef struct { 83 | Shape shape; 84 | PointVec points; 85 | } Polygon; 86 | 87 | extern struct ShapeAPI Polygon_api; 88 | 89 | 90 | Polygon Polygon_init(void) { 91 | Polygon p = {{&Polygon_api}, {0}}; 92 | return p; 93 | } 94 | 95 | void Polygon_addPoint(Polygon* self, Point p) 96 | { 97 | PointVec_push(&self->points, p); 98 | } 99 | 100 | static void Polygon_drop(Shape* shape) 101 | { 102 | Polygon* self = DYN_CAST(Polygon, shape); 103 | printf("poly destructed\n"); 104 | PointVec_drop(&self->points); 105 | } 106 | 107 | static void Polygon_draw(const Shape* shape) 108 | { 109 | const Polygon* self = DYN_CAST(Polygon, shape); 110 | printf("Polygon :"); 111 | for (c_each(i, PointVec, self->points)) 112 | printf(" (%g,%g)", (double)i.ref->x, (double)i.ref->y); 113 | puts(""); 114 | } 115 | 116 | struct ShapeAPI Polygon_api = { 117 | .drop = Polygon_drop, 118 | .draw = Polygon_draw, 119 | }; 120 | 121 | // Test 122 | // ============================================================ 123 | 124 | #define T Shapes, Shape* 125 | #define i_keydrop(x) Shape_delete(*x) 126 | #define i_no_clone 127 | #include 128 | 129 | void testShape(const Shape* shape) 130 | { 131 | shape->api->draw(shape); 132 | } 133 | 134 | 135 | int main(void) 136 | { 137 | Shapes shapes = {0}; 138 | 139 | Triangle* tri1 = c_new(Triangle, Triangle_from(c_literal(Point){5, 7}, c_literal(Point){12, 7}, c_literal(Point){12, 20})); 140 | Polygon* pol1 = c_new(Polygon, Polygon_init()); 141 | Polygon* pol2 = c_new(Polygon, Polygon_init()); 142 | 143 | for (c_items(i, Point, {{50, 72}, {123, 73}, {127, 201}, {828, 333}})) 144 | Polygon_addPoint(pol1, *i.ref); 145 | 146 | for (c_items(i, Point, {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}})) 147 | Polygon_addPoint(pol2, *i.ref); 148 | 149 | Shapes_push(&shapes, &tri1->shape); 150 | Shapes_push(&shapes, &pol1->shape); 151 | Shapes_push(&shapes, &pol2->shape); 152 | 153 | for (c_each(i, Shapes, shapes)) 154 | testShape(*i.ref); 155 | 156 | Shapes_drop(&shapes); 157 | } 158 | -------------------------------------------------------------------------------- /examples/algorithms/shape.cpp: -------------------------------------------------------------------------------- 1 | // Demo of polymorphism in C++ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // Shape definition 8 | // ============================================================ 9 | 10 | struct Point { 11 | float x, y; 12 | }; 13 | 14 | std::ostream& operator<<(std::ostream& os, const Point& p) { 15 | os << " (" << p.x << "," << p.y << ")"; 16 | return os; 17 | } 18 | 19 | struct Shape { 20 | virtual ~Shape(); 21 | virtual void draw() const = 0; 22 | 23 | uint32_t color; 24 | uint16_t style; 25 | uint8_t thickness; 26 | uint8_t hardness; 27 | }; 28 | 29 | Shape::~Shape() 30 | { 31 | std::cout << "base destructed" << std::endl; 32 | } 33 | 34 | // Triangle implementation 35 | // ============================================================ 36 | 37 | struct Triangle : public Shape 38 | { 39 | Triangle(Point a, Point b, Point c); 40 | void draw() const override; 41 | 42 | private: Point p[3]; 43 | }; 44 | 45 | 46 | Triangle::Triangle(Point a, Point b, Point c) 47 | : p{a, b, c} {} 48 | 49 | void Triangle::draw() const 50 | { 51 | std::cout << "Triangle :" 52 | << p[0] << p[1] << p[2] 53 | << std::endl; 54 | } 55 | 56 | 57 | // Polygon implementation 58 | // ============================================================ 59 | 60 | 61 | struct Polygon : public Shape 62 | { 63 | ~Polygon(); 64 | void draw() const override; 65 | void addPoint(const Point& p); 66 | 67 | private: std::vector points; 68 | }; 69 | 70 | 71 | void Polygon::addPoint(const Point& p) 72 | { 73 | points.push_back(p); 74 | } 75 | 76 | Polygon::~Polygon() 77 | { 78 | std::cout << "poly destructed" << std::endl; 79 | } 80 | 81 | void Polygon::draw() const 82 | { 83 | std::cout << "Polygon :"; 84 | for (auto& p : points) 85 | std::cout << p ; 86 | std::cout << std::endl; 87 | } 88 | 89 | 90 | // Test 91 | // ============================================================ 92 | 93 | void testShape(const Shape* shape) 94 | { 95 | shape->draw(); 96 | } 97 | 98 | #include 99 | 100 | int main(void) 101 | { 102 | std::vector> shapes; 103 | 104 | auto tri1 = std::make_unique(Point{5, 7}, Point{12, 7}, Point{12, 20}); 105 | auto pol1 = std::make_unique(); 106 | auto pol2 = std::make_unique(); 107 | 108 | for (auto& p: std::array 109 | {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}}) 110 | pol1->addPoint(p); 111 | 112 | for (auto& p: std::array 113 | {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}}) 114 | pol2->addPoint(p); 115 | 116 | shapes.push_back(std::move(tri1)); 117 | shapes.push_back(std::move(pol1)); 118 | shapes.push_back(std::move(pol2)); 119 | 120 | for (auto& shape: shapes) 121 | testShape(shape.get()); 122 | } 123 | -------------------------------------------------------------------------------- /examples/bitsets/bits.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | cbits set = cbits_with_size(23, true); 7 | cbits s2; 8 | c_defer( 9 | cbits_drop(&set), 10 | cbits_drop(&s2) 11 | ){ 12 | printf("count %d, %d\n", (int)cbits_count(&set), (int)cbits_size(&set)); 13 | cbits s1 = cbits_from("1110100110111"); 14 | char buf[256]; 15 | cbits_to_str(&s1, buf, 0, 255); 16 | printf("buf: %s: %d\n", buf, (int)cbits_count(&s1)); 17 | cbits_drop(&s1); 18 | 19 | cbits_reset(&set, 9); 20 | cbits_resize(&set, 43, false); 21 | printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255)); 22 | 23 | printf("%4d: ", (int)cbits_size(&set)); 24 | for (c_range(i, cbits_size(&set))) 25 | printf("%d", cbits_test(&set, i)); 26 | puts(""); 27 | 28 | cbits_set(&set, 28); 29 | cbits_resize(&set, 77, true); 30 | cbits_resize(&set, 93, false); 31 | cbits_resize(&set, 102, true); 32 | cbits_set_value(&set, 99, false); 33 | printf("%4d: ", (int)cbits_size(&set)); 34 | for (c_range(i, cbits_size(&set))) 35 | printf("%d", cbits_test(&set, i)); 36 | 37 | puts("\nIterate:"); 38 | printf("%4d: ", (int)cbits_size(&set)); 39 | for (c_range(i, cbits_size(&set))) 40 | printf("%d", cbits_test(&set, i)); 41 | puts(""); 42 | 43 | // Make a clone 44 | s2 = cbits_clone(set); 45 | cbits_flip_all(&s2); 46 | cbits_set(&s2, 16); 47 | cbits_set(&s2, 17); 48 | cbits_set(&s2, 18); 49 | printf(" new: "); 50 | for (c_range(i, cbits_size(&s2))) 51 | printf("%d", cbits_test(&s2, i)); 52 | puts(""); 53 | 54 | printf(" xor: "); 55 | cbits_xor(&set, &s2); 56 | for (c_range(i, cbits_size(&set))) 57 | printf("%d", cbits_test(&set, i)); 58 | puts(""); 59 | 60 | cbits_set_all(&set, false); 61 | printf("%4d: ", (int)cbits_size(&set)); 62 | for (c_range(i, cbits_size(&set))) 63 | printf("%d", cbits_test(&set, i)); 64 | puts(""); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /examples/bitsets/bits2.c: -------------------------------------------------------------------------------- 1 | #include 2 | // Example of static sized (stack allocated) bitsets 3 | 4 | #define T Bits, 80 // enable fixed size bitset on the stack 5 | #include 6 | 7 | int main(void) 8 | { 9 | Bits s1 = Bits_from("1110100110111"); 10 | 11 | printf("size %d\n", (int)Bits_size(&s1)); 12 | char buf[256]; 13 | Bits_to_str(&s1, buf, 0, 256); 14 | printf("buf: %s: count=%d\n", buf, (int)Bits_count(&s1)); 15 | 16 | Bits_reset(&s1, 8); 17 | printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256)); 18 | 19 | Bits s2 = Bits_clone(s1); 20 | 21 | Bits_flip_all(&s2); 22 | Bits_reset(&s2, 66); 23 | Bits_reset(&s2, 67); 24 | printf(" s2: "); 25 | for (c_range(i, Bits_size(&s2))) 26 | printf("%d", Bits_test(&s2, i)); 27 | puts(""); 28 | 29 | printf("xor: "); 30 | Bits_xor(&s1, &s2); 31 | for (c_range(i, Bits_size(&s1))) 32 | printf("%d", Bits_test(&s1, i)); 33 | puts(""); 34 | 35 | printf("all: "); 36 | Bits_set_pattern(&s1, 0x3333333333333333); 37 | for (c_range(i, Bits_size(&s1))) 38 | printf("%d", Bits_test(&s1, i)); 39 | puts(""); 40 | } 41 | -------------------------------------------------------------------------------- /examples/bitsets/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'bits2', 3 | 'bits', 4 | 'prime', 5 | ] 6 | test( 7 | sample, 8 | executable( 9 | sample, 10 | files(f'@sample@.c'), 11 | dependencies: example_deps, 12 | install: false, 13 | ), 14 | suite: 'cbits', 15 | ) 16 | endforeach 17 | -------------------------------------------------------------------------------- /examples/bitsets/prime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | cbits sieveOfEratosthenes(isize n) 8 | { 9 | cbits bits = cbits_with_size(n/2 + 1, true); 10 | isize q = (isize)sqrt((double) n) + 1; 11 | for (isize i = 3; i < q; i += 2) { 12 | for (isize j = i; j < n; j += 2) { 13 | if (cbits_test(&bits, j/2)) { 14 | i = j; 15 | break; 16 | } 17 | } 18 | for (isize j = i*i; j < n; j += i*2) 19 | cbits_reset(&bits, j/2); 20 | } 21 | return bits; 22 | } 23 | 24 | int main(void) 25 | { 26 | int n = 100000000; 27 | printf("Computing prime numbers up to %d\n", n); 28 | 29 | clock_t t = clock(); 30 | cbits primes = sieveOfEratosthenes(n + 1); 31 | 32 | int np = (int)cbits_count(&primes); 33 | t = clock() - t; 34 | 35 | printf("Number of primes: %d, time: %f\n\n", np, (double)t/CLOCKS_PER_SEC); 36 | 37 | puts("Show all the primes in the range [2, 1000):"); 38 | printf("2"); 39 | for (c_range(i, 3, 1000, 2)) 40 | if (cbits_test(&primes, i/2)) printf(" %d", (int)i); 41 | puts("\n"); 42 | 43 | puts("Show the last 50 primes using a temporary crange generator, 10 per line:"); 44 | 45 | c_filter(crange, c_iota(n - 1, 1, -2), true 46 | && cbits_test(&primes, *value/2) 47 | && printf("%d ", (int) *value) 48 | && c_flt_take(50) 49 | && c_flt_getcount() % 10 == 0 50 | && printf("\n") 51 | ); 52 | cbits_drop(&primes); 53 | } 54 | -------------------------------------------------------------------------------- /examples/coroutines/cointerleave.c: -------------------------------------------------------------------------------- 1 | // https://www.youtube.com/watch?v=8sEe-4tig_A 2 | #include 3 | #include 4 | #define T IVec, int 5 | #include 6 | 7 | struct GenValue { 8 | IVec *v; 9 | IVec_iter it; 10 | cco_state cco; 11 | }; 12 | 13 | static long get_value(struct GenValue* g) 14 | { 15 | cco_routine (g) { 16 | for (cco_each(g->it, IVec, *g->v)) 17 | cco_yield_v(*g->it.ref); 18 | } 19 | return 1L<<31; 20 | } 21 | 22 | struct Generator { 23 | struct GenValue x, y; 24 | bool xact, yact; 25 | long value; 26 | cco_state cco; 27 | }; 28 | 29 | int interleaved(struct Generator* g) 30 | { 31 | cco_routine (g) { 32 | do { 33 | g->value = get_value(&g->x); 34 | g->xact = cco_active(&g->x); 35 | if (g->xact) 36 | cco_yield; 37 | 38 | g->value = get_value(&g->y); 39 | g->yact = cco_active(&g->y); 40 | if (g->yact) 41 | cco_yield; 42 | } while (g->xact | g->yact); 43 | } 44 | return 0; 45 | } 46 | 47 | void Use(void) 48 | { 49 | IVec a = c_make(IVec, {2, 4, 6, 8, 10, 11}); 50 | IVec b = c_make(IVec, {3, 5, 7, 9}); 51 | 52 | struct Generator g = {{&a}, {&b}}; 53 | 54 | cco_run_coroutine(interleaved(&g)) { 55 | printf("%ld ", g.value); 56 | } 57 | puts(""); 58 | c_drop(IVec, &a, &b); 59 | } 60 | 61 | int main(void) 62 | { 63 | Use(); 64 | } 65 | -------------------------------------------------------------------------------- /examples/coroutines/coread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Read file line by line using coroutines: 7 | 8 | struct file_read { 9 | const char* filename; 10 | FILE* fp; 11 | cstr line; 12 | cco_state cco; 13 | }; 14 | 15 | int file_read(struct file_read* g) 16 | { 17 | cco_routine (g) { 18 | g->fp = fopen(g->filename, "r"); 19 | if (g->fp == NULL) cco_return; 20 | g->line = (cstr){0}; 21 | 22 | cco_await( !cstr_getline(&g->line, g->fp) ); 23 | 24 | cco_finally: 25 | printf("finish\n"); 26 | cstr_drop(&g->line); 27 | if (g->fp) fclose(g->fp); 28 | } 29 | return 0; 30 | } 31 | 32 | int main(void) 33 | { 34 | struct file_read g = {.filename=__FILE__}; 35 | int n = 0; 36 | cco_run_coroutine(file_read(&g)) 37 | { 38 | printf("%3d %s\n", ++n, cstr_str(&g.line)); 39 | //if (n == 10) cco_stop(&g); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/coroutines/coroutine_tasks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Demonstrate calling two coroutine from a coroutine: 6 | // First call them concurrently, then in parallel: 7 | 8 | 9 | // Suspend yield values 10 | enum { YIELD_PRM = 1<<0, YIELD_FIB = 1<<1}; 11 | 12 | bool is_prime(long long i) { 13 | for (long long j=2; j*j <= i; ++j) 14 | if (i % j == 0) return false; 15 | return true; 16 | } 17 | 18 | cco_task_struct (prime) { 19 | prime_state cco; 20 | int count; 21 | long long value; 22 | }; 23 | 24 | int prime(struct prime* g, cco_fiber* fb) { 25 | (void)fb; 26 | cco_routine (g) { 27 | if (g->value <= 2) { 28 | g->value = 2; 29 | if (g->count-- == 0) 30 | cco_return; 31 | cco_yield_v(YIELD_PRM); 32 | } 33 | for (g->value |= 1; g->count > 0; g->value += 2) { 34 | if (is_prime(g->value)) { 35 | --g->count; 36 | cco_yield_v(YIELD_PRM); 37 | } 38 | } 39 | cco_finally: 40 | puts("DONE prm"); 41 | } 42 | return 0; 43 | } 44 | 45 | 46 | // Use coroutine to create a fibonacci sequence generator: 47 | 48 | cco_task_struct (fibonacci) { 49 | fibonacci_state cco; 50 | int count; 51 | long long value, b; 52 | }; 53 | 54 | int fibonacci(struct fibonacci* g, cco_fiber* fb) { 55 | (void)fb; 56 | assert(g->count < 94); 57 | cco_routine (g) { 58 | if (g->value == 0) 59 | g->b = 1; 60 | while (true) { 61 | if (g->count-- == 0) 62 | cco_return; 63 | // NB! locals lasts only until next yield/await! 64 | long long tmp = g->value; 65 | g->value = g->b; 66 | g->b += tmp; 67 | cco_yield_v(YIELD_FIB); 68 | } 69 | cco_finally: 70 | puts("DONE fib"); 71 | } 72 | return 0; 73 | } 74 | 75 | int main(void) { 76 | struct prime prm; 77 | struct fibonacci fib; 78 | 79 | puts("SERIAL:"); 80 | prm = (struct prime){{prime}, .count=8}; 81 | fib = (struct fibonacci){{fibonacci}, .count=12}; 82 | 83 | cco_run_task(&prm) { 84 | printf(" Prime=%lld\n", prm.value); 85 | } 86 | cco_run_task(&fib) { 87 | printf(" Fibon=%lld\n", fib.value); 88 | } 89 | puts(""); 90 | 91 | 92 | puts("CONCURRENT:"); 93 | prm = (struct prime){{prime}, .count=8}; 94 | fib = (struct fibonacci){{fibonacci}, .count=12}; 95 | 96 | cco_fiber* fb = c_new(cco_fiber, 0); 97 | cco_spawn(&prm, fb); 98 | cco_spawn(&fib, fb); 99 | 100 | cco_run_fiber(run, fb) { 101 | switch (run->result) { 102 | case YIELD_PRM: 103 | printf(" Prime=%lld\n", prm.value); 104 | break; 105 | case YIELD_FIB: 106 | printf(" Fibon=%lld\n", fib.value); 107 | break; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /examples/coroutines/coroutines.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Demonstrate calling two coroutine from a coroutine: 6 | // First call them concurrently, then in parallel: 7 | 8 | 9 | // Suspend yield values 10 | enum { YIELD_PRM = 1<<0, YIELD_FIB = 1<<1}; 11 | 12 | bool is_prime(long long i) { 13 | for (long long j=2; j*j <= i; ++j) 14 | if (i % j == 0) return false; 15 | return true; 16 | } 17 | 18 | struct prime { 19 | int count; 20 | long long result; 21 | cco_state cco; 22 | }; 23 | 24 | int prime(struct prime* g) { 25 | cco_routine (g) { 26 | if (g->result <= 2) { 27 | g->result = 2; 28 | if (g->count-- == 0) 29 | cco_return; 30 | cco_yield_v(YIELD_PRM); 31 | } 32 | for (g->result |= 1; g->count > 0; g->result += 2) { 33 | if (is_prime(g->result)) { 34 | --g->count; 35 | cco_yield_v(YIELD_PRM); 36 | } 37 | } 38 | cco_finally: 39 | puts("DONE prm"); 40 | } 41 | return 0; 42 | } 43 | 44 | 45 | // Use coroutine to create a fibonacci sequence generator: 46 | 47 | struct fibonacci { 48 | int count; 49 | long long result, b; 50 | cco_state cco; 51 | }; 52 | 53 | int fibonacci(struct fibonacci* g) { 54 | assert(g->count < 94); 55 | cco_routine (g) { 56 | if (g->result == 0) 57 | g->b = 1; 58 | while (true) { 59 | if (g->count-- == 0) 60 | cco_return; 61 | // NB! locals lasts only until next yield/await! 62 | long long tmp = g->result; 63 | g->result = g->b; 64 | g->b += tmp; 65 | cco_yield_v(YIELD_FIB); 66 | } 67 | cco_finally: 68 | puts("DONE fib"); 69 | } 70 | return 0; 71 | } 72 | 73 | // Combine 74 | 75 | struct combined { 76 | struct prime prm; 77 | struct fibonacci fib; 78 | cco_state cco; 79 | }; 80 | 81 | int combined(struct combined* g) { 82 | cco_routine (g) { 83 | puts("SEQUENCED:"); 84 | g->prm = (struct prime){.count = 8}, g->fib = (struct fibonacci){.count = 12}; 85 | cco_await_coroutine( prime(&g->prm) ); 86 | cco_await_coroutine( fibonacci(&g->fib) ); 87 | 88 | puts("\nPARALLEL, AWAIT ALL:"); 89 | g->prm = (struct prime){.count = 8}, g->fib = (struct fibonacci){.count = 12}; 90 | cco_await_coroutine( prime(&g->prm) | 91 | fibonacci(&g->fib) ); 92 | cco_finally: 93 | puts("DONE prime and fib"); 94 | } 95 | return 0; 96 | } 97 | 98 | 99 | int main(void) { 100 | struct combined c = {0}; 101 | int res; 102 | 103 | cco_run_coroutine(res = combined(&c)) { 104 | if (res & YIELD_PRM) 105 | printf("Prime=%lld\n", c.prm.result); 106 | if (res & YIELD_FIB) 107 | printf("Fibon=%lld\n", c.fib.result); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /examples/coroutines/dining_philosophers.c: -------------------------------------------------------------------------------- 1 | // https://en.wikipedia.org/wiki/Dining_philosophers_problem 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum {num_philosophers = 5}; 8 | enum PhState {ph_thinking, ph_hungry, ph_eating}; 9 | 10 | // Philosopher coroutine 11 | struct Philosopher { 12 | int id; 13 | cco_timer tm; 14 | enum PhState state; 15 | int hunger; 16 | struct Philosopher* left; 17 | struct Philosopher* right; 18 | cco_state cco; // required 19 | }; 20 | 21 | int Philosopher(struct Philosopher* self) { 22 | double duration; 23 | cco_routine (self) { 24 | while (1) { 25 | duration = 1.0 + crand64_real()*2.0; 26 | printf("Philosopher %d is thinking for %.0f minutes...\n", self->id, duration*10); 27 | self->hunger = 0; 28 | self->state = ph_thinking; 29 | cco_await_timer_sec(&self->tm, duration); 30 | 31 | printf("Philosopher %d is hungry...\n", self->id); 32 | self->state = ph_hungry; 33 | cco_await(self->hunger >= self->left->hunger && 34 | self->hunger >= self->right->hunger); 35 | 36 | duration = 0.5 + crand64_real(); 37 | printf("Philosopher %d is eating for %.0f minutes...\n", self->id, duration*10); 38 | self->hunger = 3; 39 | self->state = ph_eating; 40 | cco_await_timer_sec(&self->tm, duration); 41 | 42 | // increase the neighbours hunger only if they are already hungry. 43 | if (self->left->state == ph_hungry) ++self->left->hunger; 44 | if (self->right->state == ph_hungry) ++self->right->hunger; 45 | } 46 | 47 | cco_finally: 48 | printf("Philosopher %d done\n", self->id); 49 | } 50 | return 0; 51 | } 52 | 53 | // Dining coroutine 54 | struct Dining { 55 | struct Philosopher philos[num_philosophers]; 56 | cco_state cco; // required 57 | }; 58 | 59 | int Dining(struct Dining* self) { 60 | cco_routine (self) { 61 | for (int i = 0; i < num_philosophers; ++i) { 62 | cco_reset(&self->philos[i]); 63 | self->philos[i].id = i + 1; 64 | self->philos[i].left = &self->philos[(i - 1 + num_philosophers) % num_philosophers]; 65 | self->philos[i].right = &self->philos[(i + 1) % num_philosophers]; 66 | } 67 | 68 | while (1) { 69 | // NB! local i OK here as it does not cross yield/await. 70 | for (int i = 0; i < num_philosophers; ++i) { 71 | Philosopher(&self->philos[i]); // resume until next yield 72 | } 73 | cco_yield; // suspend, return control back to caller who 74 | // can do other tasks before resuming dining. 75 | } 76 | 77 | cco_finally: 78 | for (int i = 0; i < num_philosophers; ++i) { 79 | cco_stop(&self->philos[i]); 80 | Philosopher(&self->philos[i]); // execute philos. cco_finally. 81 | } 82 | puts("Dining done"); 83 | } 84 | return 0; 85 | } 86 | 87 | int main(void) 88 | { 89 | struct Dining dining = {0}; 90 | cco_timer tm = cco_make_timer_sec(5.0); 91 | crand64_seed((uint64_t)time(NULL)); 92 | 93 | cco_run_coroutine(Dining(&dining)) { 94 | if (cco_timer_expired(&tm)) 95 | cco_stop(&dining); 96 | cco_sleep_sec(0.001); // do other things 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /examples/coroutines/fibonacci.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Use coroutine to create a fibonacci sequence generator: 5 | 6 | struct fibonacci { 7 | unsigned long long value, b; 8 | cco_state cco; 9 | }; 10 | 11 | int fibonacci(struct fibonacci* g) { 12 | unsigned long long tmp; 13 | cco_routine (g) { 14 | g->value = 0; 15 | g->b = 1; 16 | cco_yield; 17 | 18 | while (true) { 19 | tmp = g->value; 20 | g->value = g->b; 21 | g->b += tmp; 22 | cco_yield; 23 | } 24 | 25 | cco_finally: 26 | puts("done"); 27 | } 28 | return 0; 29 | } 30 | 31 | 32 | int main(void) { 33 | struct fibonacci fib = {0}; 34 | int n = 0; 35 | 36 | cco_run_coroutine( fibonacci(&fib) ) { 37 | printf("Fib(%d) = %llu\n", n++, fib.value); 38 | 39 | if (fib.value > fib.b) 40 | cco_stop(&fib); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/coroutines/filetask.c: -------------------------------------------------------------------------------- 1 | // https://github.com/lewissbaker/cppcoro#taskt 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | cco_task_struct (file_read) { 9 | file_read_state cco; 10 | const char* path; 11 | cstr line; 12 | FILE* fp; 13 | cco_timer tm; 14 | }; 15 | 16 | 17 | int file_read(struct file_read* co, cco_fiber* fb) 18 | { 19 | cco_routine (co) { 20 | (void)fb; 21 | co->fp = fopen(co->path, "r"); 22 | co->line = cstr_init(); 23 | 24 | while (true) { 25 | // emulate async io: await 10ms per line 26 | cco_await_timer_sec(&co->tm, 0.010); 27 | 28 | if (!cstr_getline(&co->line, co->fp)) 29 | break; 30 | cco_yield; 31 | } 32 | 33 | cco_finally: 34 | fclose(co->fp); 35 | cstr_drop(&co->line); 36 | puts("done file_read"); 37 | } 38 | return 0; 39 | } 40 | 41 | 42 | cco_task_struct (count_line) { 43 | count_line_state cco; 44 | cstr path; 45 | struct file_read reader; 46 | int lineCount; 47 | }; 48 | 49 | 50 | int count_line(struct count_line* co, cco_fiber* fb) 51 | { 52 | cco_routine (co) { 53 | co->reader.cco.func = file_read; 54 | co->reader.path = cstr_str(&co->path); 55 | 56 | while (true) { 57 | // await for next CCO_YIELD (or CCO_DONE) in file_read() 58 | cco_await_task(&co->reader, fb, CCO_YIELD); 59 | if (fb->result == CCO_DONE) break; 60 | co->lineCount += 1; 61 | cco_yield; 62 | } 63 | 64 | cco_finally: 65 | cstr_drop(&co->path); 66 | puts("done count_line"); 67 | } 68 | return 0; 69 | } 70 | 71 | 72 | int main(void) 73 | { 74 | // Creates a new task 75 | struct count_line countTask = { 76 | .cco = {count_line}, 77 | .path = cstr_from(__FILE__), 78 | }; 79 | 80 | // Execute coroutine as top-level blocking 81 | int loop = 0; 82 | 83 | cco_run_task(&countTask) { ++loop; } 84 | 85 | printf("line count = %d\n", countTask.lineCount); 86 | printf("exec count = %d\n", loop); 87 | } 88 | -------------------------------------------------------------------------------- /examples/coroutines/generator.c: -------------------------------------------------------------------------------- 1 | // https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // Create an iterable generator Triple with max_triples items. 8 | // Requires coroutine Triple_next() and function Triple_begin() to be defined. 9 | 10 | typedef struct { 11 | int a, b, c; 12 | } Triple, Triple_value; 13 | 14 | typedef struct { 15 | Triple* ref; // required by iterator 16 | cco_state cco; // required by coroutine 17 | } Triple_iter; 18 | 19 | int Triple_next(Triple_iter* it) { 20 | Triple* g = it->ref; // get generator before cco_routine starts! 21 | cco_routine (it) 22 | { 23 | for (g->c = 5;; ++g->c) { 24 | for (g->a = 1; g->a < g->c; ++g->a) { 25 | for (g->b = g->a; g->b < g->c; ++g->b) { 26 | if (g->a*g->a + g->b*g->b == g->c*g->c) { 27 | cco_yield; 28 | } 29 | } 30 | } 31 | } 32 | cco_finally: 33 | it->ref = NULL; // stop iteration 34 | printf("Coroutine done\n"); 35 | } 36 | return 0; 37 | } 38 | 39 | Triple_iter Triple_begin(Triple* g) { 40 | Triple_iter it = {.ref = g}; 41 | Triple_next(&it); 42 | return it; 43 | } 44 | 45 | int main(void) 46 | { 47 | Triple triple = {0}; 48 | 49 | puts("Pythagorean triples.\nGet all triples with c < 40, using for c_each:"); 50 | int n=0; 51 | for (c_each(i, Triple, triple)) { 52 | if (i.ref->c < 40) 53 | printf("%u: (%d, %d, %d)\n", n++, i.ref->a, i.ref->b, i.ref->c); 54 | else 55 | cco_stop(&i); 56 | } 57 | 58 | puts("\nGet the 10 first triples with c < 40, using c_filter:"); 59 | c_filter(Triple, triple, true 60 | && (value->c < 40) 61 | && cco_flt_take(10) // NB! use cco_flt_take(n) instead of c_flt_take(n) 62 | // to ensure coroutine cleanup. 63 | // Also applies to cco_flt_takewhile(pred) 64 | && printf("%d: (%d, %d, %d)\n", c_flt_getcount(), value->a, value->b, value->c) 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /examples/coroutines/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'cointerleave', 3 | 'coread', 4 | 'coroutines', 5 | 'coroutine_tasks', 6 | 'producer', 7 | 'producer_task', 8 | 'dining_philosophers', 9 | 'fibonacci', 10 | 'filetask', 11 | 'generator', 12 | 'scheduler', 13 | 'triples', 14 | ] 15 | test( 16 | sample, 17 | executable( 18 | sample, 19 | files(f'@sample@.c'), 20 | dependencies: example_deps, 21 | install: false, 22 | ), 23 | suite: 'coroutine', 24 | ) 25 | endforeach 26 | -------------------------------------------------------------------------------- /examples/coroutines/producer.c: -------------------------------------------------------------------------------- 1 | // https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct next_value { 9 | int val; 10 | cco_timer tm; 11 | cco_state cco; 12 | }; 13 | 14 | int next_value(struct next_value* co) { 15 | cco_routine (co) { 16 | while (true) { 17 | cco_await_timer_sec(&co->tm, 1 + rand() % 2); 18 | co->val = rand(); 19 | cco_yield; 20 | } 21 | } 22 | return 0; 23 | } 24 | 25 | void print_time(void) { 26 | time_t now = time(NULL); 27 | char mbstr[64]; 28 | strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now)); 29 | printf("%s ", mbstr); 30 | } 31 | 32 | // PRODUCER 33 | struct produce { 34 | struct next_value next; 35 | cstr text; 36 | cco_state cco; 37 | }; 38 | 39 | int produce(struct produce* pr) { 40 | cco_routine (pr) { 41 | pr->text = cstr_init(); 42 | while (true) { 43 | cco_await_coroutine(next_value(&pr->next), CCO_YIELD); 44 | cstr_printf(&pr->text, "item %d", pr->next.val); 45 | print_time(); 46 | printf("produced %s\n", cstr_str(&pr->text)); 47 | cco_yield; 48 | } 49 | 50 | cco_finally: 51 | cstr_drop(&pr->text); 52 | puts("done producer"); 53 | } 54 | return 0; 55 | } 56 | 57 | // CONSUMER 58 | struct consume { 59 | int n, i; 60 | cco_state cco; 61 | }; 62 | 63 | int consume(struct consume* co, struct produce* pr) { 64 | cco_routine (co) { 65 | for (co->i = 1; co->i <= co->n; ++co->i) { 66 | printf("consumer #%d\n", co->i); 67 | cco_await_coroutine(produce(pr), CCO_YIELD); 68 | print_time(); 69 | printf("consumed %s\n", cstr_str(&pr->text)); 70 | } 71 | 72 | cco_finally: 73 | puts("done consumer"); 74 | } 75 | return 0; 76 | } 77 | 78 | int main(void) { 79 | struct produce producer = {0}; 80 | struct consume consumer = {.n=5}; 81 | int count = 0; 82 | 83 | cco_run_coroutine(consume(&consumer, &producer)) { 84 | ++count; 85 | //cco_sleep_sec(0.001); 86 | //if (consumer.i == 3) cco_stop(&consumer); 87 | } 88 | cco_stop(&producer); 89 | produce(&producer); 90 | printf("count: %d\n", count); 91 | } 92 | -------------------------------------------------------------------------------- /examples/coroutines/producer_task.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define T Inventory, int 5 | #include 6 | 7 | // Example shows symmetric coroutines producer/consumer style. 8 | 9 | cco_task_struct (produce) { 10 | produce_state cco; // must be first (compile-time checked) 11 | struct consume* consumer; 12 | Inventory inv; 13 | int limit, batch, serial, total; 14 | }; 15 | 16 | cco_task_struct (consume) { 17 | consume_state cco; // must be first 18 | struct produce* producer; 19 | }; 20 | 21 | 22 | int produce(struct produce* co, cco_fiber* fb) { 23 | cco_routine (co) { 24 | while (1) { 25 | if (co->serial > co->total) { 26 | if (Inventory_is_empty(&co->inv)) 27 | cco_return; // cleanup and finish 28 | } 29 | else if (Inventory_size(&co->inv) < co->limit) { 30 | for (c_range(co->batch)) 31 | Inventory_push(&co->inv, ++co->serial); 32 | 33 | printf("produced %d items, Inventory has now %d items:\n", 34 | co->batch, (int)Inventory_size(&co->inv)); 35 | 36 | for (c_each(i, Inventory, co->inv)) 37 | printf(" %2d", *i.ref); 38 | puts(""); 39 | } 40 | 41 | cco_yield_to(co->consumer, fb); // symmetric transfer 42 | } 43 | 44 | cco_finally: 45 | cco_cancel_task(co->consumer, fb); 46 | Inventory_drop(&co->inv); 47 | puts("cleanup producer"); 48 | } 49 | return 0; 50 | } 51 | 52 | int consume(struct consume* co, cco_fiber* fb) { 53 | cco_routine (co) { 54 | int n, sz; 55 | while (1) { 56 | n = rand() % 10; 57 | sz = (int)Inventory_size(&co->producer->inv); 58 | if (n > sz) n = sz; 59 | 60 | for (c_range(n)) 61 | Inventory_pop(&co->producer->inv); 62 | printf("consumed %d items\n", n); 63 | 64 | cco_yield_to(co->producer, fb); // symmetric transfer 65 | } 66 | 67 | cco_finally: 68 | puts("cleanup consumer"); 69 | } 70 | return 0; 71 | } 72 | 73 | int main(void) 74 | { 75 | srand((unsigned)time(0)); 76 | struct produce producer = { 77 | .cco = {produce}, 78 | .inv = {0}, 79 | .limit = 12, 80 | .batch = 8, 81 | .total = 50, 82 | }; 83 | struct consume consumer = { 84 | .cco = {consume}, 85 | .producer = &producer, 86 | }; 87 | producer.consumer = &consumer; 88 | 89 | cco_run_task(&producer); 90 | } 91 | -------------------------------------------------------------------------------- /examples/coroutines/scheduler.c: -------------------------------------------------------------------------------- 1 | // https://www.youtube.com/watch?v=8sEe-4tig_A 2 | #include 3 | #include 4 | 5 | #define T Tasks, cco_task* 6 | #define i_keydrop(x) { puts("free task"); free(*x); } 7 | #define i_no_clone 8 | #include 9 | 10 | cco_task_struct (Scheduler) { 11 | Scheduler_state cco; 12 | cco_task* pulled; 13 | Tasks tasks; 14 | }; 15 | 16 | int Scheduler(struct Scheduler* co, cco_fiber* fb) { 17 | cco_routine (co) { 18 | while (!Tasks_is_empty(&co->tasks)) { 19 | co->pulled = Tasks_pull(&co->tasks); 20 | 21 | cco_await_task(co->pulled, fb, CCO_YIELD); 22 | 23 | if (fb->result == CCO_YIELD) { 24 | Tasks_push(&co->tasks, co->pulled); 25 | } else { 26 | Tasks_value_drop(&co->tasks, &co->pulled); 27 | } 28 | } 29 | 30 | cco_finally: 31 | Tasks_drop(&co->tasks); 32 | puts("Task queue dropped"); 33 | } 34 | return 0; 35 | } 36 | 37 | 38 | static int TaskA(struct cco_task* co, cco_fiber* fb) { 39 | (void)fb; 40 | cco_routine (co) { 41 | puts("Hello, from task A"); 42 | cco_yield; 43 | puts("A is back doing work"); 44 | cco_yield; 45 | puts("A is back doing more work"); 46 | cco_yield; 47 | puts("A is back doing even more work"); 48 | 49 | cco_finally: 50 | puts("A done"); 51 | } 52 | return 0; 53 | } 54 | 55 | 56 | static int TaskB(struct cco_task* co, cco_fiber* fb) { 57 | (void)fb; 58 | cco_routine (co) { 59 | puts("Hello, from task B"); 60 | cco_yield; 61 | puts("B is back doing work"); 62 | cco_yield; 63 | puts("B is back doing more work"); 64 | 65 | cco_finally: 66 | puts("B done"); 67 | } 68 | return 0; 69 | } 70 | 71 | int main(void) { 72 | struct Scheduler schedule = { 73 | .cco={Scheduler}, 74 | .tasks = c_make(Tasks, { 75 | c_new(cco_task, {.cco={TaskA}}), 76 | c_new(cco_task, {.cco={TaskB}}), 77 | }) 78 | }; 79 | 80 | cco_run_task(&schedule); 81 | } 82 | -------------------------------------------------------------------------------- /examples/coroutines/triples.c: -------------------------------------------------------------------------------- 1 | // https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ 2 | 3 | #include 4 | #include 5 | 6 | void triples_vanilla(int max_c) { 7 | for (int c = 5, i = 0;; ++c) { 8 | for (int a = 1; a < c; ++a) { 9 | for (int b = a + 1; b < c; ++b) { 10 | if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) { 11 | if (c > max_c) 12 | goto done; 13 | printf("%d: {%d, %d, %d}\n", ++i, a, b, c); 14 | } 15 | } 16 | } 17 | } 18 | done:; 19 | } 20 | 21 | struct triples { 22 | int max_c; 23 | int a, b, c; 24 | cco_state cco; 25 | }; 26 | 27 | int triples_coro(struct triples* t) { 28 | cco_routine (t) { 29 | for (t->c = 5;; ++t->c) { 30 | for (t->a = 1; t->a < t->c; ++t->a) { 31 | for (t->b = t->a + 1; t->b < t->c; ++t->b) { 32 | if ((int64_t)t->a * t->a + 33 | (int64_t)t->b * t->b == 34 | (int64_t)t->c * t->c) 35 | { 36 | if (t->c > t->max_c) 37 | cco_return; 38 | cco_yield; 39 | } 40 | } 41 | } 42 | } 43 | cco_finally: 44 | puts("done"); 45 | } 46 | return 0; 47 | } 48 | 49 | int gcd(int a, int b) { 50 | while (b) { 51 | int t = a % b; 52 | a = b; 53 | b = t; 54 | } 55 | return a; 56 | } 57 | 58 | int main(void) 59 | { 60 | puts("Vanilla triples:"); 61 | triples_vanilla(20); 62 | 63 | puts("\nCoroutine triples with GCD = 1:"); 64 | struct triples t = {.max_c = 100}; 65 | int n = 0; 66 | 67 | cco_run_coroutine(triples_coro(&t)) { 68 | if (gcd(t.a, t.b) > 1) 69 | continue; 70 | if (++n <= 20) 71 | printf("%d: {%d, %d, %d}\n", n, t.a, t.b, t.c); 72 | else 73 | cco_stop(&t); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/hashmaps/birthday.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define T hmap_ui, uint64_t, int 7 | #include 8 | 9 | static uint64_t seed = 12345; 10 | 11 | static void test_repeats(void) 12 | { 13 | enum {BITS = 46, BITS_TEST = BITS/2 + 2}; 14 | static const isize N = (isize)(1ull << BITS_TEST); 15 | static const uint64_t mask = (1ull << BITS) - 1; 16 | 17 | printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST); 18 | crand64 rng = crand64_from(seed); 19 | 20 | hmap_ui m = hmap_ui_with_capacity(N); 21 | for (c_range(i, N)) { 22 | uint64_t k = crand64_uint_r(&rng, 1) & mask; 23 | int v = hmap_ui_insert(&m, k, 0).ref->second += 1; 24 | if (v > 1) printf("repeated value %" PRIu64 " (%d) at 2^%d\n", 25 | k, v, (int)log2((double)i)); 26 | } 27 | hmap_ui_drop(&m); 28 | } 29 | 30 | #define T hmap_uu, uint32_t, uint64_t 31 | #include 32 | 33 | void test_distribution(void) 34 | { 35 | enum {BITS = 24}; 36 | printf("distribution test: 2^%d values\n", BITS); 37 | crand64 rng = crand64_from(seed); 38 | const isize N = (isize)(1ull << BITS); 39 | 40 | hmap_uu map = {0}; 41 | for (c_range(N)) { 42 | uint64_t k = crand64_uint_r(&rng, 1); 43 | hmap_uu_insert(&map, k & 0xf, 0).ref->second += 1; 44 | } 45 | 46 | uint64_t sum = 0; 47 | for (c_each(i, hmap_uu, map)) sum += i.ref->second; 48 | sum /= (uint64_t)map.size; 49 | 50 | for (c_each(i, hmap_uu, map)) { 51 | printf("%4" PRIu32 ": %" PRIu64 " - %" PRIu64 ": %11.8f\n", 52 | i.ref->first, i.ref->second, sum, 53 | (1.0 - (double)i.ref->second / (double)sum)); 54 | } 55 | 56 | hmap_uu_drop(&map); 57 | } 58 | 59 | int main(void) 60 | { 61 | seed = (uint64_t)time(NULL); 62 | test_distribution(); 63 | test_repeats(); 64 | } 65 | -------------------------------------------------------------------------------- /examples/hashmaps/books.c: -------------------------------------------------------------------------------- 1 | // https://doc.rust-lang.org/std/collections/struct.HashMap.html 2 | #include 3 | #define i_keypro cstr 4 | #define i_valpro cstr 5 | #include 6 | 7 | // Type inference lets us omit an explicit type signature (which 8 | // would be `HashMap` in this example). 9 | int main(void) 10 | { 11 | hmap_cstr book_reviews = {0}; 12 | 13 | // Review some books. 14 | hmap_cstr_emplace(&book_reviews, 15 | "Adventures of Huckleberry Finn", 16 | "My favorite book." 17 | ); 18 | hmap_cstr_emplace(&book_reviews, 19 | "Grimms' Fairy Tales", 20 | "Masterpiece." 21 | ); 22 | hmap_cstr_emplace(&book_reviews, 23 | "Pride and Prejudice", 24 | "Very enjoyable" 25 | ); 26 | hmap_cstr_insert(&book_reviews, 27 | cstr_lit("The Adventures of Sherlock Holmes"), 28 | cstr_lit("Eye lyked it alot.") 29 | ); 30 | 31 | // Check for a specific one. 32 | // When collections store owned values (String), they can still be 33 | // queried using references (&str). 34 | if (hmap_cstr_contains(&book_reviews, "Les Misérables")) { 35 | printf("We've got %d reviews, but Les Misérables ain't one.", 36 | (int)hmap_cstr_size(&book_reviews)); 37 | } 38 | 39 | // oops, this review has a lot of spelling mistakes, let's delete it. 40 | hmap_cstr_erase(&book_reviews, "The Adventures of Sherlock Holmes"); 41 | 42 | // Look up the values associated with some keys. 43 | const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"}; 44 | for (c_range(i, c_countof(to_find))) { 45 | const hmap_cstr_value* b = hmap_cstr_get(&book_reviews, to_find[i]); 46 | if (b) 47 | printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second)); 48 | else 49 | printf("%s is unreviewed.\n", to_find[i]); 50 | } 51 | 52 | // Look up the value for a key (will panic if the key is not found). 53 | printf("Review for Jane: %s\n", cstr_str(hmap_cstr_at(&book_reviews, "Pride and Prejudice"))); 54 | 55 | // Iterate over everything. 56 | for (c_each_kv(book, review, hmap_cstr, book_reviews)) { 57 | printf("%s: \"%s\"\n", cstr_str(book), cstr_str(review)); 58 | } 59 | 60 | hmap_cstr_drop(&book_reviews); 61 | } 62 | -------------------------------------------------------------------------------- /examples/hashmaps/hashmap.c: -------------------------------------------------------------------------------- 1 | // https://doc.rust-lang.org/rust-by-example/std/hash.html 2 | #include 3 | #include 4 | #define T StrMap, cstr, cstr, (c_keypro | c_valpro) 5 | #include 6 | 7 | const char* call(const char* number) { 8 | if (strcmp(number, "798-1364") == 0) 9 | return "We're sorry, the call cannot be completed as dialed." 10 | " Please hang up and try again."; 11 | else if (strcmp(number, "645-7689") == 0) 12 | return "Hello, this is Mr. Awesome's Pizza. My name is Fred." 13 | " What can I get for you today?"; 14 | else 15 | return "Hi! Who is this again?"; 16 | } 17 | 18 | int main(void) { 19 | StrMap contacts = {0}; 20 | 21 | StrMap_emplace(&contacts, "Daniel", "798-1364"); 22 | StrMap_emplace(&contacts, "Ashley", "645-7689"); 23 | StrMap_emplace(&contacts, "Katie", "435-8291"); 24 | StrMap_emplace(&contacts, "Robert", "956-1745"); 25 | 26 | const StrMap_value* v; 27 | if ((v = StrMap_get(&contacts, "Daniel"))) 28 | printf("Calling Daniel: %s\n", call(cstr_str(&v->second))); 29 | else 30 | printf("Don't have Daniel's number."); 31 | 32 | StrMap_emplace_or_assign(&contacts, "Daniel", "164-6743"); 33 | 34 | if ((v = StrMap_get(&contacts, "Ashley"))) 35 | printf("Calling Ashley: %s\n", call(cstr_str(&v->second))); 36 | else 37 | printf("Don't have Ashley's number."); 38 | 39 | StrMap_erase(&contacts, "Ashley"); 40 | 41 | puts(""); 42 | for (c_each_kv(contact, number, StrMap, contacts)) { 43 | printf("Calling %s: %s\n", cstr_str(contact), call(cstr_str(number))); 44 | } 45 | puts(""); 46 | 47 | StrMap_drop(&contacts); 48 | } 49 | -------------------------------------------------------------------------------- /examples/hashmaps/mapmap.c: -------------------------------------------------------------------------------- 1 | // create a structure like: std::map>: 2 | #include 3 | 4 | // People: map cstr -> cstr. (name -> email) 5 | #define T People, cstr, cstr, (c_keypro | c_valpro) 6 | #define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override 7 | #include 8 | 9 | // Departments: map cstr -> People. People is a map and has _clone, _drop, therefore a "class". 10 | #define T Departments, cstr, People, (c_keypro | c_valclass) 11 | #include 12 | 13 | 14 | void add(Departments* deps, const char* name, const char* email, const char* dep) 15 | { 16 | People *people = &Departments_emplace(deps, dep, People_init()).ref->second; 17 | People_emplace_or_assign(people, name, email); 18 | } 19 | 20 | int contains(Departments* map, const char* name) 21 | { 22 | int count = 0; 23 | for (c_each(i, Departments, *map)) 24 | if (People_contains(&i.ref->second, name)) 25 | ++count; 26 | return count; 27 | } 28 | 29 | int main(void) 30 | { 31 | Departments map = {0}; 32 | 33 | add(&map, "Anna Kendro", "Anna@myplace.com", "Support"); 34 | add(&map, "Terry Dane", "Terry@myplace.com", "Development"); 35 | add(&map, "Kik Winston", "Kik@myplace.com", "Finance"); 36 | add(&map, "Nancy Drew", "Nancy@live.com", "Development"); 37 | add(&map, "Nick Denton", "Nick@myplace.com", "Finance"); 38 | add(&map, "Stan Whiteword", "Stan@myplace.com", "Marketing"); 39 | add(&map, "Serena Bath", "Serena@myplace.com", "Support"); 40 | add(&map, "Patrick Dust", "Patrick@myplace.com", "Finance"); 41 | add(&map, "Red Winger", "Red@gmail.com", "Marketing"); 42 | add(&map, "Nick Denton", "Nick@yahoo.com", "Support"); 43 | add(&map, "Colin Turth", "Colin@myplace.com", "Support"); 44 | add(&map, "Dennis Kay", "Dennis@mail.com", "Marketing"); 45 | add(&map, "Anne Dickens", "Anne@myplace.com", "Development"); 46 | 47 | for (c_each_kv(dep, people, Departments, map)) 48 | for (c_each_kv(name, email, People, *people)) 49 | printf("%s: %s - %s\n", cstr_str(dep), cstr_str(name), cstr_str(email)); 50 | puts(""); 51 | 52 | printf("found Nick Denton: %d\n", contains(&map, "Nick Denton")); 53 | printf("found Patrick Dust: %d\n", contains(&map, "Patrick Dust")); 54 | printf("found Dennis Kay: %d\n", contains(&map, "Dennis Kay")); 55 | printf("found Serena Bath: %d\n", contains(&map, "Serena Bath")); 56 | puts("Done"); 57 | 58 | Departments_drop(&map); 59 | } 60 | -------------------------------------------------------------------------------- /examples/hashmaps/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'birthday', 3 | 'books', 4 | 'hashmap', 5 | 'mapmap', 6 | 'new_map', 7 | 'phonebook', 8 | 'unordered_set', 9 | 'vikings', 10 | ] 11 | test( 12 | sample, 13 | executable( 14 | sample, 15 | files(f'@sample@.c'), 16 | dependencies: example_deps, 17 | install: false, 18 | ), 19 | suite: 'hmap', 20 | ) 21 | endforeach 22 | -------------------------------------------------------------------------------- /examples/hashmaps/new_map.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | declare_hashmap(hmap_pnt, struct Point, int); 5 | 6 | typedef struct MyStruct { 7 | hmap_pnt pntmap; 8 | cstr name; 9 | } MyStruct; 10 | 11 | // int => int map 12 | #define T hmap_int, int, int 13 | #include 14 | 15 | // Point => int map 16 | typedef struct Point { int x, y; } Point; 17 | 18 | // Point => int map, uses default hash function 19 | #define T hmap_pnt, struct Point, int, (c_declared) 20 | #define i_eq c_memcmp_eq 21 | #include 22 | 23 | // cstr => cstr map 24 | #define i_keypro cstr 25 | #define i_valpro cstr 26 | #include 27 | 28 | // string set 29 | #define i_keypro cstr 30 | #include 31 | 32 | 33 | int main(void) 34 | { 35 | hmap_pnt pmap = c_make(hmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}}); 36 | 37 | for (c_each(i, hmap_pnt, pmap)) 38 | printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second); 39 | puts(""); 40 | 41 | hmap_cstr smap = c_make(hmap_cstr, { 42 | {"Hello, friend", "long time no see"}, 43 | {"So long", "see you around"}, 44 | }); 45 | 46 | hset_cstr sset = c_make(hset_cstr, { 47 | "Hello, friend", 48 | "Nice to see you again", 49 | "So long", 50 | }); 51 | 52 | hmap_int map = {0}; 53 | hmap_int_insert(&map, 123, 321); 54 | hmap_int_insert(&map, 456, 654); 55 | hmap_int_insert(&map, 789, 987); 56 | 57 | for (c_each(i, hset_cstr, sset)) 58 | printf(" %s\n", cstr_str(i.ref)); 59 | 60 | hmap_int_drop(&map); 61 | hset_cstr_drop(&sset); 62 | hmap_cstr_drop(&smap); 63 | hmap_pnt_drop(&pmap); 64 | } 65 | -------------------------------------------------------------------------------- /examples/hashmaps/phonebook.c: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // Copyright (c) 2018 Maksim Andrianov 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to 6 | // deal in the Software without restriction, including without limitation the 7 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | // IN THE SOFTWARE. 21 | 22 | // Program to emulates the phone book. 23 | #include 24 | #define T StrMap, cstr, cstr, (c_keypro | c_valpro) 25 | #include 26 | 27 | #define T StrSet, cstr, (c_keypro) 28 | #include 29 | 30 | void print_phone_book(StrMap phone_book) 31 | { 32 | for (c_each(i, StrMap, phone_book)) 33 | printf("%s\t- %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); 34 | } 35 | 36 | int main(void) 37 | { 38 | StrMap phone_book = c_make(StrMap, { 39 | {"Lilia Friedman", "(892) 670-4739"}, 40 | {"Tariq Beltran", "(489) 600-7575"}, 41 | {"Laiba Juarez", "(303) 885-5692"}, 42 | {"Elliott Mooney", "(945) 616-4482"}, 43 | }); 44 | 45 | printf("Phone book:\n"); 46 | print_phone_book(phone_book); 47 | 48 | StrMap_emplace(&phone_book, "Zak Byers", "(551) 396-1880"); 49 | StrMap_emplace(&phone_book, "Zak Byers", "(551) 396-1990"); 50 | 51 | printf("\nPhone book after adding Zak Byers:\n"); 52 | print_phone_book(phone_book); 53 | 54 | if (StrMap_contains(&phone_book, "Tariq Beltran")) 55 | printf("\nTariq Beltran is in phone book\n"); 56 | 57 | StrMap_erase(&phone_book, "Tariq Beltran"); 58 | StrMap_erase(&phone_book, "Elliott Mooney"); 59 | 60 | printf("\nPhone book after erasing Tariq and Elliott:\n"); 61 | print_phone_book(phone_book); 62 | 63 | StrMap_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188"); 64 | 65 | printf("\nPhone book after update phone of Zak Byers:\n"); 66 | print_phone_book(phone_book); 67 | 68 | StrMap_drop(&phone_book); 69 | } 70 | -------------------------------------------------------------------------------- /examples/hashmaps/unordered_set.c: -------------------------------------------------------------------------------- 1 | // https://iq.opengenus.org/containers-cpp-stl/ 2 | // C program to demonstrate various function of stc hset 3 | #include 4 | #define i_keypro cstr 5 | #include 6 | 7 | int main(void) 8 | { 9 | // declaring set for storing string data-type 10 | hset_cstr stringSet = {0}; 11 | c_defer( 12 | hset_cstr_drop(&stringSet) 13 | ){ 14 | // inserting various string, same string will be stored 15 | // once in set 16 | hset_cstr_emplace(&stringSet, "code"); 17 | hset_cstr_emplace(&stringSet, "in"); 18 | hset_cstr_emplace(&stringSet, "C"); 19 | hset_cstr_emplace(&stringSet, "is"); 20 | hset_cstr_emplace(&stringSet, "fast"); 21 | 22 | const char* key = "slow"; 23 | 24 | // find returns end iterator if key is not found, 25 | // else it returns iterator to that key 26 | 27 | if (hset_cstr_find(&stringSet, key).ref == NULL) 28 | printf("\"%s\" not found\n", key); 29 | else 30 | printf("Found \"%s\"\n", key); 31 | 32 | key = "C"; 33 | if (!hset_cstr_contains(&stringSet, key)) 34 | printf("\"%s\" not found\n", key); 35 | else 36 | printf("Found \"%s\"\n", key); 37 | 38 | // now iterating over whole set and printing its 39 | // content 40 | printf("All elements :\n"); 41 | for (c_each(itr, hset_cstr, stringSet)) 42 | printf("%s\n", cstr_str(itr.ref)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/hashmaps/vikings.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct Viking { 4 | cstr name; 5 | cstr country; 6 | } Viking; 7 | 8 | Viking Viking_make(cstr_raw name, cstr_raw country) { 9 | return (Viking){.name = cstr_from(name), .country = cstr_from(country)}; 10 | } 11 | 12 | void Viking_drop(Viking* vk) { 13 | cstr_drop(&vk->name); 14 | cstr_drop(&vk->country); 15 | } 16 | 17 | Viking Viking_clone(Viking v) { 18 | v.name = cstr_clone(v.name); 19 | v.country = cstr_clone(v.country); 20 | return v; 21 | } 22 | 23 | // Define Viking_raw, a Viking lookup struct with eq, hash and conversion functions between them: 24 | typedef struct { 25 | const char* name; 26 | const char* country; 27 | } Viking_raw; 28 | 29 | bool Viking_raw_eq(const Viking_raw* rx, const Viking_raw* ry) { 30 | return strcmp(rx->name, ry->name)==0 && strcmp(rx->country, ry->country)==0; 31 | } 32 | 33 | size_t Viking_raw_hash(const Viking_raw* rv) { 34 | return c_hash_mix(c_hash_str(rv->name), c_hash_str(rv->country)); 35 | } 36 | 37 | Viking Viking_from(Viking_raw raw) { // note: parameter is by value 38 | Viking v = {cstr_from(raw.name), cstr_from(raw.country)}; return v; 39 | } 40 | 41 | Viking_raw Viking_toraw(const Viking* vp) { 42 | Viking_raw rv = {cstr_str(&vp->name), cstr_str(&vp->country)}; return rv; 43 | } 44 | 45 | // Define the map. Viking is now a "pro"-type: 46 | #define T Players, Viking, int, (c_keypro) 47 | #include 48 | 49 | int main(void) 50 | { 51 | Players vikings = c_make(Players, { 52 | {{"Einar", "Norway"}, 25}, 53 | {{"Olaf", "Denmark"}, 24}, 54 | {{"Harald", "Iceland"}, 12}, 55 | }); 56 | 57 | // Now lookup is using Viking_raw, not Viking: 58 | printf("Lookup: Olaf of Denmark has %d hp\n\n", *Players_at(&vikings, (Viking_raw){"Olaf", "Denmark"})); 59 | 60 | for (c_each(v, Players, vikings)) { 61 | Players_raw r = Players_value_toraw(v.ref); 62 | printf("%s of %s has %d hp\n", r.first.name, r.first.country, r.second); 63 | } 64 | Players_drop(&vikings); 65 | } 66 | -------------------------------------------------------------------------------- /examples/linkedlists/intrusive.c: -------------------------------------------------------------------------------- 1 | // Example of list using the node API. 2 | 3 | #include 4 | 5 | #define T List, int, (c_use_cmp) 6 | #include 7 | 8 | void printList(List list) { 9 | printf("list:"); 10 | for (c_each(i, List, list)) 11 | printf(" %d", *i.ref); 12 | puts(""); 13 | } 14 | 15 | int main(void) { 16 | List list = {0}; 17 | for (c_items(i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8})) 18 | List_push_back_node(&list, c_new(List_node, {.value=*i.ref})); 19 | 20 | printList(list); 21 | 22 | puts("Sort list"); 23 | List_sort(&list); 24 | printList(list); 25 | 26 | puts("Remove nodes from list"); 27 | while (!List_is_empty(&list)) 28 | free(List_unlink_after_node(&list, list.last)); 29 | 30 | printList(list); 31 | } 32 | -------------------------------------------------------------------------------- /examples/linkedlists/list_erase.c: -------------------------------------------------------------------------------- 1 | // erasing from list 2 | #include 3 | 4 | #define T IList, int 5 | #include 6 | 7 | int main(void) 8 | { 9 | IList L = c_make(IList, {10, 20, 30, 40, 50}); 10 | 11 | for (c_each(x, IList, L)) 12 | printf("%d ", *x.ref); 13 | puts(""); 14 | // 10 20 30 40 50 15 | IList_iter it = IList_begin(&L); // ^ 16 | IList_next(&it); 17 | it = IList_erase_at(&L, it); // 10 30 40 50 18 | // ^ 19 | IList_iter end = IList_end(&L); // 20 | IList_next(&it); 21 | it = IList_erase_range(&L, it, end); // 10 30 22 | // ^ 23 | printf("list contains:"); 24 | for (c_each(x, IList, L)) 25 | printf(" %d", *x.ref); 26 | puts(""); 27 | 28 | IList_drop(&L); 29 | } 30 | -------------------------------------------------------------------------------- /examples/linkedlists/list_splice.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define T IList, int 4 | #include 5 | 6 | void print_IList(const char* s, IList list) 7 | { 8 | printf("%s", s); 9 | for (c_each(i, IList, list)) { 10 | printf(" %d", *i.ref); 11 | } 12 | puts(""); 13 | } 14 | 15 | int main(void) 16 | { 17 | IList list1 = c_make(IList, {1, 2, 3, 4, 5}); 18 | IList list2 = c_make(IList, {10, 20, 30, 40, 50}); 19 | 20 | print_IList("list1:", list1); 21 | print_IList("list2:", list2); 22 | 23 | IList_iter it = IList_advance(IList_begin(&list1), 2); 24 | it = IList_splice(&list1, it, &list2); 25 | 26 | puts("After splice"); 27 | print_IList("list1:", list1); 28 | print_IList("list2:", list2); 29 | 30 | IList_splice_range(&list2, IList_begin(&list2), &list1, it, IList_end(&list1)); 31 | 32 | puts("After splice_range"); 33 | print_IList("list1:", list1); 34 | print_IList("list2:", list2); 35 | 36 | c_drop(IList, &list1, &list2); 37 | } 38 | -------------------------------------------------------------------------------- /examples/linkedlists/lists.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define T DList, double, (c_use_cmp) 7 | #include 8 | 9 | int main(void) { 10 | const int n = 3000000; 11 | DList list = {0}; 12 | 13 | crand64_seed(1234567); 14 | int m = 0; 15 | for (c_range(n)) 16 | DList_push_back(&list, crand64_real()*n + 100), ++m; 17 | 18 | printf("sum of %d: ", m); 19 | double sum = 0.0; 20 | c_filter(DList, list, sum += *value); 21 | printf("%f\n", sum); 22 | 23 | // Print 10 first items using c_filter: 24 | c_filter(DList, list, true 25 | && c_flt_take(10) 26 | && printf("%4d: %10f\n", c_flt_getcount(), *value)); 27 | 28 | puts("sort:"); 29 | DList_sort(&list); // qsort O(n*log n) 30 | 31 | c_filter(DList, list, true 32 | && c_flt_take(10) 33 | && printf("%4d: %10f\n", c_flt_getcount(), *value)); 34 | 35 | DList_drop(&list); 36 | list = c_make(DList, {10, 20, 30, 40, 30, 50}); 37 | 38 | printf("List: "); 39 | for (c_each(i, DList, list)) 40 | printf(" %g", *i.ref); 41 | puts(""); 42 | 43 | const double* v = DList_find(&list, 30).ref; 44 | printf("Found: %g\n", *v); 45 | 46 | DList_remove(&list, 30); 47 | DList_insert_at(&list, DList_begin(&list), 5); // same as push_front() 48 | DList_push_front(&list, 2023); 49 | DList_push_back(&list, 2024); 50 | 51 | printf("Full: "); 52 | for (c_each(i, DList, list)) 53 | printf(" %g", *i.ref); 54 | 55 | printf("\nTail: "); 56 | DList_iter it = DList_begin(&list); 57 | 58 | for (c_each(i, DList, DList_advance(it, 4), DList_end(&list))) 59 | printf(" %g", *i.ref); 60 | puts(""); 61 | 62 | DList_drop(&list); 63 | } 64 | -------------------------------------------------------------------------------- /examples/linkedlists/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'intrusive', 3 | 'list_erase', 4 | 'lists', 5 | 'list_splice', 6 | 'new_list', 7 | ] 8 | test( 9 | sample, 10 | executable( 11 | sample, 12 | files(f'@sample@.c'), 13 | dependencies: example_deps, 14 | install: false, 15 | ), 16 | suite: 'list', 17 | ) 18 | endforeach 19 | -------------------------------------------------------------------------------- /examples/linkedlists/new_list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | declare_list(list_i32, int32_t); 5 | declare_list(list_pnt, struct Point); 6 | 7 | typedef struct { 8 | list_i32 intlist; 9 | list_pnt pntlist; 10 | } MyStruct; 11 | 12 | #define T list_i32, int32_t, (c_declared) 13 | #include 14 | 15 | typedef struct Point { int x, y; } Point; 16 | int point_cmp(const Point* a, const Point* b) { 17 | int c = a->x - b->x; 18 | return c ? c : a->y - b->y; 19 | } 20 | 21 | #define T list_pnt, Point, (c_declared) 22 | #define i_cmp point_cmp 23 | #include 24 | 25 | // use < and == operators for comparison 26 | #define T list_float, float, (c_use_cmp) 27 | #include 28 | 29 | void MyStruct_drop(MyStruct* s); 30 | 31 | // exclude cloning support because of class/drop: 32 | #define T MyList, MyStruct, (c_keyclass | c_no_clone) 33 | #include 34 | 35 | void MyStruct_drop(MyStruct* s) { 36 | list_i32_drop(&s->intlist); 37 | list_pnt_drop(&s->pntlist); 38 | } 39 | 40 | 41 | int main(void) 42 | { 43 | MyStruct my = {0}; 44 | list_i32_push_back(&my.intlist, 123); 45 | list_pnt_push_back(&my.pntlist, c_literal(Point){123, 456}); 46 | MyStruct_drop(&my); 47 | 48 | list_pnt plist = c_make(list_pnt, {{42, 14}, {32, 94}, {62, 81}}); 49 | list_pnt_sort(&plist); 50 | 51 | for (c_each(i, list_pnt, plist)) 52 | printf(" (%d %d)", i.ref->x, i.ref->y); 53 | puts(""); 54 | list_pnt_drop(&plist); 55 | 56 | 57 | list_float flist = c_make(list_float, {123.3f, 321.2f, -32.2f, 78.2f}); 58 | list_float_sort(&flist); 59 | 60 | for (c_each(i, list_float, flist)) 61 | printf(" %g", (double)*i.ref); 62 | 63 | puts(""); 64 | list_float_drop(&flist); 65 | } 66 | -------------------------------------------------------------------------------- /examples/make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #set -e 4 | 5 | if [ "$(uname)" = 'Linux' ]; then 6 | sanitize='-fsanitize=address -fsanitize=undefined -fsanitize-trap' 7 | clibs='-lm' # -pthread 8 | oflag='-o ' 9 | fi 10 | common="-std=c99 -Wpedantic -Wall -Werror" 11 | #cc=clang; cflags="-s -O3 $common" 12 | cc=gcc; cflags="-s -O3 $common" 13 | #cc=gcc; cflags="-g $sanitize $common" 14 | #cc=gcc; cflags="-x c++ -std=c++17 -O2 -s -DSTC_IMPLEMENT -Di_import" 15 | #cc=tcc; cflags="-std=c99" 16 | #cc=cl; cflags="-nologo -O2 -MD -W3 -std:c11 -wd4003" 17 | #cc=cl; cflags="-nologo -c -TP -std:c++20 -wd4003 -DSTC_IMPLEMENT -Di_import" 18 | 19 | if [ "$cc" = "cl" ]; then 20 | oflag='/Fe:' 21 | else 22 | oflag='-o ' 23 | fi 24 | 25 | run=0 26 | if [ "$1" = '-h' -o "$1" = '--help' ]; then 27 | echo usage: runall.sh [-run] [compiler + options] 28 | exit 29 | fi 30 | if [ "$1" = '-run' ]; then 31 | run=1 32 | shift 33 | fi 34 | if [ ! -z "$1" ] ; then 35 | comp="$@" 36 | else 37 | comp="$cc $cflags" 38 | fi 39 | 40 | INC= 41 | #INC=-I../include 42 | #INC=-I../../stcsingle 43 | #CPATH= 44 | if [ $run = 0 ] ; then 45 | for i in */*.c ; do 46 | out=$(basename $i .c).exe 47 | #out=$(dirname $i)/$(basename $i .c).exe 48 | #echo $comp -I../../../stcsingle $i $clibs $oflag$out 49 | echo $comp $INC $i $clibs $oflag$out 50 | #$comp $INC $i $clibs $oflag$out -lstc 51 | $comp $INC $i $clibs $oflag$out -I../include -DSTC_STATIC 52 | done 53 | else 54 | for i in */*.c ; do 55 | out=$(basename $i .c).exe 56 | #out=$(dirname $i)/$(basename $i .c).exe 57 | echo $comp $INC $i $clibs $oflag$out 58 | $comp $INC $i $clibs $oflag$out -lstc 59 | if [ -f $out ]; then ./$out; fi 60 | done 61 | fi 62 | 63 | #rm -f a.out *.o *.obj # *.exe 64 | -------------------------------------------------------------------------------- /examples/meson.build: -------------------------------------------------------------------------------- 1 | examples = get_option('examples').enable_auto_if(root) 2 | 3 | if examples.enabled() 4 | example_deps = [ 5 | stc_dep, 6 | cc.find_library('m', required: false), 7 | ] 8 | subdir('algorithms') 9 | subdir('bitsets') 10 | subdir('coroutines') 11 | subdir('hashmaps') 12 | subdir('linkedlists') 13 | subdir('mixed') 14 | subdir('priorityqueues') 15 | subdir('queues') 16 | subdir('regularexpressions') 17 | subdir('smartpointers') 18 | subdir('sortedmaps') 19 | subdir('spans') 20 | subdir('strings') 21 | subdir('vectors') 22 | endif 23 | -------------------------------------------------------------------------------- /examples/mixed/complex.c: -------------------------------------------------------------------------------- 1 | 2 | // Define similar c++ data types: 3 | // 4 | // using FloatStack = std::stack; 5 | // using StackList = std::forward_list; 6 | // using ListMap = std::unordered_map; 7 | // using MapMap = std::unordered_map; 8 | #include 9 | 10 | #define T FloatStack, float 11 | #define i_keydrop(p) printf("drop %g\n", *p) 12 | #define i_keyclone(v) v // only because i_keydrop was defined 13 | #include 14 | 15 | // container as elements is "class"; has _clone() and _drop() "members" 16 | #define T StackList, FloatStack, (c_keyclass) 17 | #include 18 | 19 | // same, but StackList is the mapped value type, not the key: 20 | #define T ListMap, int, StackList, (c_valclass) 21 | #include 22 | 23 | // cstr is "pro"; has _clone, _drop, _cmp, _hash, _toraw, and _from. 24 | #define T MapMap, cstr, ListMap, (c_keypro | c_valclass) 25 | #include 26 | 27 | 28 | int main(void) 29 | { 30 | MapMap mmap = {0}; 31 | 32 | // Put in some data in the structures 33 | ListMap* lmap = &MapMap_emplace(&mmap, "first", ListMap_init()).ref->second; 34 | StackList* list = &ListMap_insert(lmap, 42, StackList_init()).ref->second; 35 | FloatStack* stack = StackList_push_back(list, FloatStack_with_size(10, 42)); 36 | stack->data[3] = 3.1415927f; 37 | 38 | // Access the data entry 39 | const ListMap* lmap_p = MapMap_at(&mmap, "first"); 40 | const StackList* list_p = ListMap_at(lmap_p, 42); 41 | const FloatStack* stack_p = StackList_back(list_p); 42 | 43 | printf("value is: %g\n", 44 | stack_p->data[3] // pi 45 | ); 46 | printf("directly: %g\n", 47 | StackList_back(ListMap_at(MapMap_at(&mmap, "first"), 42))->data[3] // pi 48 | ); 49 | 50 | // Free everything 51 | MapMap_drop(&mmap); 52 | } 53 | -------------------------------------------------------------------------------- /examples/mixed/convert.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define i_keypro cstr // key = cstr 5 | #define i_valpro cstr 6 | #include 7 | 8 | #define i_keypro cstr 9 | #include 10 | 11 | #define i_keypro cstr 12 | #include 13 | 14 | int main(void) 15 | { 16 | hmap_cstr map = {0}, mclone = {0}; 17 | vec_cstr keys = {0}, values = {0}; 18 | list_cstr list = {0}; 19 | c_defer( 20 | hmap_cstr_drop(&map), 21 | hmap_cstr_drop(&mclone), 22 | vec_cstr_drop(&keys), 23 | vec_cstr_drop(&values), 24 | list_cstr_drop(&list) 25 | ){ 26 | map = c_make(hmap_cstr, { 27 | {"green", "#00ff00"}, 28 | {"blue", "#0000ff"}, 29 | {"yellow", "#ffff00"}, 30 | }); 31 | 32 | puts("MAP:"); 33 | c_filter(hmap_cstr, map, 34 | printf(" %s: %s\n", cstr_str(&value->first), cstr_str(&value->second))); 35 | 36 | puts("\nCLONE MAP:"); 37 | mclone = hmap_cstr_clone(map); 38 | // print 39 | c_filter(hmap_cstr, mclone, 40 | printf(" %s: %s\n", cstr_str(&value->first), cstr_str(&value->second))); 41 | 42 | puts("\nCOPY MAP TO VECS:"); 43 | c_filter(hmap_cstr, mclone, 44 | (vec_cstr_push(&keys, cstr_clone(value->first)), 45 | vec_cstr_push(&values, cstr_clone(value->second)))); 46 | // print both keys and values zipped 47 | c_filter_zip(vec_cstr, keys, values, 48 | printf(" %s: %s\n", cstr_str(value1), cstr_str(value2))); 49 | 50 | puts("\nCOPY VEC TO LIST:"); 51 | c_copy_to(list_cstr, &list, vec_cstr, keys); 52 | // print 53 | c_filter(list_cstr, list, printf(" %s\n", cstr_str(value))); 54 | 55 | puts("\nCOPY VEC AND LIST TO MAP:"); 56 | hmap_cstr_clear(&map); 57 | c_filter_zip(vec_cstr, values, list_cstr, list, 58 | hmap_cstr_emplace(&map, cstr_str(value1), cstr_str(value2))); 59 | // print inverted map 60 | c_filter(hmap_cstr, map, 61 | printf(" %s: %s\n", cstr_str(&value->first), cstr_str(&value->second))); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /examples/mixed/inits.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define T IdMap, int, cstr, (c_valpro) // Map of int => cstr 4 | #include 5 | 6 | #define T NationMap, cstr, int, (c_keypro) // Map of cstr => int 7 | #include 8 | 9 | typedef struct {int x, y;} IPair; 10 | inline static int IPair_cmp(const IPair* a, const IPair* b) { 11 | int c = c_default_cmp(&a->x, &b->x); 12 | return c ? c : c_default_cmp(&a->y, &b->y); 13 | } 14 | 15 | #define T vec_ip, IPair, (c_cmpclass) 16 | #include 17 | 18 | #define T list_ip, IPair, (c_cmpclass) 19 | #include 20 | 21 | #define T PriorityQ, float 22 | #include 23 | 24 | int main(void) 25 | { 26 | // VEC FLOAT / PRIORITY QUEUE 27 | 28 | PriorityQ floats = {0}; 29 | const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f}; 30 | 31 | // PRIORITY QUEUE 32 | for (c_range(i, c_countof(nums))) 33 | PriorityQ_push(&floats, nums[i]); 34 | 35 | puts("\npop and show high priorites first:"); 36 | while (! PriorityQ_is_empty(&floats)) { 37 | printf("%.1f ", (double)*PriorityQ_top(&floats)); 38 | PriorityQ_pop(&floats); 39 | } 40 | puts("\n"); 41 | PriorityQ_drop(&floats); 42 | 43 | // CMAP ID 44 | 45 | int year = 2020; 46 | IdMap idnames = {0}; 47 | IdMap_emplace(&idnames, 100, "Hello"); 48 | IdMap_insert(&idnames, 110, cstr_lit("World")); 49 | IdMap_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year)); 50 | 51 | for (c_each(i, IdMap, idnames)) 52 | printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second)); 53 | puts(""); 54 | IdMap_drop(&idnames); 55 | 56 | // CMAP CNT 57 | 58 | NationMap countries = c_make(NationMap, { 59 | {"Norway", 100}, 60 | {"Denmark", 50}, 61 | {"Iceland", 10}, 62 | {"Belgium", 10}, 63 | {"Italy", 10}, 64 | {"Germany", 10}, 65 | {"Spain", 10}, 66 | {"France", 10}, 67 | }); 68 | NationMap_emplace(&countries, "Greenland", 0).ref->second += 20; 69 | NationMap_emplace(&countries, "Sweden", 0).ref->second += 20; 70 | NationMap_emplace(&countries, "Norway", 0).ref->second += 20; 71 | NationMap_emplace(&countries, "Finland", 0).ref->second += 20; 72 | 73 | for (c_each_kv(country, health, NationMap, countries)) 74 | printf("%s: %d\n", cstr_str(country), *health); 75 | puts(""); 76 | NationMap_drop(&countries); 77 | 78 | // CVEC PAIR 79 | 80 | vec_ip pairs1 = c_make(vec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); 81 | vec_ip_sort(&pairs1); 82 | 83 | for (c_each(i, vec_ip, pairs1)) 84 | printf("(%d %d) ", i.ref->x, i.ref->y); 85 | puts(""); 86 | vec_ip_drop(&pairs1); 87 | 88 | // CLIST PAIR 89 | 90 | list_ip pairs2 = c_make(list_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); 91 | list_ip_sort(&pairs2); 92 | 93 | for (c_each(i, list_ip, pairs2)) 94 | printf("(%d %d) ", i.ref->x, i.ref->y); 95 | puts(""); 96 | list_ip_drop(&pairs2); 97 | } 98 | -------------------------------------------------------------------------------- /examples/mixed/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'astar', 3 | 'complex', 4 | 'convert', 5 | 'demos', 6 | 'inits', 7 | 'read', 8 | ] 9 | test( 10 | sample, 11 | executable( 12 | sample, 13 | files(f'@sample@.c'), 14 | dependencies: example_deps, 15 | install: false, 16 | ), 17 | ) 18 | endforeach 19 | -------------------------------------------------------------------------------- /examples/mixed/read.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define i_keypro cstr 5 | #include 6 | 7 | vec_cstr read_file(const char* name) 8 | { 9 | vec_cstr vec = {0}; 10 | c_with (FILE* f = fopen(name, "r"), f != NULL, fclose(f)) 11 | c_with (cstr line = {0}, cstr_drop(&line)) 12 | while (cstr_getline(&line, f)) 13 | vec_cstr_push(&vec, cstr_clone(line)); 14 | return vec; 15 | } 16 | 17 | int main(void) 18 | { 19 | int n = 0; 20 | c_with (vec_cstr vec = read_file(__FILE__), vec_cstr_drop(&vec)) 21 | for (c_each(i, vec_cstr, vec)) 22 | printf("%5d: %s\n", ++n, cstr_str(i.ref)); 23 | 24 | if (errno) 25 | printf("error: read_file(" __FILE__ "). errno: %d\n", errno); 26 | } 27 | -------------------------------------------------------------------------------- /examples/priorityqueues/functor.c: -------------------------------------------------------------------------------- 1 | // Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue 2 | // Example of per-instance less-function on a single priority queue type 3 | // 4 | 5 | #include 6 | 7 | #define T IPQueue, int 8 | #define i_aux { bool(*less)(const int*, const int*); } 9 | #define i_less(x, y) self->aux.less(x, y) 10 | #include 11 | 12 | void print_queue(const char* name, IPQueue q) { 13 | // Make a clone, because there is no way to traverse 14 | // priority queues ordered without erasing the queue. 15 | 16 | // NB! A clone function for the extended container struct is provided. 17 | // It assumes that the extended member(s) are POD/trivial type(s). 18 | IPQueue copy = IPQueue_clone(q); 19 | printf("%s: \t", name); 20 | while (!IPQueue_is_empty(©)) { 21 | printf("%d ", IPQueue_pull(©)); 22 | } 23 | puts(""); 24 | 25 | IPQueue_drop(©); 26 | } 27 | 28 | static bool int_less(const int* x, const int* y) { return *x < *y; } 29 | static bool int_greater(const int* x, const int* y) { return *x > *y; } 30 | static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); } 31 | 32 | int main(void) 33 | { 34 | const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_countof(data); 35 | printf("data: \t"); 36 | for (c_range(i, n)) printf("%d ", data[i]); 37 | puts(""); 38 | 39 | // Max priority queue 40 | IPQueue q1 = {.aux={.less=int_less}}; 41 | IPQueue_put_n(&q1, data, n); 42 | print_queue("q1", q1); 43 | 44 | // Min priority queue 45 | IPQueue minq1 = {.aux={.less=int_greater}}; 46 | IPQueue_put_n(&minq1, data, n); 47 | print_queue("minq1", minq1); 48 | 49 | // Using lambda to compare elements. 50 | IPQueue q5 = {.aux={.less=int_lambda}}; 51 | IPQueue_put_n(&q5, data, n); 52 | print_queue("q5", q5); 53 | 54 | c_drop(IPQueue, &q1, &minq1, &q5); 55 | } 56 | -------------------------------------------------------------------------------- /examples/priorityqueues/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'functor', 3 | 'new_pqueue', 4 | 'priority', 5 | ] 6 | test( 7 | sample, 8 | executable( 9 | sample, 10 | files(f'@sample@.c'), 11 | dependencies: example_deps, 12 | install: false, 13 | ), 14 | suite: 'pqueue', 15 | ) 16 | endforeach 17 | -------------------------------------------------------------------------------- /examples/priorityqueues/new_pqueue.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct Point { int x, y; } Point; 4 | 5 | #define T PointQ, Point 6 | #define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) 7 | #include 8 | 9 | 10 | int main(void) 11 | { 12 | PointQ pqueue = c_make(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}}); 13 | // print 14 | for (; !PointQ_is_empty(&pqueue); PointQ_pop(&pqueue)) 15 | { 16 | const Point *v = PointQ_top(&pqueue); 17 | printf(" (%d,%d)", v->x, v->y); 18 | } 19 | puts(""); 20 | PointQ_drop(&pqueue); 21 | } 22 | -------------------------------------------------------------------------------- /examples/priorityqueues/priority.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #define T PQueue, int 7 | #define i_cmp -c_default_cmp // min-heap (increasing values) 8 | #include 9 | 10 | int main(void) { 11 | int N = 10000000; 12 | crand64 rng = crand64_from((uint64_t)time(NULL)); 13 | PQueue heap = {0}; 14 | 15 | // Push ten million random numbers to priority queue 16 | printf("Push %d numbers\n", N); 17 | for (c_range(N)) 18 | PQueue_push(&heap, crand64_uint_r(&rng, 1) & ((1<<20) - 1)); 19 | 20 | // push some negative numbers too. 21 | for (c_items(i, int, {-231, -32, -873, -4, -343})) 22 | PQueue_push(&heap, *i.ref); 23 | 24 | for (c_range(N)) 25 | PQueue_push(&heap, crand64_uint_r(&rng, 1) & ((1<<20) - 1)); 26 | 27 | puts("Extract the hundred smallest."); 28 | for (c_range(100)) { 29 | printf("%d ", PQueue_pull(&heap)); 30 | } 31 | 32 | PQueue_drop(&heap); 33 | } 34 | -------------------------------------------------------------------------------- /examples/queues/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'new_queue', 3 | 'queue', 4 | ] 5 | test( 6 | sample, 7 | executable( 8 | sample, 9 | files(f'@sample@.c'), 10 | dependencies: example_deps, 11 | install: false, 12 | ), 13 | suite: 'queue', 14 | ) 15 | endforeach 16 | -------------------------------------------------------------------------------- /examples/queues/new_queue.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | declare_queue(queue_pnt, struct Point); 6 | 7 | typedef struct Point { int x, y; } Point; 8 | #define T queue_pnt, Point 9 | #define i_declared 10 | #include 11 | 12 | #define T IntQ, int 13 | #include 14 | 15 | int main(void) { 16 | int n = 50000000; 17 | crand64 rng = crand64_from((uint64_t)time(NULL)); 18 | 19 | IntQ Q = {0}; 20 | 21 | // Push 50'000'000 random numbers onto the queue. 22 | for (c_range(n)) 23 | IntQ_push(&Q, crand64_uint_r(&rng, 1) & ((1<<24) - 1)); 24 | 25 | // Push or pop on the queue 50 million times 26 | printf("befor: size %" c_ZI ", capacity %" c_ZI "\n", IntQ_size(&Q), IntQ_capacity(&Q)); 27 | 28 | for (c_range(n)) { 29 | int r = crand64_uint_r(&rng, 1) & ((1<<24) - 1); 30 | if (r & 3) 31 | IntQ_push(&Q, r); 32 | else 33 | IntQ_pop(&Q); 34 | } 35 | 36 | printf("after: size %" c_ZI ", capacity %" c_ZI "\n", IntQ_size(&Q), IntQ_capacity(&Q)); 37 | IntQ_drop(&Q); 38 | } 39 | -------------------------------------------------------------------------------- /examples/queues/queue.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define T queue_i, int 5 | #include 6 | 7 | int main(void) { 8 | int n = 1000000; 9 | crand64_seed(1234); 10 | 11 | queue_i queue = {0}; 12 | 13 | // Push ten million random numbers onto the queue. 14 | for (c_range(n)) 15 | queue_i_push(&queue, crand64_uint() & ((1 << 20) - 1)); 16 | 17 | // Push or pop on the queue ten million times 18 | printf("%d\n", n); 19 | for (c_range(n)) { // forrange uses initial n only. 20 | int r = (int)crand64_uint() & ((1 << 20) - 1); 21 | if (r & 1) 22 | ++n, queue_i_push(&queue, r); 23 | else 24 | --n, queue_i_pop(&queue); 25 | } 26 | printf("%d, %" c_ZI "\n", n, queue_i_size(&queue)); 27 | 28 | queue_i_drop(&queue); 29 | } 30 | -------------------------------------------------------------------------------- /examples/regularexpressions/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'regex1', 3 | 'regex2', 4 | 'regex_match', 5 | 'regex_replace', 6 | ] 7 | test( 8 | sample, 9 | executable( 10 | sample, 11 | files(f'@sample@.c'), 12 | dependencies: example_deps, 13 | install: false, 14 | ), 15 | suite: 'cregex', 16 | ) 17 | endforeach 18 | -------------------------------------------------------------------------------- /examples/regularexpressions/regex1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) 5 | { 6 | (void)argv; 7 | if (argc <= 1) { 8 | printf("Usage: regex1 -i\n"); 9 | return 0; 10 | } 11 | cstr input = {0}; 12 | cregex float_expr = {0}; 13 | 14 | int res = cregex_compile(&float_expr, "^[+-]?[0-9]+((\\.[0-9]*)?|\\.[0-9]+)$"); 15 | // Until "q" is given, ask for another number 16 | if (res > 0) while (true) 17 | { 18 | printf("Enter a double precision number (q for quit): "); 19 | cstr_getline(&input, stdin); 20 | 21 | // Exit when the user inputs q 22 | if (cstr_equals(&input, "q")) 23 | break; 24 | 25 | if (cregex_is_match(&float_expr, cstr_str(&input))) 26 | printf("Input is a float\n"); 27 | else 28 | printf("Invalid input : Not a float\n"); 29 | } 30 | 31 | cstr_drop(&input); 32 | cregex_drop(&float_expr); 33 | } 34 | -------------------------------------------------------------------------------- /examples/regularexpressions/regex2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | struct { const char *pattern, *input; } s[] = { 7 | {"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])", 8 | "date: 2024-02-29 leapyear day, christmas eve is on 2022-12-24." 9 | }, 10 | {"(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?", 11 | "https://en.cppreference.com/w/cpp/regex/regex_search" 12 | }, 13 | {"!((abc|123)+)!", "!123abcabc!"}, 14 | {"(\\p{Alpha}+ )+(\\p{Nd}+)", "Großpackung süßigkeiten 199"}, 15 | {"\\p{Han}+", "This is Han: 王明:那是杂志吗?"}, 16 | }; 17 | 18 | cregex re = {0}; 19 | for (c_range(i, c_countof(s))) 20 | { 21 | int res = cregex_compile(&re, s[i].pattern); 22 | if (res < 0) { 23 | printf("error in regex pattern: %d\n", res); 24 | continue; 25 | } 26 | printf("\ninput: %s\n", s[i].input); 27 | 28 | for (c_match(j, &re, s[i].input)) { 29 | for (c_range(k, cregex_captures(&re) + 1)) 30 | printf(" submatch %d: " c_svfmt "\n", (int)k, c_svarg(j.match[k])); 31 | } 32 | } 33 | cregex_drop(&re); 34 | } 35 | -------------------------------------------------------------------------------- /examples/regularexpressions/regex_match.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define T Fvec, float 6 | #include 7 | 8 | int main(void) 9 | { 10 | // Lets find the first sequence of digits in a string 11 | const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour. " 12 | "Around 365.25 days a year, and 52 weeks in a year. " 13 | "Boltzmann const: 1.38064852E-23, is very small. " 14 | "Bohrradius is 5.29177210903e-11, and Avogadros number is 6.02214076e23."; 15 | cregex re = {0}; 16 | Fvec vec = {0}; 17 | 18 | const char* num_pattern = "[+-]?([0-9]*\\.)?\\d+([Ee][+-]?\\d+)?"; 19 | int res = cregex_compile(&re, num_pattern); 20 | printf("%d: %s\n", res, num_pattern); 21 | 22 | // extract and convert all numbers in str to floats 23 | for (c_match(i, &re, str)) 24 | Fvec_push(&vec, (float)atof(i.match[0].buf)); 25 | 26 | for (c_each(i, Fvec, vec)) 27 | printf(" %g\n", (double)*i.ref); 28 | 29 | // extracts the numbers only to a comma separated string. 30 | cstr nums = cregex_replace_pro(&re, csview_from(str), " $0,", 31 | INT32_MAX, NULL, CREG_STRIP); 32 | printf("\n%s\n", cstr_str(&nums)); 33 | 34 | cstr_drop(&nums); 35 | cregex_drop(&re); 36 | Fvec_drop(&vec); 37 | } 38 | -------------------------------------------------------------------------------- /examples/regularexpressions/regex_replace.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool add_10_years(int group, csview match, cstr* out) { 6 | if (group == 1) { // year match 7 | int year; 8 | sscanf(match.buf, "%4d", &year); // scan 4 chars only 9 | cstr_printf(out, "%04d", year + 10); 10 | return true; 11 | } 12 | return false; 13 | } 14 | 15 | int main(void) 16 | { 17 | const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b"; 18 | const char* input = "start date: 2015-12-31, end date: 2022-02-28"; 19 | 20 | cstr str = {0}; 21 | cregex re = {0}; 22 | c_defer( 23 | cregex_drop(&re), 24 | cstr_drop(&str) 25 | ){ 26 | printf("INPUT: %s\n", input); 27 | 28 | /* replace with a fixed string, extended all-in-one call: */ 29 | cstr_take(&str, cregex_replace_aio(pattern, input, "YYYY-MM-DD")); 30 | printf("fixed: %s\n", cstr_str(&str)); 31 | 32 | /* US date format, and add 10 years to dates: */ 33 | cstr_take(&str, cregex_replace_aio_pro(pattern, csview_from(input), "$1/$3/$2", 34 | INT32_MAX, add_10_years, CREG_DEFAULT)); 35 | printf("us+10: %s\n", cstr_str(&str)); 36 | 37 | /* Wrap first date inside []: */ 38 | cstr_take(&str, cregex_replace_aio(pattern, input, "[$0]")); 39 | printf("brack: %s\n", cstr_str(&str)); 40 | 41 | /* Shows how to compile RE separately */ 42 | re = cregex_from(pattern); 43 | if (cregex_captures(&re) == 0) 44 | continue; /* break c_defer */ 45 | 46 | /* European date format. */ 47 | cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); 48 | printf("euros: %s\n", cstr_str(&str)); 49 | 50 | /* Strip out everything but the matches */ 51 | cstr_take(&str, cregex_replace_pro(&re, csview_from(input), "$3.$2.$1;", 52 | INT32_MAX, NULL, CREG_STRIP)); 53 | printf("strip: %s\n", cstr_str(&str)); 54 | 55 | /* Wrap all words in ${} */ 56 | cstr_take(&str, cregex_replace_aio("[a-z]+", "52 apples and 31 mangoes", "$${$0}")); 57 | printf("curly: %s\n", cstr_str(&str)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/smartpointers/arc_containers.c: -------------------------------------------------------------------------------- 1 | // Create a vec and a list of shared pointers to maps, 2 | // and demonstrate sharing and cloning of maps. 3 | #include 4 | #define T Map, cstr, int, (c_keypro) 5 | #define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p)) 6 | #include 7 | 8 | #define T Arc, Map, (c_no_atomic) // non-atomic ref. counted Map 9 | #define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) 10 | #include 11 | 12 | #define T Vec, Arc, (c_keypro) // arc is a "pro" type 13 | #include 14 | 15 | #define T List, Arc, (c_keypro) 16 | #include 17 | 18 | int main(void) 19 | { 20 | c_with (Vec vec = {0}, Vec_drop(&vec)) 21 | c_with (List list = {0}, List_drop(&list)) 22 | { 23 | // POPULATE vec with shared pointers to Maps: 24 | Map *map; 25 | //map = Vec_push(&vec, Arc_from(Map_init()))->get; 26 | map = Vec_emplace(&vec, Map_init())->get; 27 | Map_emplace(map, "Joey", 1990); 28 | Map_emplace(map, "Mary", 1995); 29 | Map_emplace(map, "Joanna", 1992); 30 | 31 | //map = Vec_push(&vec, Arc_from(Map_init()))->get; 32 | map = Vec_emplace(&vec, Map_init())->get; 33 | Map_emplace(map, "Rosanna", 2001); 34 | Map_emplace(map, "Brad", 1999); 35 | Map_emplace(map, "Jack", 1980); 36 | 37 | // POPULATE list: 38 | //map = List_push_back(&list, Arc_from(Map_init()))->get; 39 | map = List_emplace_back(&list, Map_init())->get; 40 | Map_emplace(map, "Steve", 1979); 41 | Map_emplace(map, "Rick", 1974); 42 | Map_emplace(map, "Tracy", 2003); 43 | 44 | // Share two Maps from the vec with the list using emplace (clone the arc): 45 | List_push_back(&list, Arc_clone(vec.data[0])); 46 | List_push_back(&list, Arc_clone(vec.data[1])); 47 | 48 | // Clone (deep copy) a Map from the vec to the list 49 | // List will contain two shared and two unshared maps. 50 | map = List_push_back(&list, Arc_from(Map_clone(*vec.data[1].get)))->get; 51 | 52 | // Add one more element to the cloned map: 53 | Map_emplace_or_assign(map, "CLONED", 2021); 54 | 55 | // Add one more element to the shared map: 56 | Map_emplace_or_assign(vec.data[1].get, "SHARED", 2021); 57 | 58 | puts("VEC"); 59 | for (c_each(i, Vec, vec)) { 60 | for (c_each_kv(name, year, Map, *i.ref->get)) 61 | printf(" %s:%d", cstr_str(name), *year); 62 | puts(""); 63 | } 64 | 65 | puts("LIST"); 66 | for (c_each(i, List, list)) { 67 | for (c_each_kv(name, year, Map, *i.ref->get)) 68 | printf(" %s:%d", cstr_str(name), *year); 69 | puts(""); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /examples/smartpointers/arc_demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void int_drop(int* x) { 5 | printf("drop: %d\n", *x); 6 | } 7 | 8 | // arc implements its own clone method using reference counting, 9 | // so 'i_keyclone' is not required to be defined (ignored). 10 | 11 | // Define the Arc, no need for atomic in single thread, enable default int comparisons. 12 | #define T Arc, int, (c_no_atomic| c_use_cmp) 13 | #define i_keydrop int_drop // optional, just to display the elements destroyed 14 | #include // Arc 15 | 16 | #define T Arcset, Arc, (c_keypro) // arc's are "pro" types 17 | #include // Arcset (like: std::set>) 18 | 19 | #define T Arcvec, Arc, (c_keypro| c_use_cmp) 20 | #include // Arcvec (like: std::vector>) 21 | 22 | int main(void) 23 | { 24 | const int years[] = {2021, 2012, 2022, 2015}; 25 | 26 | Arcvec vec = {0}; 27 | for (c_range(i, c_countof(years))) { 28 | Arcvec_emplace(&vec, years[i]); 29 | // Arcvec_push(&vec, Arc_from(years[i])); // alt. 30 | } 31 | 32 | Arcvec_sort(&vec); 33 | 34 | printf("vec:"); 35 | for (c_each(i, Arcvec, vec)) 36 | printf(" %d", *i.ref->get); 37 | puts(""); 38 | 39 | // add odd numbers from vec to set 40 | Arcset set = {0}; 41 | for (c_each(i, Arcvec, vec)) 42 | if (*i.ref->get & 1) 43 | Arcset_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter. 44 | 45 | // erase the two last elements in vec 46 | Arcvec_pop_back(&vec); 47 | Arcvec_pop_back(&vec); 48 | 49 | printf("vec:"); 50 | for (c_each(i, Arcvec, vec)) printf(" %d", *i.ref->get); 51 | 52 | printf("\nset:"); 53 | for (c_each(i, Arcset, set)) printf(" %d", *i.ref->get); 54 | 55 | Arc p = Arc_clone(vec.data[0]); 56 | printf("\n%d is now owned by %ld objects\n", *p.get, Arc_use_count(p)); 57 | 58 | Arc_drop(&p); 59 | Arcvec_drop(&vec); 60 | Arcset_drop(&set); 61 | } 62 | -------------------------------------------------------------------------------- /examples/smartpointers/arcvec_erase.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void show_drop(int* x) { printf("drop: %d\n", *x); } 4 | 5 | 6 | // enable sort/search for non-atomic Arc int type 7 | #define T Arc, int, (c_no_atomic | c_use_cmp) 8 | #define i_keydrop show_drop 9 | #include // Shared pointer to int 10 | 11 | // arc is "pro", enable search/sort 12 | #define T Vec, Arc, (c_keypro | c_use_cmp) 13 | #include // Vec: vec 14 | 15 | 16 | int main(void) 17 | { 18 | Vec vec = c_make(Vec, {2012, 1990, 2012, 2019, 2015}); 19 | printf("elm size: %d\n", (int)sizeof(Arc)); 20 | 21 | // clone the second 2012 and push it back. 22 | // note: cloning make sure that vec.data[2] has ref count 2. 23 | Vec_push(&vec, Arc_clone(vec.data[2])); // => share vec.data[2] 24 | Vec_emplace(&vec, *vec.data[2].get); // => deep-copy vec.data[2] 25 | 26 | printf("vec before erase :"); 27 | for (c_each(i, Vec, vec)) 28 | printf(" %d", *i.ref->get); 29 | 30 | printf("\nerase vec.data[2]; or first matching value depending on compare.\n"); 31 | Vec_iter it; 32 | it = Vec_find(&vec, *vec.data[2].get); 33 | if (it.ref) 34 | Vec_erase_at(&vec, it); 35 | 36 | int year = 2015; 37 | it = Vec_find(&vec, year); // Ok as tmp only. 38 | if (it.ref) 39 | Vec_erase_at(&vec, it); 40 | 41 | printf("vec after erase :"); 42 | for (c_each(i, Vec, vec)) 43 | printf(" %d", *i.ref->get); 44 | 45 | Vec_sort(&vec); 46 | printf("\nvec after sort :"); 47 | for (c_each(i, Vec, vec)) 48 | printf(" %d", *i.ref->get); 49 | 50 | puts("\nDone"); 51 | Vec_drop(&vec); 52 | } 53 | -------------------------------------------------------------------------------- /examples/smartpointers/box.c: -------------------------------------------------------------------------------- 1 | /* box: heap allocated boxed type */ 2 | #include 3 | 4 | typedef struct { cstr name, last; } Person; 5 | 6 | Person Person_make(const char* name, const char* last) { 7 | return c_literal(Person){.name = cstr_from(name), .last = cstr_from(last)}; 8 | } 9 | 10 | size_t Person_hash(const Person* a) { 11 | return cstr_hash(&a->name) ^ cstr_hash(&a->last); 12 | } 13 | 14 | int Person_cmp(const Person* a, const Person* b) { 15 | int c = cstr_cmp(&a->name, &b->name); 16 | return c ? c : cstr_cmp(&a->last, &b->last); 17 | } 18 | 19 | Person Person_clone(Person p) { 20 | p.name = cstr_clone(p.name); 21 | p.last = cstr_clone(p.last); 22 | return p; 23 | } 24 | 25 | void Person_drop(Person* p) { 26 | printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); 27 | c_drop(cstr, &p->name, &p->last); 28 | } 29 | 30 | // "class" binds _clone, _drop functions. 31 | // "use_cmp" binds _cmp, _hash functions. 32 | #define T PBox, Person, (c_keyclass | c_use_cmp) 33 | #include 34 | 35 | // box, arc, and cstr types are "pro"-types. 36 | #define T Persons, PBox, (c_keypro) 37 | #include 38 | 39 | int main(void) 40 | { 41 | Persons vec = {0}; 42 | PBox p = PBox_from(Person_make("Laura", "Palmer")); 43 | PBox q = PBox_clone(p); 44 | cstr_assign(&q.get->name, "Leland"); 45 | 46 | printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); 47 | printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); 48 | 49 | Persons_emplace(&vec, Person_make("Dale", "Cooper")); 50 | Persons_emplace(&vec, Person_make("Audrey", "Home")); 51 | 52 | // NB! Clone/share p and q in the Persons container. 53 | Persons_push(&vec, PBox_clone(p)); 54 | Persons_push(&vec, PBox_clone(q)); 55 | 56 | for (c_each(i, Persons, vec)) 57 | printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); 58 | puts(""); 59 | 60 | // Look-up Audrey! Create a temporary Person for lookup. 61 | Person a = Person_make("Audrey", "Home"); 62 | const PBox *v = Persons_get(&vec, a); // lookup 63 | if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); 64 | 65 | Person_drop(&a); 66 | PBox_drop(&p); 67 | PBox_drop(&q); 68 | Persons_drop(&vec); 69 | } 70 | -------------------------------------------------------------------------------- /examples/smartpointers/box2.c: -------------------------------------------------------------------------------- 1 | // example: https://doc.rust-lang.org/rust-by-example/std/box.html 2 | #include 3 | 4 | typedef struct { 5 | double x; 6 | double y; 7 | } Point; 8 | 9 | // A Rectangle can be specified by where its top left and bottom right 10 | // corners are in space 11 | typedef struct { 12 | Point top_left; 13 | Point bottom_right; 14 | } Rectangle; 15 | 16 | #define T BoxPoint, Point 17 | #include 18 | 19 | #define T BoxRect, Rectangle 20 | #include 21 | 22 | // Box in box: (box is a "pro" key-type) 23 | #define T BoxBoxPoint, BoxPoint, (c_keypro) 24 | #include 25 | 26 | Point origin(void) { 27 | return c_literal(Point){ .x=1.0, .y=2.0 }; 28 | } 29 | 30 | BoxPoint boxed_origin(void) { 31 | // Allocate this point on the heap, and return a pointer to it 32 | return BoxPoint_from(c_literal(Point){ .x=1.0, .y=2.0 }); 33 | } 34 | 35 | 36 | int main(void) { 37 | // Stack allocated variables 38 | Point point = origin(); 39 | Rectangle rectangle = { 40 | .top_left = origin(), 41 | .bottom_right = { .x=3.0, .y=-4.0 } 42 | }; 43 | 44 | // Heap allocated rectangle 45 | BoxRect boxed_rectangle = BoxRect_from(c_literal(Rectangle){ 46 | .top_left = origin(), 47 | .bottom_right = { .x=3.0, .y=-4.0 } 48 | }); 49 | // The output of functions can be boxed 50 | BoxPoint boxed_point = BoxPoint_from(origin()); 51 | 52 | // Create BoxBoxPoint from either a Point or a BoxPoint: 53 | BoxBoxPoint box_in_a_box = BoxBoxPoint_from(origin()); 54 | 55 | c_defer( 56 | BoxBoxPoint_drop(&box_in_a_box), 57 | BoxPoint_drop(&boxed_point), 58 | BoxRect_drop(&boxed_rectangle) 59 | ){ 60 | printf("box_in_a_box: x = %g\n", BoxBoxPoint_toraw(&box_in_a_box).x); 61 | 62 | printf("Point occupies %d bytes on the stack\n", 63 | (int)sizeof(point)); 64 | printf("Rectangle occupies %d bytes on the stack\n", 65 | (int)sizeof(rectangle)); 66 | 67 | // box size == pointer size 68 | printf("Boxed point occupies %d bytes on the stack\n", 69 | (int)sizeof(boxed_point)); 70 | printf("Boxed rectangle occupies %d bytes on the stack\n", 71 | (int)sizeof(boxed_rectangle)); 72 | printf("Boxed box occupies %d bytes on the stack\n", 73 | (int)sizeof(box_in_a_box)); 74 | 75 | // Copy the data contained in `boxed_point` into `unboxed_point` 76 | Point unboxed_point = *boxed_point.get; 77 | printf("Unboxed point occupies %d bytes on the stack\n", 78 | (int)sizeof(unboxed_point)); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/smartpointers/map_box.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define T IBox, long 6 | #include // unique_ptr alike. 7 | 8 | // hashmap of cstr => IBox (both cstr and box are "pro") 9 | #define T Boxmap, cstr, IBox, (c_keypro | c_valpro) 10 | #include 11 | 12 | 13 | int main(void) 14 | { 15 | Boxmap map = {0}; 16 | 17 | puts("Map cstr => IBox:"); 18 | Boxmap_insert(&map, cstr_lit("Test1"), IBox_make(1)); 19 | Boxmap_insert(&map, cstr_lit("Test2"), IBox_make(2)); 20 | 21 | // Simpler: emplace() implicitly creates cstr from const char* and IBox from long! 22 | Boxmap_emplace(&map, "Test3", 3); 23 | Boxmap_emplace(&map, "Test4", 4); 24 | 25 | for (c_each_kv(name, number, Boxmap, map)) 26 | printf("%s: %ld\n", cstr_str(name), *number->get); 27 | puts(""); 28 | 29 | Boxmap_drop(&map); 30 | } 31 | -------------------------------------------------------------------------------- /examples/smartpointers/map_ptr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // box 5 | #define T boxlong, long //, (c_use_cmp) // add if compare is needed 6 | #include 7 | 8 | // hashmap 9 | #define T Magicmap, cstr, boxlong, (c_keypro | c_valpro) 10 | #include 11 | 12 | int main(void) 13 | { 14 | // c_make() and emplace() implicitly creates cstr from const char* 15 | // and a "boxed long" from long. 16 | Magicmap map = c_make(Magicmap, { 17 | {"just", 10}, 18 | {"some", 20}, 19 | {"random", 30}, 20 | {"words", 40}, 21 | }); 22 | Magicmap_emplace(&map, "another", 100); 23 | 24 | printf("Lookup \"some\": %ld\n\n", *Magicmap_at(&map, "some")->get); 25 | 26 | for (c_each_kv(name, num, Magicmap, map)) { 27 | printf("%s: %ld\n", cstr_str(name), *num->get); 28 | } 29 | 30 | Magicmap_drop(&map); 31 | } 32 | -------------------------------------------------------------------------------- /examples/smartpointers/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'arc_containers', 3 | 'arc_demo', 4 | 'arcvec_erase', 5 | 'box2', 6 | 'box', 7 | 'map_box', 8 | 'map_ptr', 9 | 'music_arc', 10 | 'person_arc', 11 | ] 12 | test( 13 | sample, 14 | executable( 15 | sample, 16 | files(f'@sample@.c'), 17 | dependencies: example_deps, install: false, 18 | ), 19 | suite: 'arc', 20 | ) 21 | endforeach 22 | -------------------------------------------------------------------------------- /examples/smartpointers/music_arc.c: -------------------------------------------------------------------------------- 1 | // shared_ptr-examples.cpp 2 | // based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 3 | 4 | // Advanced example. 5 | 6 | #include 7 | #include 8 | 9 | typedef struct { 10 | cstr artist; 11 | cstr title; 12 | } Song; 13 | 14 | // Make Song a "class" by defining _clone and _drop "members": 15 | Song Song_init(const char* artist, const char* title) 16 | { return (Song){cstr_from(artist), cstr_from(title)}; } 17 | 18 | Song Song_clone(Song s) { 19 | s.artist = cstr_clone(s.artist); 20 | s.title = cstr_clone(s.title); 21 | return s; 22 | } 23 | 24 | void Song_drop(Song* self) { 25 | printf("drop: %s\n", cstr_str(&self->title)); 26 | c_drop(cstr, &self->artist, &self->title); 27 | } 28 | 29 | // Define a keyraw conversion type, SongView: 30 | typedef struct { 31 | const char* artist; 32 | const char* title; 33 | } SongView; 34 | 35 | inline static bool SongView_cmp(const SongView* xw, const SongView* yw) 36 | { int c = strcmp(xw->artist, yw->artist); return c ? c : strcmp(xw->title, yw->title); } 37 | 38 | inline static size_t SongView_hash(const SongView* xw) 39 | { return c_hash_mix(c_hash_str(xw->artist), c_hash_str(xw->title)); } 40 | 41 | 42 | // Define the shared pointer type SongArc and conversion functions to SongView: 43 | // "keyclass" binds Song_clone(), Song_drop() 44 | // "cmpclass" specifies the type/view to convert to/from and binds _cmp, _eq, _hash functions. 45 | #define T SongArc, Song, (c_keyclass | c_use_cmp) // also enable _cmp/_hash for arc cmpclass (SongView). 46 | #define i_cmpclass SongView 47 | #define i_keytoraw(x) ((SongView){.artist=cstr_str(&x->artist), .title=cstr_str(&x->title)}) 48 | #define i_keyfrom(sw) ((Song){.artist=cstr_from(sw.artist), .title=cstr_from(sw.title)}) 49 | #include 50 | 51 | // Create a set of SongArc 52 | #define T SongSet, SongArc, (c_keypro) // arc-type is "pro" 53 | #include 54 | 55 | void example3(void) 56 | { 57 | SongSet set1 = c_make(SongSet, { 58 | (SongView){"Bob Dylan", "The Times They Are A Changing"}, 59 | (SongView){"Aretha Franklin", "Bridge Over Troubled Water"}, 60 | (SongView){"Thalia", "Entre El Mar y Una Estrella"}, 61 | }); 62 | 63 | SongSet set2 = {0}; 64 | // Share all entries in set1 with set2. Copy arc => share. 65 | c_copy_to(SongSet, &set2, set1); 66 | 67 | // Add a few more SongArcs to set2. 68 | SongSet_emplace(&set2, (SongView){"Bob Dylan", "The Times They Are A Changing"}); 69 | SongSet_emplace(&set2, (SongView){"Michael Jackson", "Billie Jean"}); 70 | 71 | // The previous line is identical to: 72 | // SongSet_insert(&set2, SongArc_make((Song){cstr_lit("Michael Jackson"), cstr_lit("Billie Jean")})); 73 | 74 | // We now have two sets with some shared, some unique entries. 75 | // Remove "Thalia" from set1. Song is not destroyed, there is still one reference in set2: 76 | SongSet_erase(&set1, (SongView){"Thalia", "Entre El Mar y Una Estrella"}); 77 | 78 | int n = 0; 79 | for (c_items(i, SongSet, {set1, set2})) { 80 | printf("SET%d:\n", ++n); 81 | for (c_each(s, SongSet, *i.ref)) 82 | printf(" %s (%s), REFS: %ld\n", cstr_str(&s.ref->get->title), 83 | cstr_str(&s.ref->get->artist), 84 | SongArc_use_count(*s.ref)); 85 | } 86 | const SongArc* found = SongSet_get(&set2, (SongView){"Aretha Franklin", "Bridge Over Troubled Water"}); 87 | if (found) printf("FOUND: %s\n", cstr_str(&found->get->title)); 88 | 89 | c_drop(SongSet, &set1, &set2); 90 | } 91 | 92 | 93 | int main(void) 94 | { 95 | example3(); 96 | } 97 | -------------------------------------------------------------------------------- /examples/smartpointers/person_arc.c: -------------------------------------------------------------------------------- 1 | /* box example: heap allocated smart pointer type */ 2 | #include 3 | 4 | // ===== Person: create a "pro" type: 5 | typedef struct { cstr name, last; } Person; 6 | typedef struct { const char *name, *last; } Person_raw; 7 | 8 | Person Person_from(Person_raw raw) 9 | { return (Person){.name = cstr_from(raw.name), .last = cstr_from(raw.last)}; } 10 | 11 | Person_raw Person_toraw(Person* p) 12 | { return (Person_raw){.name = cstr_str(&p->name), .last = cstr_str(&p->last)}; } 13 | 14 | int Person_raw_cmp(const Person_raw* a, const Person_raw* b) { 15 | int c = strcmp(a->name, b->name); 16 | return c ? c : strcmp(a->last, b->last); 17 | } 18 | 19 | size_t Person_raw_hash(const Person_raw* a) 20 | { return c_hash_str(a->name) ^ c_hash_str(a->last); } 21 | 22 | Person Person_clone(Person p) { 23 | p.name = cstr_clone(p.name); 24 | p.last = cstr_clone(p.last); 25 | return p; 26 | } 27 | 28 | void Person_drop(Person* p) { 29 | printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); 30 | c_drop(cstr, &p->name, &p->last); 31 | } 32 | // ===== 33 | 34 | // binds Person_clone, Person_drop, enable search/sort 35 | // Person is a "pro" type (has Person_raw conversion type): 36 | #define T PersArc, Person, (c_keypro | c_use_cmp) 37 | #include 38 | 39 | // Arcs and Boxes are always "pro" types: 40 | #define T Persons, PersArc, (c_keypro | c_use_cmp) 41 | #include 42 | 43 | 44 | int main(void) 45 | { 46 | Persons vec = {0}; 47 | PersArc laura = PersArc_from((Person_raw){"Laura", "Palmer"}); 48 | PersArc bobby = PersArc_from((Person_raw){"Bobby", "Briggs"}); 49 | 50 | c_defer( 51 | PersArc_drop(&laura), 52 | PersArc_drop(&bobby), 53 | Persons_drop(&vec) 54 | ){ 55 | // Use Persons_emplace() to implicitly call PersArc_from() on the argument: 56 | Persons_emplace(&vec, (Person_raw){"Audrey", "Home"}); 57 | Persons_emplace(&vec, (Person_raw){"Dale", "Cooper"}); 58 | 59 | Persons_push(&vec, PersArc_clone(laura)); 60 | Persons_push(&vec, PersArc_clone(bobby)); 61 | 62 | for (c_each(i, Persons, vec)) { 63 | Person_raw p = Persons_value_toraw(i.ref); 64 | printf("%s %s (%d)\n", p.name, p.last, (int)PersArc_use_count(*i.ref)); 65 | } 66 | puts(""); 67 | 68 | // Look-up Audrey! 69 | const PersArc *a = Persons_find(&vec, (Person_raw){"Audrey", "Home"}).ref; 70 | if (a) { 71 | Person_raw p = Persons_value_toraw(a); // two-level unwrap! 72 | printf("found: %s %s\n", p.name, p.last); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/sortedmaps/gauss2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Declare int -> int sorted map. 7 | #define T SortedMap, int, int 8 | #include 9 | 10 | int main(void) 11 | { 12 | enum {N = 5000000}; 13 | uint64_t seed = (uint64_t)time(NULL); 14 | crand64_seed(seed); 15 | const double Mean = round(crand64_real()*98.0 - 49.0), 16 | StdDev = crand64_real()*10.0 + 1.0, 17 | Scale = 74.0; 18 | 19 | printf("Demo of gaussian / normal distribution of %d random samples\n", N); 20 | printf("Mean %f, StdDev %f\n", Mean, StdDev); 21 | 22 | // Setup random normal distribution. 23 | crand64_normal_dist d = {.mean=Mean, .stddev=StdDev}; 24 | 25 | // Create and init histogram map with defered destruct 26 | SortedMap hist = {0}; 27 | 28 | for (c_range(N)) { 29 | int index = (int)round(crand64_normal(&d)); 30 | SortedMap_insert(&hist, index, 0).ref->second += 1; 31 | } 32 | 33 | // Print the gaussian bar chart 34 | for (c_each_kv(index, count, SortedMap, hist)) { 35 | int n = (int)round(2.5 * Scale * StdDev * (*count) / (isize)N); 36 | if (n > 0) { 37 | printf("%4d ", *index); 38 | while (n--) printf("*"); 39 | puts(""); 40 | } 41 | } 42 | SortedMap_drop(&hist); 43 | } 44 | -------------------------------------------------------------------------------- /examples/sortedmaps/listmap.c: -------------------------------------------------------------------------------- 1 | // This implements the multimap c++ example found at: 2 | // https://en.cppreference.com/w/cpp/container/multimap/insert 3 | 4 | // Multimap entries 5 | #include 6 | #define i_keypro cstr 7 | #include 8 | 9 | // Map of int => list_cstr. 10 | // "valclass" bind list_cstr_clone() and list_cstr_drop() 11 | #define T Multimap, int, list_cstr, (c_valclass) 12 | #define i_cmp -c_default_cmp // like std::greater 13 | #include 14 | 15 | void print(const char* lbl, const Multimap mmap) 16 | { 17 | printf("%s ", lbl); 18 | for (c_each(e, Multimap, mmap)) { 19 | for (c_each(s, list_cstr, e.ref->second)) 20 | printf("{%d,%s} ", e.ref->first, cstr_str(s.ref)); 21 | } 22 | puts(""); 23 | } 24 | 25 | void insert(Multimap* mmap, int key, const char* str) 26 | { 27 | list_cstr *list = &Multimap_insert(mmap, key, list_cstr_init()).ref->second; 28 | list_cstr_emplace_back(list, str); 29 | } 30 | 31 | int main(void) 32 | { 33 | Multimap mmap = {0}; 34 | 35 | // list-initialize 36 | struct pair {int a; const char* b;}; 37 | for (c_items(i, struct pair, {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}})) 38 | insert(&mmap, i.ref->a, i.ref->b); 39 | print("#1", mmap); 40 | 41 | // insert using value_type 42 | insert(&mmap, 5, "pqr"); 43 | print("#2", mmap); 44 | 45 | // insert using make_pair 46 | insert(&mmap, 6, "uvw"); 47 | print("#3", mmap); 48 | 49 | insert(&mmap, 7, "xyz"); 50 | print("#4", mmap); 51 | 52 | // insert using initialization_list 53 | for (c_items(i, struct pair, {{5, "one"}, {5, "two"}})) 54 | insert(&mmap, i.ref->a, i.ref->b); 55 | print("#5", mmap); 56 | 57 | // FOLLOWING NOT IN ORIGINAL EXAMPLE: 58 | // erase all entries with key 5 59 | Multimap_erase(&mmap, 5); 60 | print("+5", mmap); 61 | 62 | Multimap_drop(&mmap); 63 | } 64 | -------------------------------------------------------------------------------- /examples/sortedmaps/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'gauss2', 3 | 'listmap', 4 | 'multimap', 5 | 'new_smap', 6 | 'smap_erase', 7 | 'smap_find', 8 | 'smap_insert', 9 | 'sorted_map', 10 | 'sset_erase', 11 | ] 12 | test( 13 | sample, 14 | executable( 15 | sample, 16 | files(f'@sample@.c'), 17 | dependencies: example_deps, 18 | install: false, 19 | ), 20 | suite: 'hmap', 21 | ) 22 | endforeach 23 | -------------------------------------------------------------------------------- /examples/sortedmaps/new_smap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | declare_sortedmap(PntMap, struct Point, int); 5 | 6 | // Use forward declared PntMap in struct 7 | typedef struct { 8 | PntMap pntmap; 9 | cstr name; 10 | } MyStruct; 11 | 12 | // Point => int map 13 | typedef struct Point { int x, y; } Point; 14 | int Point_cmp(const Point* a, const Point* b) { 15 | int c = a->x - b->x; 16 | return c ? c : a->y - b->y; 17 | } 18 | 19 | #define T PntMap, Point, int, (c_cmpclass | c_declared) 20 | #include 21 | 22 | // cstr => cstr map 23 | #define T StrMap, cstr, cstr, (c_keypro | c_valpro) 24 | #include 25 | 26 | // cstr set 27 | #define T StrSet, cstr, (c_keypro) 28 | #include 29 | 30 | 31 | int main(void) 32 | { 33 | PntMap pmap = c_make(PntMap, { 34 | {{42, 14}, 1}, 35 | {{32, 94}, 2}, 36 | {{62, 81}, 3}, 37 | }); 38 | 39 | StrMap smap = c_make(StrMap, { 40 | {"Hello, friend", "this is the mapped value"}, 41 | {"The brown fox", "jumped"}, 42 | {"This is the time", "for all good things"}, 43 | }); 44 | 45 | for (c_each_kv(p, i, PntMap, pmap)) 46 | printf(" (%d,%d: %d)", p->x, p->y, *i); 47 | puts(""); 48 | 49 | for (c_each_kv(i, j, StrMap, smap)) 50 | printf(" (%s: %s)\n", cstr_str(i), cstr_str(j)); 51 | 52 | StrSet sset = {0}; 53 | StrSet_emplace(&sset, "Hello, friend"); 54 | StrSet_emplace(&sset, "Goodbye, foe"); 55 | printf("Found? %s\n", StrSet_contains(&sset, "Hello, friend") ? "true" : "false"); 56 | 57 | PntMap_drop(&pmap); 58 | StrMap_drop(&smap); 59 | StrSet_drop(&sset); 60 | } 61 | -------------------------------------------------------------------------------- /examples/sortedmaps/smap_erase.c: -------------------------------------------------------------------------------- 1 | // map_erase.c 2 | // From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16 3 | #include 4 | #include 5 | 6 | #define T mymap, int, cstr, (c_valpro) 7 | #include 8 | 9 | void printmap(mymap m) 10 | { 11 | for (c_each(elem, mymap, m)) 12 | printf(" [%d, %s]", elem.ref->first, cstr_str(&elem.ref->second)); 13 | printf("\nsize() == %" c_ZI "\n\n", mymap_size(&m)); 14 | } 15 | 16 | int main(void) 17 | { 18 | mymap m1 = {0}; 19 | 20 | // Fill in some data to test with, one at a time 21 | mymap_insert(&m1, 1, cstr_lit("A")); 22 | mymap_insert(&m1, 2, cstr_lit("B")); 23 | mymap_insert(&m1, 3, cstr_lit("C")); 24 | mymap_insert(&m1, 4, cstr_lit("D")); 25 | mymap_insert(&m1, 5, cstr_lit("E")); 26 | 27 | puts("Starting data of map m1 is:"); 28 | printmap(m1); 29 | // The 1st member function removes an element at a given position 30 | mymap_erase_at(&m1, mymap_advance(mymap_begin(&m1), 1)); 31 | puts("After the 2nd element is deleted, the map m1 is:"); 32 | printmap(m1); 33 | 34 | // Fill in some data to test with 35 | mymap m2 = c_make(mymap, { 36 | {10, "Bob"}, 37 | {11, "Rob"}, 38 | {12, "Robert"}, 39 | {13, "Bert"}, 40 | {14, "Bobby"}, 41 | }); 42 | 43 | puts("Starting data of map m2 is:"); 44 | printmap(m2); 45 | mymap_iter it1 = mymap_advance(mymap_begin(&m2), 1); 46 | mymap_iter it2 = mymap_find(&m2, mymap_back(&m2)->first); 47 | 48 | puts("to remove:"); 49 | for (c_each(i, mymap, it1, it2)) 50 | printf(" [%d, %s]", i.ref->first, cstr_str(&i.ref->second)); 51 | puts(""); 52 | // The 2nd member function removes elements 53 | // in the range [First, Last) 54 | mymap_erase_range(&m2, it1, it2); 55 | puts("After the middle elements are deleted, the map m2 is:"); 56 | printmap(m2); 57 | 58 | mymap m3 = {0}; 59 | 60 | // Fill in some data to test with, one at a time, using emplace 61 | mymap_emplace(&m3, 1, "red"); 62 | mymap_emplace(&m3, 2, "yellow"); 63 | mymap_emplace(&m3, 3, "blue"); 64 | mymap_emplace(&m3, 4, "green"); 65 | mymap_emplace(&m3, 5, "orange"); 66 | mymap_emplace(&m3, 6, "purple"); 67 | mymap_emplace(&m3, 7, "pink"); 68 | 69 | puts("Starting data of map m3 is:"); 70 | printmap(m3); 71 | // The 3rd member function removes elements with a given Key 72 | int count = mymap_erase(&m3, 2); 73 | // The 3rd member function also returns the number of elements removed 74 | printf("The number of elements removed from m3 is: %d\n", count); 75 | puts("After the element with a key of 2 is deleted, the map m3 is:"); 76 | printmap(m3); 77 | 78 | c_drop(mymap, &m1, &m2, &m3); 79 | } 80 | -------------------------------------------------------------------------------- /examples/sortedmaps/smap_find.c: -------------------------------------------------------------------------------- 1 | // This implements the c++ std::map::find example at: 2 | // https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17 3 | #include 4 | 5 | #define T smap_istr, int, cstr, (c_valpro) 6 | #include 7 | 8 | #define T vec_istr, smap_istr_raw 9 | #include 10 | 11 | void print_elem(smap_istr_raw p) { 12 | printf("(%d, %s) ", p.first, p.second); 13 | } 14 | 15 | #define use_print_collection(CX) \ 16 | void print_collection_##CX(const CX* t) { \ 17 | printf("%" c_ZI " elements: ", CX##_size(t)); \ 18 | \ 19 | for (c_each(p, CX, *t)) { \ 20 | print_elem(CX##_value_toraw(p.ref)); \ 21 | } \ 22 | puts(""); \ 23 | } 24 | 25 | use_print_collection(smap_istr) 26 | use_print_collection(vec_istr) 27 | 28 | void findit(smap_istr c, smap_istr_key val) 29 | { 30 | printf("Trying find() on value %d\n", val); 31 | smap_istr_iter result = smap_istr_find(&c, val); // prefer contains() or get() 32 | if (result.ref) { 33 | printf("Element found: "); print_elem(smap_istr_value_toraw(result.ref)); puts(""); 34 | } else { 35 | puts("Element not found."); 36 | } 37 | } 38 | 39 | int main(void) 40 | { 41 | smap_istr m1 = c_make(smap_istr, {{40, "Zr"}, {45, "Rh"}}); 42 | vec_istr v = {0}; 43 | 44 | puts("The starting map m1 is (key, value):"); 45 | print_collection_smap_istr(&m1); 46 | 47 | typedef vec_istr_value pair; 48 | vec_istr_push(&v, c_literal(pair){43, "Tc"}); 49 | vec_istr_push(&v, c_literal(pair){41, "Nb"}); 50 | vec_istr_push(&v, c_literal(pair){46, "Pd"}); 51 | vec_istr_push(&v, c_literal(pair){42, "Mo"}); 52 | vec_istr_push(&v, c_literal(pair){44, "Ru"}); 53 | vec_istr_push(&v, c_literal(pair){44, "Ru"}); // attempt a duplicate 54 | 55 | puts("Inserting the following vector data into m1:"); 56 | print_collection_vec_istr(&v); 57 | 58 | for (c_each(i, vec_istr, vec_istr_begin(&v), vec_istr_end(&v))) 59 | smap_istr_emplace(&m1, i.ref->first, i.ref->second); 60 | 61 | puts("The modified map m1 is (key, value):"); 62 | print_collection_smap_istr(&m1); 63 | puts(""); 64 | findit(m1, 45); 65 | findit(m1, 6); 66 | 67 | smap_istr_drop(&m1); 68 | vec_istr_drop(&v); 69 | } 70 | -------------------------------------------------------------------------------- /examples/sortedmaps/smap_insert.c: -------------------------------------------------------------------------------- 1 | // This implements the std::map insert c++ example at: 2 | // https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19 3 | 4 | #define T smap_ii, int, int 5 | #include 6 | 7 | #define T vec_ii, smap_ii_value 8 | #include 9 | 10 | #include 11 | 12 | #define T smap_istr, int, cstr, (c_valpro) // Map of int => cstr 13 | #include 14 | 15 | void print_ii(smap_ii map) { 16 | for (c_each(e, smap_ii, map)) 17 | printf("(%d, %d) ", e.ref->first, e.ref->second); 18 | puts(""); 19 | } 20 | 21 | void print_istr(smap_istr map) { 22 | for (c_each(e, smap_istr, map)) 23 | printf("(%d, %s) ", e.ref->first, cstr_str(&e.ref->second)); 24 | puts(""); 25 | } 26 | 27 | int main(void) 28 | { 29 | // insert single values 30 | smap_ii m1 = {0}; 31 | smap_ii_insert(&m1, 1, 10); 32 | smap_ii_push(&m1, c_literal(smap_ii_value){2, 20}); 33 | 34 | puts("The original key and mapped values of m1 are:"); 35 | print_ii(m1); 36 | 37 | // intentionally attempt a duplicate, single element 38 | smap_ii_result ret = smap_ii_insert(&m1, 1, 111); 39 | if (!ret.inserted) { 40 | smap_ii_value pr = *ret.ref; 41 | puts("Insert failed, element with key value 1 already exists."); 42 | printf(" The existing element is (%d, %d)\n", pr.first, pr.second); 43 | } 44 | else { 45 | puts("The modified key and mapped values of m1 are:"); 46 | print_ii(m1); 47 | } 48 | puts(""); 49 | 50 | smap_ii_insert(&m1, 3, 30); 51 | puts("The modified key and mapped values of m1 are:"); 52 | print_ii(m1); 53 | puts(""); 54 | 55 | // The templatized version inserting a jumbled range 56 | smap_ii m2 = {0}; 57 | vec_ii v = {0}; 58 | typedef vec_ii_value ipair; 59 | vec_ii_push(&v, c_literal(ipair){43, 294}); 60 | vec_ii_push(&v, c_literal(ipair){41, 262}); 61 | vec_ii_push(&v, c_literal(ipair){45, 330}); 62 | vec_ii_push(&v, c_literal(ipair){42, 277}); 63 | vec_ii_push(&v, c_literal(ipair){44, 311}); 64 | 65 | puts("Inserting the following vector data into m2:"); 66 | for (c_each(e, vec_ii, v)) 67 | printf("(%d, %d) ", e.ref->first, e.ref->second); 68 | puts(""); 69 | 70 | for (c_each(e, vec_ii, v)) 71 | smap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second); 72 | 73 | puts("The modified key and mapped values of m2 are:"); 74 | for (c_each(e, smap_ii, m2)) 75 | printf("(%d, %d) ", e.ref->first, e.ref->second); 76 | puts("\n"); 77 | 78 | // The templatized versions move-constructing elements 79 | smap_istr m3 = {0}; 80 | smap_istr_value ip1 = {475, cstr_lit("blue")}, ip2 = {510, cstr_lit("green")}; 81 | 82 | // single element 83 | smap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second)); 84 | puts("After the first move insertion, m3 contains:"); 85 | print_istr(m3); 86 | 87 | // single element 88 | smap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second)); 89 | puts("After the second move insertion, m3 contains:"); 90 | print_istr(m3); 91 | puts(""); 92 | 93 | smap_ii m4 = {0}; 94 | // Insert the elements from an initializer_list 95 | m4 = c_make(smap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}}); 96 | puts("After initializer_list insertion, m4 contains:"); 97 | print_ii(m4); 98 | puts(""); 99 | 100 | vec_ii_drop(&v); 101 | smap_istr_drop(&m3); 102 | c_drop(smap_ii, &m1, &m2, &m4); 103 | } 104 | -------------------------------------------------------------------------------- /examples/sortedmaps/sorted_map.c: -------------------------------------------------------------------------------- 1 | // https://iq.opengenus.org/containers-cpp-stl/ 2 | 3 | #include 4 | #define T Mymap, int, int 5 | #include 6 | 7 | int main(void) 8 | { 9 | Mymap gquiz1 = {0}, gquiz2 = {0}; 10 | c_defer( 11 | Mymap_drop(&gquiz1), 12 | Mymap_drop(&gquiz2) 13 | ){ 14 | // insert elements in random order 15 | Mymap_insert(&gquiz1, 2, 30); 16 | Mymap_insert(&gquiz1, 4, 20); 17 | Mymap_insert(&gquiz1, 7, 10); 18 | Mymap_insert(&gquiz1, 5, 50); 19 | Mymap_insert(&gquiz1, 3, 60); 20 | Mymap_insert(&gquiz1, 1, 40); 21 | Mymap_insert(&gquiz1, 6, 50); 22 | 23 | // printing map gquiz1 24 | printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n"); 25 | for (c_each(itr, Mymap, gquiz1)) 26 | printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); 27 | printf("\n"); 28 | 29 | // assigning the elements from gquiz1 to gquiz2 30 | for (c_each(i, Mymap, gquiz1)) 31 | Mymap_insert(&gquiz2, i.ref->first, i.ref->second); 32 | 33 | // print all elements of the map gquiz2 34 | printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n"); 35 | for (c_each(itr, Mymap, gquiz2)) 36 | printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); 37 | printf("\n"); 38 | 39 | // remove all elements up to element with key=3 in gquiz2 40 | printf("\ngquiz2 after removal of elements less than key=3 :\n"); 41 | printf("\tKEY\tELEMENT\n"); 42 | Mymap_erase_range(&gquiz2, Mymap_begin(&gquiz2), 43 | Mymap_find(&gquiz2, 3)); 44 | for (c_each(itr, Mymap, gquiz2)) 45 | printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); 46 | printf("\n"); 47 | 48 | // remove all elements with key = 4 49 | int num = Mymap_erase(&gquiz2, 4); 50 | printf("\ngquiz2.erase(4) : %d removed\n", num); 51 | printf("\tKEY\tELEMENT\n"); 52 | for (c_each(itr, Mymap, gquiz2)) 53 | printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); 54 | printf("\n"); 55 | 56 | // lower bound and upper bound for map gquiz1 key = 5 57 | printf("gquiz1.lower_bound(5) : "); 58 | printf("\tKEY = %d\t", Mymap_lower_bound(&gquiz1, 5).ref->first); 59 | printf("\tELEMENT = %d\n", Mymap_lower_bound(&gquiz1, 5).ref->second); 60 | printf("gquiz1.upper_bound(5) : "); 61 | printf("\tKEY = %d\t", Mymap_lower_bound(&gquiz1, 5+1).ref->first); 62 | printf("\tELEMENT = %d\n", Mymap_lower_bound(&gquiz1, 5+1).ref->second); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /examples/sortedmaps/sset_erase.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define T ISet, int 4 | #include 5 | 6 | int main(void) 7 | { 8 | ISet set = c_make(ISet, {30, 20, 80, 40, 60, 90, 10, 70, 50}); 9 | 10 | for (c_each(k, ISet, set)) 11 | printf(" %d", *k.ref); 12 | puts(""); 13 | 14 | int val = 64; 15 | ISet_iter it; 16 | printf("Show values >= %d:\n", val); 17 | it = ISet_lower_bound(&set, val); 18 | 19 | for (c_each(k, ISet, it, ISet_end(&set))) 20 | printf(" %d", *k.ref); 21 | puts(""); 22 | 23 | printf("Erase values >= %d:\n", val); 24 | while (it.ref) 25 | it = ISet_erase_at(&set, it); 26 | 27 | for (c_each(k, ISet, set)) 28 | printf(" %d", *k.ref); 29 | puts(""); 30 | 31 | val = 40; 32 | printf("Erase values < %d:\n", val); 33 | it = ISet_lower_bound(&set, val); 34 | ISet_erase_range(&set, ISet_begin(&set), it); 35 | 36 | for (c_each(k, ISet, set)) 37 | printf(" %d", *k.ref); 38 | puts(""); 39 | 40 | ISet_drop(&set); 41 | } 42 | -------------------------------------------------------------------------------- /examples/spans/matmult.c: -------------------------------------------------------------------------------- 1 | // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2642r2.html 2 | // https://vaibhaw-vipul.medium.com/matrix-multiplication-optimizing-the-code-from-6-hours-to-1-sec-70889d33dcfa 3 | // Compile with: gcc -O3 -march=native -fopenmp matmult.c -lstc # Multiplies two 4K matrices in 0.5 seconds on a Ryzen 5700X CPU. 4 | #define NDEBUG 5 | #include 6 | #include 7 | #include 8 | 9 | use_cspan(Mat, float, 2); 10 | typedef Mat OutMat; 11 | 12 | // Default matrix multiplication 13 | void base_case_matrix_product(Mat A, Mat B, OutMat C) { 14 | #ifdef __GNUC__ 15 | #pragma omp parallel for schedule(runtime) 16 | #endif 17 | for (int i = 0; i < A.shape[0]; ++i) { 18 | for (int k = 0; k < A.shape[1]; k++) { 19 | for (int j = 0; j < B.shape[1]; j++) { 20 | *cspan_at(&C, i,j) += *cspan_at(&A, i,k) * *cspan_at(&B, k,j); 21 | } 22 | } 23 | } 24 | } 25 | 26 | // Recursive implementation 27 | typedef struct { Mat r00, r01, r10, r11; } Partition; 28 | 29 | Partition partition(Mat A) { 30 | int m = A.shape[0]; 31 | int n = A.shape[1]; 32 | return (Partition){ 33 | .r00 = cspan_slice(&A, Mat, {0, m/2}, {0, n/2}), 34 | .r01 = cspan_slice(&A, Mat, {0, m/2}, {n/2, n}), 35 | .r10 = cspan_slice(&A, Mat, {m/2, m}, {0, n/2}), 36 | .r11 = cspan_slice(&A, Mat, {m/2, m}, {n/2, n}), 37 | }; 38 | } 39 | 40 | void recursive_matrix_product(Mat A, Mat B, OutMat C) { 41 | // Some hardware-dependent constant 42 | if (C.shape[0]*C.shape[1] <= 2048*2048) { 43 | base_case_matrix_product(A, B, C); 44 | } else { 45 | Partition c = partition(C), 46 | a = partition(A), 47 | b = partition(B); 48 | recursive_matrix_product(a.r00, b.r00, c.r00); 49 | recursive_matrix_product(a.r01, b.r10, c.r00); 50 | recursive_matrix_product(a.r10, b.r00, c.r10); 51 | recursive_matrix_product(a.r11, b.r10, c.r10); 52 | recursive_matrix_product(a.r00, b.r01, c.r01); 53 | recursive_matrix_product(a.r01, b.r11, c.r01); 54 | recursive_matrix_product(a.r10, b.r01, c.r11); 55 | recursive_matrix_product(a.r11, b.r11, c.r11); 56 | } 57 | } 58 | 59 | 60 | #define T Data, float 61 | #include 62 | #include 63 | 64 | int main(int argc, char* argv[]) { 65 | int M = 512, P, N; 66 | if (argc > 1) 67 | M = atoi(argv[1]); 68 | if (argc > 3) { 69 | P = atoi(argv[2]); 70 | N = atoi(argv[3]); 71 | } else 72 | P = N = M; 73 | 74 | printf("Recursive Matrix Multiplication (%dx%d * %dx%d)\n", M, P, P, N); 75 | printf("Usage: %s [m [p n]]\n", argv[0]); 76 | 77 | Data values = Data_with_size(M*P + P*N + M*N, 0); 78 | for (c_each_n(i, Data, values, M*P + P*N)) 79 | *i.ref = (Data_value)((crand64_real() - 0.5)*10.0); 80 | 81 | Mat a = cspan_md(values.data, M, P); 82 | Mat b = cspan_md(values.data + M*P, P, N); 83 | OutMat c = cspan_md(values.data + M*P + P*N, M, N); 84 | 85 | clock_t t = clock(); 86 | 87 | //base_case_matrix_product(a, b, c); 88 | recursive_matrix_product(a, b, c); // > gcc 2x faster 89 | 90 | t = clock() - t; 91 | 92 | puts("an 8x8 sub-matrix of result c"); 93 | cspan_print(Mat, "%.4f", cspan_slice(&c, Mat, {0, 8}, {0, 8})); 94 | 95 | printf("\ntime %f ms\n", (double)t*1000.0/CLOCKS_PER_SEC); 96 | Data_drop(&values); 97 | } 98 | -------------------------------------------------------------------------------- /examples/spans/mdspan.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | use_cspan(DSpan2, double, 2); 6 | use_cspan(DSpan3, double, 3); 7 | 8 | int main(void) { 9 | const int nx=3, ny=4, nz=5; 10 | double* data = c_new_n(double, nx*ny*nz); 11 | 12 | printf("\nMultidim span ms[3, 4, 5], fortran ordered"); 13 | DSpan3 ms = cspan_md_layout(c_COLMAJOR, data, nx, ny, nz); 14 | 15 | int idx = 0; 16 | for (int i = 0; i < ms.shape[0]; ++i) 17 | for (int j = 0; j < ms.shape[1]; ++j) 18 | for (int k = 0; k < ms.shape[2]; ++k) 19 | *cspan_at(&ms, i, j, k) = ++idx; 20 | 21 | cspan_transpose(&ms); 22 | 23 | printf(", transposed:\n\n"); 24 | cspan_print(DSpan3, "%.2f", ms); 25 | 26 | puts("Slicing:"); 27 | printf("ms[0, :, :]\n"); 28 | cspan_print(DSpan2, "%g", cspan_slice(&ms, DSpan2, {0}, {c_ALL}, {c_ALL})); 29 | 30 | printf("ms[:, 0, :]\n"); 31 | cspan_print(DSpan2, "%g", cspan_slice(&ms, DSpan2, {c_ALL}, {0}, {c_ALL})); 32 | 33 | printf("ms[:, :, 0]\n"); 34 | cspan_print(DSpan2, "%g", cspan_slice(&ms, DSpan2, {c_ALL}, {c_ALL}, {0})); 35 | 36 | free(data); 37 | } 38 | -------------------------------------------------------------------------------- /examples/spans/meson.build: -------------------------------------------------------------------------------- 1 | cc = meson.get_compiler('c') 2 | 3 | if cc.get_id() == 'gcc' 4 | span_deps = [example_deps, dependency('openmp')] 5 | else 6 | span_deps = example_deps 7 | endif 8 | 9 | foreach sample : [ 10 | 'matmult', 11 | 'mdspan', 12 | 'multidim', 13 | 'printspan', 14 | 'submdspan', 15 | 'span_demo', 16 | ] 17 | test( 18 | sample, 19 | executable( 20 | sample, 21 | files(f'@sample@.c'), 22 | dependencies: span_deps, 23 | install: false, 24 | ), 25 | suite: 'cspan', 26 | ) 27 | endforeach 28 | -------------------------------------------------------------------------------- /examples/spans/multidim.c: -------------------------------------------------------------------------------- 1 | // Example based on https://en.cppreference.com/w/cpp/container/mdspan 2 | #include 3 | #define T Vec, int 4 | #include 5 | #include 6 | 7 | use_cspan3(ISpan, int); // define ISpan, ISpan2, ISpan3 8 | 9 | int main(void) 10 | { 11 | 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}); 12 | 13 | // Create 1d span from a compatibel container 14 | ISpan ms1 = cspan_from_vec(&vec); 15 | 16 | // Create a 3D mdspan 2 x 3 x 4 17 | ISpan3 ms3 = cspan_md(vec.data, 2, 3, 4); 18 | 19 | puts("ms3:"); 20 | cspan_print(ISpan3, "%d", ms3); 21 | 22 | // Take a slice of md3 23 | ISpan3 ss3 = cspan_slice(&ms3, ISpan3, {c_ALL}, {1,3}, {1,3}); 24 | puts("\nss3 = ms3[:, 1:3, 1:3]"); 25 | cspan_print(ISpan3, "%d", ss3); 26 | 27 | puts("\nIterate ss3 flat:"); 28 | for (c_each(i, ISpan3, ss3)) 29 | printf(" %d", *i.ref); 30 | puts(""); 31 | 32 | // submd3 span reduces rank depending on number of arguments 33 | ISpan2 ms2 = cspan_submd3(&ms3, 1); 34 | 35 | // Change data on the 2d subspan 36 | for (int i=0; i != ms2.shape[0]; i++) 37 | for (int j=0; j != ms2.shape[1]; j++) 38 | *cspan_at(&ms2, i, j) = (i + 1)*100 + j; 39 | 40 | puts("\nms2 = ms3[1] with updated data:"); 41 | cspan_print(ISpan2, "%d", ms2); 42 | 43 | puts("\nOriginal s1 span with updated data:"); 44 | for (c_each(i, ISpan, ms1)) 45 | printf(" %d", *i.ref); 46 | puts(""); 47 | 48 | puts("\nOriginal ms3 span with updated data:"); 49 | cspan_print(ISpan3, "%d", ms3); 50 | 51 | puts("\ncol = ms3[1, :, 2]"); 52 | ISpan col = cspan_slice(&ms3, ISpan, {1}, {c_ALL}, {2}); 53 | for (c_each(i, ISpan, col)) 54 | printf(" %d", *i.ref); 55 | puts(""); 56 | 57 | Vec_drop(&vec); 58 | } 59 | -------------------------------------------------------------------------------- /examples/spans/printspan.c: -------------------------------------------------------------------------------- 1 | // https://www.modernescpp.com/index.php/c-20-std-span/ 2 | 3 | #include 4 | #define i_key int 5 | #include 6 | #define i_key int 7 | #include 8 | #include 9 | 10 | use_cspan(intspan, const int); 11 | 12 | 13 | void printMe(intspan container) { 14 | printf("%d:", (int)cspan_size(&container)); 15 | for (c_each(e, intspan, container)) 16 | printf(" %d", *e.ref); 17 | puts(""); 18 | } 19 | 20 | 21 | int main(void) 22 | { 23 | printMe( c_make(intspan, {1, 2, 3, 4}) ); 24 | 25 | int arr[] = {1, 2, 3, 4, 5}; 26 | printMe( (intspan)cspan_from_array(arr) ); 27 | 28 | vec_int vec = c_make(vec_int, {1, 2, 3, 4, 5, 6}); 29 | printMe( (intspan)cspan_from_vec(&vec) ); 30 | 31 | stack_int stk = c_make(stack_int, {1, 2, 3, 4, 5, 6, 7}); 32 | printMe( (intspan)cspan_from_vec(&stk) ); 33 | 34 | intspan spn = c_make(intspan, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); 35 | printMe( (intspan)cspan_subspan(&spn, 2, 8) ); 36 | 37 | // cleanup 38 | vec_int_drop(&vec); 39 | stack_int_drop(&stk); 40 | } 41 | -------------------------------------------------------------------------------- /examples/spans/span_demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | use_cspan3(Span, int); 4 | 5 | int main(void) 6 | { 7 | Span3 md3 = cspan_md(cspan_zeros(Span, 3*4*5).data, 3, 4, 5); 8 | for (c_range32(i, 3*4*5)) md3.data[i] = i; 9 | 10 | Span2 tmp2 = cspan_submd3(&md3, 2); 11 | cspan_transpose(&tmp2); 12 | Span last_col = cspan_submd2(&tmp2, 4); 13 | 14 | Span2 sliced = cspan_slice(&md3, Span2, {c_ALL}, {c_ALL}, {0}); 15 | 16 | Span2 img = cspan_md(md3.data, 6, 10); 17 | Span2 half = {img.data, cspan_shape(img.shape[0]/2, img.shape[1]/2), 18 | cspan_strides(img.stride.d[0]*2, img.stride.d[1]*2)}; 19 | 20 | Span2 half_tr = Span2_transposed(half); 21 | 22 | puts("\n3D SPAN (md3):"); 23 | cspan_print(Span3, "%d", md3); 24 | 25 | puts("\n3D SPAN LAST 1D COLUMN:"); 26 | cspan_print(Span, "%d", last_col); 27 | 28 | puts("\n3D SPAN SLICED 2D:"); 29 | cspan_print(Span2, "%d", sliced); 30 | 31 | puts("\nROWMAJOR (img):"); 32 | cspan_print(Span2, "%d", img); 33 | 34 | puts("\nSTRIDED (half):"); 35 | cspan_print(Span2, "%d", half); 36 | 37 | puts("\nCOLMAJOR (half):"); 38 | cspan_print(Span2, "%d", half_tr); 39 | } 40 | -------------------------------------------------------------------------------- /examples/spans/submdspan.c: -------------------------------------------------------------------------------- 1 | // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2630r0.html 2 | // C99: 3 | #include 4 | #include 5 | 6 | use_cspan(span2, double, 2); 7 | use_cspan(span3, double, 3); 8 | 9 | // Set all elements of a rank-2 mdspan to zero. 10 | void zero_2d(span2 grid2d) { 11 | c_static_assert(cspan_rank(&grid2d) == 2); 12 | for (int i = 0; i < grid2d.shape[0]; ++i) { 13 | for (int j = 0; j < grid2d.shape[1]; ++j) { 14 | *cspan_at(&grid2d, i,j) = 0; 15 | } 16 | } 17 | } 18 | 19 | void zero_surface(span3 grid3d) { 20 | c_static_assert(cspan_rank(&grid3d) == 3); 21 | zero_2d(cspan_slice(&grid3d, span2, {0}, {c_ALL}, {c_ALL})); 22 | zero_2d(cspan_slice(&grid3d, span2, {c_ALL}, {0}, {c_ALL})); 23 | zero_2d(cspan_slice(&grid3d, span2, {c_ALL}, {c_ALL}, {0})); 24 | zero_2d(cspan_slice(&grid3d, span2, {grid3d.shape[0]-1}, {c_ALL}, {c_ALL})); 25 | zero_2d(cspan_slice(&grid3d, span2, {c_ALL}, {grid3d.shape[1]-1}, {c_ALL})); 26 | zero_2d(cspan_slice(&grid3d, span2, {c_ALL}, {c_ALL}, {grid3d.shape[2]-1})); 27 | } 28 | 29 | int main(void) { 30 | double arr[4*4*5]; 31 | for (c_range32(i, c_countof(arr))) 32 | arr[i] = i + i/77.0; 33 | 34 | span3 md = cspan_md(arr, 4, 4, 5); 35 | 36 | zero_surface(md); 37 | 38 | cspan_print(span3, "%.2f", md); 39 | puts("done"); 40 | } 41 | -------------------------------------------------------------------------------- /examples/strings/cstr_match.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) 6 | { 7 | cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"); 8 | 9 | isize pos = cstr_find_at(&ss, 0, "brown"); 10 | printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "" : cstr_str(&ss) + pos); 11 | printf("equals: %d\n", cstr_equals(&ss, "The quick brown fox jumps over the lazy dog.JPG")); 12 | printf("contains: %d\n", cstr_contains(&ss, "umps ove")); 13 | printf("starts_with: %d\n", cstr_starts_with(&ss, "The quick brown")); 14 | printf("ends_with: %d\n", cstr_ends_with(&ss, ".jpg")); 15 | printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); 16 | 17 | cstr s1 = cstr_lit("hell😀 w😀rl🐨"); 18 | csview ch1 = cstr_u8_at(&s1, 7).chr; 19 | csview ch2 = cstr_u8_at(&s1, 10).chr; 20 | printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); 21 | printf("ch1: " c_svfmt "\n", c_svarg(ch1)); 22 | printf("ch2: " c_svfmt "\n", c_svarg(ch2)); 23 | 24 | c_drop(cstr, &ss, &s1); 25 | } 26 | -------------------------------------------------------------------------------- /examples/strings/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'cstr_match', 3 | 'replace', 4 | 'splitstr', 5 | 'sso_map', 6 | 'sso_substr', 7 | 'sview_split', 8 | 'utf8replace_c', 9 | ] 10 | test( 11 | sample, 12 | executable( 13 | sample, 14 | files(f'@sample@.c'), 15 | dependencies: example_deps, 16 | install: false, 17 | ), 18 | suite: 'cstr', 19 | ) 20 | endforeach 21 | -------------------------------------------------------------------------------- /examples/strings/replace.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | const char *base = "this is a test string."; 6 | const char *s2 = "n example"; 7 | const char *s3 = "sample phrase"; 8 | 9 | // replace signatures used in the same order as described above: 10 | 11 | // Ustring positions: 0123456789*123456789*12345 12 | cstr s = cstr_from(base); // "this is a test string." 13 | cstr m = cstr_clone(s); 14 | 15 | cstr_append(&m, cstr_str(&m)); 16 | cstr_append(&m, cstr_str(&m)); 17 | printf("%s\n", cstr_str(&m)); 18 | 19 | cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) 20 | printf("(1) %s\n", cstr_str(&s)); 21 | 22 | cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) 23 | printf("(2) %s\n", cstr_str(&s)); 24 | 25 | cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) 26 | printf("(3) %s\n", cstr_str(&s)); 27 | 28 | cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) 29 | printf("(4) %s\n", cstr_str(&s)); 30 | 31 | cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) 32 | printf("(5) %s\n", cstr_str(&s)); 33 | 34 | c_drop(cstr, &s, &m); 35 | } 36 | -------------------------------------------------------------------------------- /examples/strings/splitstr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) 6 | { 7 | puts("Split with c_token():"); 8 | 9 | for (c_token(i, " ", "Hello World C99!")) 10 | printf("'" c_svfmt "'\n", c_svarg(i.token)); 11 | 12 | puts("\nSplit with for (c_match(regex)):"); 13 | 14 | cregex re = cregex_from("[^\\s]+"); 15 | for (c_match(i, &re, " Hello \t World \n C99! ")) 16 | printf("'" c_svfmt "'\n", c_svarg(i.match[0])); 17 | 18 | cregex_drop(&re); 19 | } 20 | -------------------------------------------------------------------------------- /examples/strings/sso_map.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define i_keypro cstr 3 | #define i_valpro cstr 4 | #include 5 | 6 | int main(void) 7 | { 8 | hmap_cstr m = {0}; 9 | hmap_cstr_emplace(&m, "Test short", "This is a short string"); 10 | hmap_cstr_emplace(&m, "Test long ", "This is a longer string"); 11 | 12 | for (c_each_kv(k, v, hmap_cstr, m)) 13 | printf("%s: '%s' Len=%d, Is long: %s\n", 14 | cstr_str(k), cstr_str(v), (int)cstr_size(v), 15 | cstr_is_long(v) ? "true" : "false"); 16 | 17 | hmap_cstr_drop(&m); 18 | } 19 | -------------------------------------------------------------------------------- /examples/strings/sso_substr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | cstr str = cstr_lit("We think in generalities, but we live in details."); 7 | csview sv = cstr_sv(&str); 8 | csview sv1 = csview_subview(sv, 3, 5); // "think" 9 | isize pos = csview_find(sv, "live"); // position of "live" 10 | csview sv2 = csview_subview(sv, pos, 4); // "live" 11 | csview sv3 = csview_subview_pro(sv, -8, 7); // "details" 12 | printf(c_svfmt ", " c_svfmt ", " c_svfmt "\n", 13 | c_svarg(sv1), c_svarg(sv2), c_svarg(sv3)); 14 | 15 | cstr_assign(&str, "apples are green or red"); 16 | sv = cstr_sv(&str); 17 | cstr s2 = cstr_from_sv(csview_subview_pro(sv, -3, 3)); // "red" 18 | cstr s3 = cstr_from_sv(csview_subview(sv, 0, 6)); // "apples" 19 | printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); 20 | 21 | c_drop(cstr, &str, &s2, &s3); 22 | } 23 | -------------------------------------------------------------------------------- /examples/strings/sview_split.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | // No memory allocations or string length calculations! 7 | const csview date = c_sv("2021/03/12"); 8 | isize pos = 0; 9 | const csview year = csview_token(date, "/", &pos); 10 | const csview day = csview_token(date, "/", &pos); 11 | const csview month = csview_token(date, "/", &pos); 12 | 13 | printf(c_svfmt ", " c_svfmt ", " c_svfmt "\n", 14 | c_svarg(year), c_svarg(month), c_svarg(day)); 15 | 16 | cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); 17 | printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); 18 | c_drop(cstr, &y, &m, &d); 19 | } 20 | -------------------------------------------------------------------------------- /examples/strings/utf8replace_c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | cstr hello = cstr_lit("hell😀 w😀rld"); 7 | printf("%s, %d:%d\n", cstr_str(&hello), (int)cstr_u8_size(&hello), (int)cstr_size(&hello)); 8 | 9 | zsview sub5 = cstr_u8_tail(&hello, 5); 10 | printf("%s, %d:%d\n", sub5.str, (int)zsview_u8_size(sub5), (int)sub5.size); 11 | 12 | /* replace second smiley at utf8 codepoint pos 7 */ 13 | 14 | cstr_u8_insert(&hello, 8, "🐨"); 15 | printf("%s, %d:%d\n", cstr_str(&hello), (int)cstr_u8_size(&hello), (int)cstr_size(&hello)); 16 | 17 | cstr_u8_erase(&hello, 7, 1); 18 | printf("%s, %d:%d\n", cstr_str(&hello), (int)cstr_u8_size(&hello), (int)cstr_size(&hello)); 19 | 20 | cstr_u8_replace(&hello, 9, 1, "😀"); 21 | printf("%s, %d:%d\n", cstr_str(&hello), (int)cstr_u8_size(&hello), (int)cstr_size(&hello)); 22 | 23 | for (c_each(c, cstr, hello)) 24 | printf(c_svfmt ",", c_svarg(c.chr)); 25 | 26 | cstr str = cstr_lit("scooby, dooby doo"); 27 | cstr_replace(&str, "oo", "00"); 28 | printf("\n%s\n", cstr_str(&str)); 29 | 30 | c_drop(cstr, &hello, &str); 31 | } 32 | -------------------------------------------------------------------------------- /examples/strings/utf8replace_rs.rs: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | let mut hello = String::from("hell😀 w😀rld"); 3 | println!("{}", hello); 4 | 5 | /* replace second smiley at utf8 codepoint pos 7 */ 6 | hello.replace_range( 7 | hello 8 | .char_indices() 9 | .nth(7) 10 | .map(|(pos, ch)| (pos..pos + ch.len_utf8())) 11 | .unwrap(), 12 | "🐨", 13 | ); 14 | println!("{}", hello); 15 | 16 | for c in hello.chars() { 17 | print!("{},", c); 18 | } 19 | 20 | let str = "If you find the time, you will find the winner"; 21 | println!("\n{}", str.replace("find", "match")); 22 | } 23 | -------------------------------------------------------------------------------- /examples/vectors/lower_bound.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define T IVec, int, (c_use_cmp) 4 | #include 5 | 6 | #define T ISet, int 7 | #include 8 | 9 | int main(void) 10 | { 11 | // TEST SORTED VECTOR 12 | { 13 | int key; 14 | IVec vec = c_make(IVec, {40, 600, 1, 7000, 2, 500, 30}); 15 | 16 | IVec_sort(&vec); 17 | 18 | key = 100; 19 | isize res = IVec_lower_bound(&vec, key); 20 | if (res != -1) 21 | printf("Sorted Vec %d: lower bound: %d\n", key, vec.data[res]); // 500 22 | 23 | key = 10; 24 | isize it1 = IVec_lower_bound(&vec, key); 25 | if (it1 != -1) 26 | printf("Sorted Vec %3d: lower_bound: %d\n", key, vec.data[it1]); // 30 27 | 28 | key = 600; 29 | isize it2 = IVec_binary_search(&vec, key); 30 | if (it2 != -1) 31 | printf("Sorted Vec %d: bin. search: %d\n", key, vec.data[it2]); // 600 32 | 33 | for (isize i = it1; i != it2; ++i) 34 | printf(" %d\n", vec.data[i]); 35 | 36 | puts(""); 37 | IVec_drop(&vec); 38 | } 39 | 40 | // TEST SORTED SET 41 | { 42 | int key, *res; 43 | ISet set = c_make(ISet, {40, 600, 1, 7000, 2, 500, 30}); 44 | 45 | key = 100; 46 | res = ISet_lower_bound(&set, key).ref; 47 | if (res) 48 | printf("Sorted Set %d: lower bound: %d\n", key, *res); // 500 49 | 50 | key = 10; 51 | ISet_iter it1 = ISet_lower_bound(&set, key); 52 | if (it1.ref) 53 | printf("Sorted Set %3d: lower bound: %d\n", key, *it1.ref); // 30 54 | 55 | key = 600; 56 | ISet_iter it2 = ISet_find(&set, key); 57 | if (it2.ref) 58 | printf("Sorted Set %d: find : %d\n", key, *it2.ref); // 600 59 | 60 | for (c_each(i, ISet, it1, it2)) 61 | printf(" %d\n", *i.ref); 62 | 63 | ISet_drop(&set); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /examples/vectors/meson.build: -------------------------------------------------------------------------------- 1 | foreach sample : [ 2 | 'lower_bound', 3 | 'new_vec', 4 | 'stack', 5 | ] 6 | test( 7 | sample, 8 | executable( 9 | sample, 10 | files(f'@sample@.c'), 11 | dependencies: example_deps, 12 | install: false, 13 | ), 14 | suite: 'vec', 15 | ) 16 | endforeach 17 | -------------------------------------------------------------------------------- /examples/vectors/new_vec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | declare_vec(vec_i32, int); 5 | declare_vec(vec_pnt, struct Point); 6 | 7 | typedef struct MyStruct { 8 | vec_i32 intvec; 9 | vec_pnt pntvec; 10 | } MyStruct; 11 | 12 | #define T vec_i32, int, (c_declared) 13 | #include 14 | 15 | typedef struct Point { int x, y; } Point; 16 | 17 | #define T vec_pnt, Point, (c_declared) 18 | #define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) 19 | #define i_eq(a, b) a->x == b->x && a->y == b->y 20 | #include 21 | 22 | int main(void) 23 | { 24 | MyStruct my = {0}; 25 | 26 | vec_pnt_push(&my.pntvec, c_literal(Point){42, 14}); 27 | vec_pnt_push(&my.pntvec, c_literal(Point){32, 94}); 28 | vec_pnt_push(&my.pntvec, c_literal(Point){62, 81}); 29 | vec_pnt_push(&my.pntvec, c_literal(Point){32, 91}); 30 | 31 | vec_pnt_sort(&my.pntvec); 32 | 33 | for (c_each(i, vec_pnt, my.pntvec)) 34 | printf(" (%d %d)", i.ref->x, i.ref->y); 35 | puts(""); 36 | 37 | vec_i32_drop(&my.intvec); 38 | vec_pnt_drop(&my.pntvec); 39 | } 40 | -------------------------------------------------------------------------------- /examples/vectors/stack.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #define T stack_i, int 5 | #define i_capacity 100 6 | #include 7 | 8 | #define T stack_c, char 9 | #include 10 | 11 | int main(void) { 12 | stack_i stack = {0}; 13 | stack_c chars = {0}; 14 | 15 | for (c_range(i, 101)) 16 | stack_i_push(&stack, (int)(i*i)); 17 | 18 | printf("%d\n", *stack_i_top(&stack)); 19 | 20 | for (c_range(i, 90)) 21 | stack_i_pop(&stack); 22 | 23 | for (c_each(i, stack_i, stack)) 24 | printf(" %d", *i.ref); 25 | puts(""); 26 | printf("top: %d\n", *stack_i_top(&stack)); 27 | 28 | stack_i_drop(&stack); 29 | stack_c_drop(&chars); 30 | } 31 | -------------------------------------------------------------------------------- /include/stc/algorithm.h: -------------------------------------------------------------------------------- 1 | #ifndef STC_ALGORITHM_H_INCLUDED 2 | #define STC_ALGORITHM_H_INCLUDED 3 | 4 | // IWYU pragma: begin_exports 5 | #include "sys/crange.h" 6 | #include "sys/filter.h" 7 | #include "sys/utility.h" 8 | #include "sys/sumtype.h" 9 | // IWYU pragma: end_exports 10 | 11 | #endif // STC_ALGORITHM_H_INCLUDED 12 | -------------------------------------------------------------------------------- /include/stc/cstr.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | /* A string type with short string optimization in C99 with good small-string 25 | * optimization (22 characters with 24 bytes string). 26 | */ 27 | #define i_header // external linkage by default. override with i_static. 28 | #include "priv/linkage.h" 29 | 30 | #ifndef STC_CSTR_H_INCLUDED 31 | #define STC_CSTR_H_INCLUDED 32 | 33 | #include "common.h" 34 | #include "types.h" 35 | #include "priv/utf8_prv.h" 36 | #include "priv/cstr_prv.h" 37 | 38 | #endif // STC_CSTR_H_INCLUDED 39 | 40 | #if defined i_implement || \ 41 | defined STC_CSTR_CORE || \ 42 | defined STC_CSTR_IO || \ 43 | defined STC_CSTR_UTF8 44 | #include "priv/cstr_prv.c" 45 | #endif // i_implement 46 | 47 | #if defined i_import || defined STC_CSTR_UTF8 48 | #include "priv/utf8_prv.c" 49 | #endif 50 | 51 | #include "priv/linkage2.h" 52 | -------------------------------------------------------------------------------- /include/stc/hashmap.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvmap 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | // Unordered map - implemented with the robin-hood hashing scheme. 25 | /* 26 | #define T IMap, int, int 27 | #include 28 | #include 29 | 30 | int main(void) { 31 | IMap map = c_make(IMap, {{12, 32}, {42, 54}}); 32 | IMap_insert(&map, 5, 15); 33 | IMap_insert(&map, 8, 18); 34 | 35 | for (c_each_kv(k, v, IMap, map)) 36 | printf(" %d -> %d\n", *k, *v); 37 | 38 | IMap_drop(&map); 39 | } 40 | */ 41 | 42 | #define _i_prefix hmap_ 43 | #include "hmap.h" 44 | -------------------------------------------------------------------------------- /include/stc/hashset.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | // Unordered set - implemented with the robin-hood hashing scheme. 25 | /* 26 | #define T ISet, int 27 | #include 28 | #include 29 | 30 | int main(void) { 31 | ISet set = {0}; 32 | ISet_insert(&set, 5); 33 | ISet_insert(&set, 8); 34 | 35 | for (c_each(i, ISet, set)) 36 | printf(" %d\n", *i.ref); 37 | 38 | ISet_drop(&set); 39 | } 40 | */ 41 | 42 | #define _i_prefix hset_ 43 | #define _i_is_set 44 | #include "hmap.h" 45 | -------------------------------------------------------------------------------- /include/stc/hset.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | // Unordered set - implemented with the robin-hood hashing scheme. 25 | /* 26 | #define T iset, int 27 | #include 28 | #include 29 | 30 | int main(void) { 31 | iset set = {0}; 32 | iset_insert(&set, 5); 33 | iset_insert(&set, 8); 34 | 35 | for (c_each(i, iset, set)) 36 | printf("set %d\n", *i.ref); 37 | iset_drop(&set); 38 | } 39 | */ 40 | 41 | #define _i_prefix hset_ 42 | #define _i_is_set 43 | #include "hmap.h" 44 | -------------------------------------------------------------------------------- /include/stc/priv/linkage.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | #undef STC_API 24 | #undef STC_DEF 25 | 26 | #if !defined i_static && !defined STC_STATIC && (defined i_header || defined STC_HEADER || \ 27 | defined i_implement || defined STC_IMPLEMENT) 28 | #define STC_API extern 29 | #define STC_DEF 30 | #else 31 | #define i_implement 32 | #if defined __GNUC__ || defined __clang__ || defined __INTEL_LLVM_COMPILER 33 | #define STC_API static __attribute__((unused)) 34 | #else 35 | #define STC_API static inline 36 | #endif 37 | #define STC_DEF static 38 | #endif 39 | #if defined STC_IMPLEMENT || defined i_import 40 | #define i_implement 41 | #endif 42 | 43 | #if defined STC_ALLOCATOR && !defined i_allocator 44 | #define i_allocator STC_ALLOCATOR 45 | #elif !defined i_allocator 46 | #define i_allocator c 47 | #endif 48 | #ifndef i_malloc 49 | #define i_malloc c_JOIN(i_allocator, _malloc) 50 | #define i_calloc c_JOIN(i_allocator, _calloc) 51 | #define i_realloc c_JOIN(i_allocator, _realloc) 52 | #define i_free c_JOIN(i_allocator, _free) 53 | #endif 54 | #if defined __clang__ && !defined __cplusplus 55 | #pragma clang diagnostic push 56 | #pragma clang diagnostic warning "-Wall" 57 | #pragma clang diagnostic warning "-Wextra" 58 | #pragma clang diagnostic warning "-Wpedantic" 59 | #pragma clang diagnostic warning "-Wconversion" 60 | #pragma clang diagnostic warning "-Wwrite-strings" 61 | // ignored 62 | #pragma clang diagnostic ignored "-Wmissing-field-initializers" 63 | #elif defined __GNUC__ && !defined __cplusplus 64 | #pragma GCC diagnostic push 65 | #pragma GCC diagnostic warning "-Wall" 66 | #pragma GCC diagnostic warning "-Wextra" 67 | #pragma GCC diagnostic warning "-Wpedantic" 68 | #pragma GCC diagnostic warning "-Wconversion" 69 | #pragma GCC diagnostic warning "-Wwrite-strings" 70 | // ignored 71 | #pragma GCC diagnostic ignored "-Wclobbered" 72 | #pragma GCC diagnostic ignored "-Wimplicit-fallthrough=3" 73 | #pragma GCC diagnostic ignored "-Wstringop-overflow=" 74 | #pragma GCC diagnostic ignored "-Wmissing-field-initializers" 75 | #endif 76 | -------------------------------------------------------------------------------- /include/stc/priv/linkage2.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | #undef i_allocator 25 | #undef i_malloc 26 | #undef i_calloc 27 | #undef i_realloc 28 | #undef i_free 29 | #undef i_aux 30 | #undef _i_aux_struct 31 | 32 | #undef i_static 33 | #undef i_header 34 | #undef i_implement 35 | #undef i_import 36 | 37 | #if defined __clang__ && !defined __cplusplus 38 | #pragma clang diagnostic pop 39 | #elif defined __GNUC__ && !defined __cplusplus 40 | #pragma GCC diagnostic pop 41 | #endif 42 | -------------------------------------------------------------------------------- /include/stc/priv/template2.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | // IWYU pragma: private 24 | #undef T // alias for i_type 25 | #undef i_type 26 | #undef i_class 27 | #undef i_tag 28 | #undef i_opt 29 | #undef i_capacity 30 | 31 | #undef i_key 32 | #undef i_keypro // Replaces next two 33 | #undef i_key_str // [deprecated] 34 | #undef i_key_arcbox // [deprecated] 35 | #undef i_keyclass 36 | #undef i_cmpclass // define i_keyraw, and bind i_cmp, i_eq, i_hash "class members" 37 | #undef i_rawclass // [deprecated] for i_cmpclass 38 | #undef i_keyclone 39 | #undef i_keydrop 40 | #undef i_keyraw 41 | #undef i_keyfrom 42 | #undef i_keytoraw 43 | #undef i_cmp 44 | #undef i_less 45 | #undef i_eq 46 | #undef i_hash 47 | 48 | #undef i_val 49 | #undef i_valpro // Replaces next two 50 | #undef i_val_str // [deprecated] 51 | #undef i_val_arcbox // [deprecated] 52 | #undef i_valclass 53 | #undef i_valclone 54 | #undef i_valdrop 55 | #undef i_valraw 56 | #undef i_valfrom 57 | #undef i_valtoraw 58 | 59 | #undef i_use_cmp 60 | #undef i_use_eq 61 | #undef i_no_hash 62 | #undef i_no_clone 63 | #undef i_no_emplace 64 | #undef i_declared 65 | 66 | #undef _i_has_cmp 67 | #undef _i_has_eq 68 | #undef _i_prefix 69 | #undef _i_template 70 | #undef Self 71 | -------------------------------------------------------------------------------- /include/stc/queue.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | // Queue. Implemented as a ring buffer. 25 | #include "priv/linkage.h" 26 | #include "types.h" 27 | 28 | #ifndef STC_QUEUE_H_INCLUDED 29 | #define STC_QUEUE_H_INCLUDED 30 | #include "common.h" 31 | #include 32 | #endif // STC_QUEUE_H_INCLUDED 33 | 34 | #ifndef _i_prefix 35 | #define _i_prefix queue_ 36 | #endif 37 | #include "priv/template.h" 38 | #include "priv/queue_prv.h" 39 | #include "priv/linkage2.h" 40 | #include "priv/template2.h" 41 | -------------------------------------------------------------------------------- /include/stc/sort.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | /* Generic Quicksort in C, performs as fast as c++ std::sort(), and more robust. 24 | template params: 25 | #define i_key keytype - [required] (or use i_type, see below) 26 | #define i_less(xp, yp) - optional less function. default: *xp < *yp 27 | #define i_cmp(xp, yp) - alternative 3-way comparison. c_default_cmp(xp, yp) 28 | #define T name - optional, defines {name}_sort(), else {i_key}s_sort(). 29 | #define T name, key - alternative one-liner to define both i_type and i_key. 30 | 31 | // ex1: 32 | #include 33 | #define i_key int 34 | #include 35 | 36 | int main(void) { 37 | int nums[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21}; 38 | 39 | ints_sort(nums, c_arraylen(nums)); 40 | 41 | for (int i = 0; i < c_arraylen(nums); i++) 42 | printf(" %d", nums[i]); 43 | puts(""); 44 | 45 | isize idx = ints_binary_search(nums, 25, c_arraylen(nums)); 46 | if (idx != -1) printf("found: %d\n", nums[idx]); 47 | 48 | idx = ints_lower_bound(nums, 200, c_arraylen(nums)); 49 | if (idx != -1) printf("found lower 200: %d\n", nums[idx]); 50 | } 51 | 52 | // ex2: Test on a deque !! 53 | #include 54 | #define T IDeq, int, (c_use_cmp) // enable comparison functions 55 | #include 56 | 57 | int main(void) { 58 | IDeq nums = c_make(IDeq, {5434, 25, 245, 1, 654, 33, 543, 21}); 59 | IDeq_push_front(&nums, 23); 60 | IDeq_push_front(&nums, 321); 61 | 62 | IDeq_sort(&nums); 63 | 64 | for (c_each (i, IDeq, nums)) 65 | printf(" %d", *i.ref); 66 | puts(""); 67 | 68 | isize idx = IDeq_binary_search(&nums, 25); 69 | if (idx != -1) printf("found: %d\n", *IDeq_at(&nums, idx)); 70 | 71 | idx = IDeq_lower_bound(&nums, 200); 72 | if (idx != -1) printf("found lower 200: %d\n", *IDeq_at(&nums, idx)); 73 | 74 | IDeq_drop(&nums); 75 | } 76 | */ 77 | #ifndef _i_template 78 | #include "priv/linkage.h" 79 | #include "common.h" 80 | 81 | #define _i_is_array 82 | #if defined T && !defined i_type 83 | #define i_type T 84 | #endif 85 | #if defined i_type && !defined i_key 86 | #define Self c_GETARG(1, i_type) 87 | #define i_key c_GETARG(2, i_type) 88 | #elif defined i_type 89 | #define Self i_type 90 | #else 91 | #define Self c_JOIN(i_key, s) 92 | #endif 93 | 94 | typedef i_key Self; 95 | typedef Self c_JOIN(Self, _value), c_JOIN(Self, _raw); 96 | #define i_at(arr, idx) (&(arr)[idx]) 97 | #define i_at_mut i_at 98 | #include "priv/template.h" // IWYU pragma: keep 99 | #endif 100 | 101 | #include "priv/sort_prv.h" 102 | 103 | #ifdef _i_is_array 104 | #undef _i_is_array 105 | #include "priv/linkage2.h" 106 | #include "priv/template2.h" 107 | #endif 108 | #undef i_at 109 | #undef i_at_mut 110 | -------------------------------------------------------------------------------- /include/stc/sortedmap.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | // Sorted map - implemented as an AA-tree (balanced binary tree). 25 | /* 26 | #include 27 | 28 | #define T Intmap, int, int 29 | #include // sorted map of int 30 | 31 | int main(void) { 32 | Intmap map = {0}; 33 | Intmap_insert(&map, 5, 25); 34 | Intmap_insert(&map, 8, 38); 35 | Intmap_insert(&map, 3, 43); 36 | Intmap_insert(&map, 5, 55); 37 | 38 | for (c_each_kv(k, v, Intmap, map)) 39 | printf(" %d -> %d\n", *k, *v); 40 | 41 | Intmap_drop(&map); 42 | } 43 | */ 44 | 45 | #define _i_prefix smap_ 46 | #include "smap.h" 47 | -------------------------------------------------------------------------------- /include/stc/sortedset.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | // Sorted set - implemented as an AA-tree (balanced binary tree). 25 | /* 26 | #include 27 | 28 | #define T Intset, int 29 | #include // sorted set of int 30 | 31 | int main(void) { 32 | Intset set = {0}; 33 | Intset_insert(&set, 5); 34 | Intset_insert(&set, 8); 35 | Intset_insert(&set, 3); 36 | Intset_insert(&set, 5); 37 | 38 | for (c_each(k, Intset, set)) 39 | printf(" %d\n", *k.ref); 40 | 41 | Intset_drop(&set); 42 | } 43 | */ 44 | 45 | #define _i_prefix sset_ 46 | #define _i_is_set 47 | #include "smap.h" 48 | -------------------------------------------------------------------------------- /include/stc/sset.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | // Sorted set - implemented as an AA-tree (balanced binary tree). 25 | /* 26 | #include 27 | 28 | #define T Intset, int 29 | #include // sorted set of int 30 | 31 | int main(void) { 32 | Intset s = {0}; 33 | Intset_insert(&s, 5); 34 | Intset_insert(&s, 8); 35 | Intset_insert(&s, 3); 36 | Intset_insert(&s, 5); 37 | 38 | for (c_each(k, Intset, s)) 39 | printf("set %d\n", *k.ref); 40 | Intset_drop(&s); 41 | } 42 | */ 43 | 44 | #define _i_prefix sset_ 45 | #define _i_is_set 46 | #include "smap.h" 47 | -------------------------------------------------------------------------------- /include/stc/utf8.h: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | * 3 | * Copyright (c) 2025 Tyge Løvset 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | #include "priv/linkage.h" 24 | 25 | #ifndef STC_UTF8_H_INCLUDED 26 | #define STC_UTF8_H_INCLUDED 27 | 28 | #include "common.h" // IWYU pragma: keep 29 | #include "types.h" 30 | #include "priv/utf8_prv.h" // IWYU pragma: keep 31 | 32 | #endif // STC_UTF8_H_INCLUDED 33 | 34 | #if defined i_implement 35 | #include "priv/utf8_prv.c" 36 | #endif 37 | #include "priv/linkage2.h" 38 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'checkscoped', 3 | type: 'feature', 4 | value: 'auto', 5 | description: 'Build checkscoped tool for c_guard* blocks', 6 | ) 7 | option( 8 | 'tests', 9 | type: 'feature', 10 | value: 'auto', 11 | description: 'Build tests and ctest', 12 | ) 13 | option( 14 | 'examples', 15 | type: 'feature', 16 | value: 'auto', 17 | description: 'Build examples', 18 | ) 19 | 20 | option('docdir', type: 'string', description: 'documentation directory') 21 | -------------------------------------------------------------------------------- /src/cregex.c: -------------------------------------------------------------------------------- 1 | #define i_implement 2 | #include "../include/stc/cregex.h" 3 | -------------------------------------------------------------------------------- /src/cspan.c: -------------------------------------------------------------------------------- 1 | #define i_implement 2 | #include "../include/stc/cspan.h" 3 | -------------------------------------------------------------------------------- /src/cstr_core.c: -------------------------------------------------------------------------------- 1 | #define STC_CSTR_CORE 2 | #include "../include/stc/cstr.h" 3 | -------------------------------------------------------------------------------- /src/cstr_io.c: -------------------------------------------------------------------------------- 1 | #define STC_CSTR_IO 2 | #include "../include/stc/cstr.h" 3 | -------------------------------------------------------------------------------- /src/cstr_utf8.c: -------------------------------------------------------------------------------- 1 | #define i_implement 2 | #include "../include/stc/utf8.h" 3 | #define STC_CSTR_UTF8 4 | #include "../include/stc/cstr.h" 5 | -------------------------------------------------------------------------------- /src/csview.c: -------------------------------------------------------------------------------- 1 | #define i_implement 2 | #include "../include/stc/csview.h" 3 | -------------------------------------------------------------------------------- /src/fmt.c: -------------------------------------------------------------------------------- 1 | #if __STDC_VERSION__ >= 201112L 2 | #define i_implement 3 | #include "../include/c11/fmt.h" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/random.c: -------------------------------------------------------------------------------- 1 | #define i_implement 2 | #include "../include/stc/random.h" 3 | -------------------------------------------------------------------------------- /src/singleheader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | import sys 5 | import os 6 | from os.path import dirname, join as path_join, abspath, basename, exists 7 | 8 | top_dir = dirname(abspath(__file__)) 9 | extra_paths = [path_join(top_dir, 'include'), path_join(top_dir, '..', 'include')] 10 | 11 | def find_file(included_name, current_file): 12 | current_dir = dirname(abspath(current_file)) 13 | for idir in [current_dir] + extra_paths: 14 | try_path = path_join(idir, included_name) 15 | if exists(try_path): 16 | return abspath(try_path) 17 | return None 18 | 19 | 20 | def process_file( 21 | file_path, 22 | out_lines=[], 23 | processed_files=[], 24 | ): 25 | out_lines += "// ### BEGIN_FILE_INCLUDE: " + basename(file_path) + '\n' 26 | comment_block = False 27 | with open(file_path, "r", encoding="utf-8") as f: 28 | for line in f: 29 | is_comment = comment_block 30 | if re.search('/\\*.*?\\*/', line): 31 | pass 32 | elif re.search('^\\s*/\\*', line): 33 | comment_block, is_comment = True, True 34 | elif re.search('\\*/', line): 35 | comment_block = False 36 | 37 | if is_comment: 38 | continue 39 | 40 | m_inc = re.search('^\\s*# *include\\s*[<"](.+)[>"]', line) if not is_comment else False 41 | if m_inc: 42 | inc_name = m_inc.group(1) 43 | inc_path = find_file(inc_name, file_path) 44 | if inc_path not in processed_files: 45 | if inc_path is not None: 46 | processed_files += [inc_path] 47 | process_file( 48 | inc_path, 49 | out_lines, 50 | processed_files, 51 | ) 52 | else: 53 | # assume it's a system header 54 | out_lines += [line] 55 | continue 56 | m_once = re.match('^\\s*# *pragma once\\s*', line) if not is_comment else False 57 | # ignore pragma once; we're handling it here 58 | if m_once: 59 | continue 60 | # otherwise, just add the line to the output 61 | if line[-1] != '\n': 62 | line += '\n' 63 | out_lines += [line] 64 | out_lines += "// ### END_FILE_INCLUDE: " + basename(file_path) + '\n' 65 | return ( 66 | "".join(out_lines) 67 | ) 68 | 69 | 70 | if __name__ == "__main__": 71 | with open(sys.argv[2], "w", newline='\n', encoding="utf-8") as f: 72 | print( 73 | process_file( 74 | abspath(sys.argv[1]), 75 | [], 76 | # We use an include guard instead of `#pragma once` because Godbolt will 77 | # cause complaints about `#pragma once` when they are used in URL includes. 78 | [abspath(sys.argv[1])], 79 | ), 80 | file=f 81 | ) 82 | -------------------------------------------------------------------------------- /src/singleupdate.sh: -------------------------------------------------------------------------------- 1 | d=$(git rev-parse --show-toplevel) 2 | mkdir -p $d/../stcsingle/c11 3 | python singleheader.py $d/include/c11/fmt.h $d/../stcsingle/c11/fmt.h 4 | python singleheader.py $d/include/stc/algorithm.h $d/../stcsingle/stc/algorithm.h 5 | python singleheader.py $d/include/stc/coroutine.h $d/../stcsingle/stc/coroutine.h 6 | python singleheader.py $d/include/stc/sort.h $d/../stcsingle/stc/sort.h 7 | python singleheader.py $d/include/stc/random.h $d/../stcsingle/stc/random.h 8 | python singleheader.py $d/include/stc/arc.h $d/../stcsingle/stc/arc.h 9 | python singleheader.py $d/include/stc/cbits.h $d/../stcsingle/stc/cbits.h 10 | python singleheader.py $d/include/stc/box.h $d/../stcsingle/stc/box.h 11 | python singleheader.py $d/include/stc/common.h $d/../stcsingle/stc/common.h 12 | python singleheader.py $d/include/stc/deque.h $d/../stcsingle/stc/deque.h 13 | python singleheader.py $d/include/stc/list.h $d/../stcsingle/stc/list.h 14 | python singleheader.py $d/include/stc/hmap.h $d/../stcsingle/stc/hmap.h 15 | python singleheader.py $d/include/stc/coption.h $d/../stcsingle/stc/coption.h 16 | python singleheader.py $d/include/stc/pqueue.h $d/../stcsingle/stc/pqueue.h 17 | python singleheader.py $d/include/stc/queue.h $d/../stcsingle/stc/queue.h 18 | python singleheader.py $d/include/stc/cregex.h $d/../stcsingle/stc/cregex.h 19 | python singleheader.py $d/include/stc/hset.h $d/../stcsingle/stc/hset.h 20 | python singleheader.py $d/include/stc/smap.h $d/../stcsingle/stc/smap.h 21 | python singleheader.py $d/include/stc/cspan.h $d/../stcsingle/stc/cspan.h 22 | python singleheader.py $d/include/stc/sset.h $d/../stcsingle/stc/sset.h 23 | python singleheader.py $d/include/stc/stack.h $d/../stcsingle/stc/stack.h 24 | python singleheader.py $d/include/stc/cstr.h $d/../stcsingle/stc/cstr.h 25 | python singleheader.py $d/include/stc/csview.h $d/../stcsingle/stc/csview.h 26 | python singleheader.py $d/include/stc/zsview.h $d/../stcsingle/stc/zsview.h 27 | python singleheader.py $d/include/stc/vec.h $d/../stcsingle/stc/vec.h 28 | python singleheader.py $d/include/stc/types.h $d/../stcsingle/stc/types.h 29 | echo "$d/../stcsingle headers updated" 30 | -------------------------------------------------------------------------------- /src/stc_core.c: -------------------------------------------------------------------------------- 1 | #define STC_IMPLEMENT 2 | #include "../include/stc/coroutine.h" 3 | -------------------------------------------------------------------------------- /tests/algorithm_test.c: -------------------------------------------------------------------------------- 1 | // https://mariusbancila.ro/blog/2019/01/20/cpp-code-samples-before-and-after-ranges/ 2 | 3 | #define T IVec, int 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | use_cspan(ISpan, int); 10 | 11 | #include "ctest.h" 12 | 13 | 14 | static cstr to_roman(int value) 15 | { 16 | cstr result = {0}; 17 | struct roman { int d; const char* r; }; 18 | 19 | for (c_items(i, struct roman, { 20 | {1000, "M"}, {900, "CM"}, 21 | {500, "D"}, {400, "CD"}, 22 | {100, "C"}, {90, "XC"}, 23 | {50, "L"}, {40, "XL"}, 24 | {10, "X"}, {9, "IX"}, 25 | {5, "V"}, {4, "IV"}, 26 | {1, "I"} 27 | })){ 28 | while (value >= i.ref->d) { 29 | cstr_append(&result, i.ref->r); 30 | value -= i.ref->d; 31 | } 32 | } 33 | return result; 34 | } 35 | 36 | TEST(algorithm, cstr_append) 37 | { 38 | c_with (cstr s = to_roman(2024), cstr_drop(&s)) 39 | { 40 | EXPECT_STREQ("MMXXIV", cstr_str(&s)); 41 | } 42 | } 43 | 44 | 45 | TEST(algorithm, c_find_if) 46 | { 47 | ISpan nums = c_make(ISpan, {1,1,2,3,5,8,13,21,34}); 48 | 49 | ISpan_iter it; 50 | c_find_if(ISpan, nums, &it, *value == 13); 51 | 52 | EXPECT_EQ(13, *it.ref); 53 | } 54 | 55 | 56 | TEST(algorithm, c_filter) 57 | { 58 | IVec vec = c_make(IVec, {1,1,2,3,5,8,13,21,34,10}); 59 | #define f_is_even(v) ((v & 1) == 0) 60 | #define f_is_odd(v) ((v & 1) == 1) 61 | 62 | isize sum = 0; 63 | c_filter(IVec, vec 64 | , c_flt_skipwhile(f_is_odd(*value)) 65 | && c_flt_skip(1) 66 | && f_is_even(*value) 67 | && c_flt_take(2) 68 | && (sum += *value)); 69 | 70 | EXPECT_EQ(42, sum); 71 | 72 | uint64_t hash = 0; 73 | c_filter(IVec, vec, hash = c_hash_mix(hash, (uint64_t)*value)); 74 | EXPECT_EQ(658, (isize)hash); 75 | 76 | hash = 0; 77 | c_filter_reverse(IVec, vec, hash = c_hash_mix(hash, (uint64_t)*value)); 78 | EXPECT_EQ(10897, (isize)hash); 79 | 80 | sum = 0; 81 | c_filter(IVec, vec, sum += *value); 82 | EXPECT_EQ(98, sum); 83 | 84 | sum = 0; 85 | c_filter_reverse(IVec, vec, sum += *value); 86 | EXPECT_EQ(98, sum); 87 | 88 | sum = 0; 89 | c_filter_zip(IVec, vec, crange, c_iota(-6), sum += *value1 * *value2); 90 | EXPECT_EQ(73, sum); 91 | 92 | IVec_drop(&vec); 93 | } 94 | -------------------------------------------------------------------------------- /tests/deque_test.c: -------------------------------------------------------------------------------- 1 | #include "ctest.h" 2 | 3 | #define T IDeq, int, (c_use_cmp) 4 | #include 5 | 6 | 7 | TEST(deque, basics) { 8 | IDeq d = c_make(IDeq, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); 9 | EXPECT_EQ(12, IDeq_size(&d)); 10 | 11 | for (c_range(5)) 12 | IDeq_pop_front(&d); 13 | for (c_range32(i, 2, 9)) 14 | IDeq_push_back(&d, i*10); 15 | 16 | IDeq res1 = c_make(IDeq, {6, 7, 8, 9, 10, 11, 12, 20, 30, 40, 50, 60, 70, 80}); 17 | EXPECT_TRUE(IDeq_eq(&res1, &d)); 18 | EXPECT_EQ(14, IDeq_size(&d)); 19 | 20 | IDeq_erase_n(&d, 7, 4); 21 | 22 | IDeq res2 = c_make(IDeq, {6, 7, 8, 9, 10, 11, 12, 60, 70, 80}); 23 | EXPECT_TRUE(IDeq_eq(&res2, &d)); 24 | 25 | int nums[] = {200, 300, 400, 500}; 26 | IDeq_insert_n(&d, 7, nums, 4); 27 | 28 | IDeq res3 = c_make(IDeq, {6, 7, 8, 9, 10, 11, 12, 200, 300, 400, 500, 60, 70, 80}); 29 | EXPECT_TRUE(IDeq_eq(&res3, &d)); 30 | EXPECT_EQ(*IDeq_find(&res3, 400).ref, 400); 31 | EXPECT_NULL(IDeq_find(&res3, 401).ref); 32 | 33 | EXPECT_EQ(14, IDeq_size(&d)); 34 | EXPECT_EQ(200, *IDeq_at(&d, 7)); 35 | 36 | c_drop(IDeq, &d, &res1, &res2, &res3); 37 | } 38 | -------------------------------------------------------------------------------- /tests/hmap_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ctest.h" 4 | 5 | #define T Intmap, int, int 6 | #include 7 | 8 | TEST(hashmap, mapdemo1) 9 | { 10 | Intmap nums = {0}; 11 | Intmap_insert(&nums, 8, 64); 12 | Intmap_insert(&nums, 11, 121); 13 | EXPECT_EQ(64, *Intmap_at(&nums, 8)); 14 | Intmap_drop(&nums); 15 | } 16 | 17 | #define T SImap, cstr, int, (c_keypro) 18 | #include 19 | 20 | TEST(hashmap, mapdemo2) 21 | { 22 | SImap nums = {0}; 23 | SImap_clear(&nums); 24 | SImap_emplace_or_assign(&nums, "Hello", 64); 25 | SImap_emplace_or_assign(&nums, "Groovy", 121); 26 | SImap_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous 27 | 28 | EXPECT_EQ(200, *SImap_at(&nums, "Groovy")); 29 | EXPECT_EQ(64, *SImap_at(&nums, "Hello")); 30 | 31 | SImap_drop(&nums); 32 | } 33 | 34 | 35 | #define T Strmap, cstr, cstr, (c_keypro | c_valpro) 36 | #include 37 | 38 | TEST(hashmap, mapdemo3) 39 | { 40 | Strmap map = {0}; 41 | Strmap_emplace(&map, "Map", "test"); 42 | Strmap_emplace(&map, "Make", "my"); 43 | Strmap_emplace(&map, "Hello", "world"); 44 | Strmap_emplace(&map, "Sunny", "day"); 45 | 46 | Strmap_iter it = Strmap_find(&map, "Make"); 47 | Strmap_erase_at(&map, it); 48 | Strmap_erase(&map, "Hello"); 49 | 50 | Strmap res1 = c_make(Strmap, {{"Map", ""}, {"Sunny", ""}}); 51 | Strmap res2 = c_make(Strmap, {{"Sunny", ""}, {"Map", ""}}); 52 | 53 | EXPECT_TRUE(Strmap_eq(&res1, &map)); 54 | EXPECT_TRUE(Strmap_eq(&res2, &map)); 55 | 56 | c_drop(Strmap, &map, &res1, &res2); 57 | } 58 | -------------------------------------------------------------------------------- /tests/list_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ctest.h" 3 | 4 | #define T IList, int, (c_use_cmp) 5 | #include 6 | 7 | 8 | TEST(list, splice) 9 | { 10 | IList list1 = c_make(IList, {1, 2, 3, 4, 5}); 11 | IList list2 = c_make(IList, {10, 20, 30, 40, 50}); 12 | IList_iter pos = IList_advance(IList_begin(&list1), 2); 13 | 14 | // splice list1 into list2 after pos: 15 | pos = IList_splice(&list1, pos, &list2); 16 | 17 | IList res1 = c_make(IList, {1, 2, 10, 20, 30, 40, 50, 3, 4, 5}); 18 | EXPECT_EQ(*pos.ref, 3); 19 | EXPECT_TRUE(IList_eq(&res1, &list1)); 20 | EXPECT_TRUE(IList_is_empty(&list2)); 21 | 22 | // splice items from pos to end of list1 into empty list2: 23 | IList_splice_range(&list2, IList_begin(&list2), &list1, pos, IList_end(&list1)); 24 | 25 | IList res2 = c_make(IList, {1, 2, 10, 20, 30, 40, 50}); 26 | EXPECT_TRUE(IList_eq(&res2, &list1)); 27 | 28 | IList res3 = c_make(IList, {3, 4, 5}); 29 | EXPECT_TRUE(IList_eq(&res3, &list2)); 30 | EXPECT_FALSE(IList_eq(&list1, &list2)); 31 | 32 | c_drop(IList, &list1, &list2, &res1, &res2, &res3); 33 | } 34 | 35 | TEST(list, erase) 36 | { 37 | IList L = c_make(IList, {10, 20, 30, 40, 50}); 38 | 39 | IList_iter it = IList_begin(&L); 40 | IList_next(&it); 41 | it = IList_erase_at(&L, it); 42 | 43 | IList res1 = c_make(IList, {10, 30, 40, 50}); 44 | EXPECT_TRUE(IList_eq(&res1, &L)); 45 | 46 | IList_next(&it); 47 | it = IList_erase_range(&L, it, IList_end(&L)); 48 | 49 | IList res2 = c_make(IList, {10, 30}); 50 | EXPECT_TRUE(IList_eq(&res2, &L)); 51 | 52 | c_drop(IList, &L, &res1, &res2); 53 | } 54 | 55 | 56 | TEST(list, misc) 57 | { 58 | IList nums = {0}, nums2 = {0}; 59 | IList_clear(&nums); 60 | 61 | for (int i = 0; i < 10; ++i) 62 | IList_push_back(&nums, i); 63 | for (int i = 100; i < 110; ++i) 64 | IList_push_back(&nums2, i); 65 | 66 | /* splice nums2 to front of nums */ 67 | IList_splice(&nums, IList_begin(&nums), &nums2); 68 | 69 | 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}); 70 | EXPECT_TRUE(IList_eq(&res1, &nums)); 71 | 72 | *IList_find(&nums, 104).ref += 50; 73 | IList_remove(&nums, 103); 74 | IList res2 = c_make(IList, {100, 101, 102, 154, 105, 106, 107, 108, 109, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); 75 | EXPECT_TRUE(IList_eq(&res2, &nums)); 76 | 77 | IList_iter it = IList_begin(&nums); 78 | IList_erase_range(&nums, IList_advance(it, 5), IList_advance(it, 15)); 79 | IList res3 = c_make(IList, {100, 101, 102, 154, 105, 6, 7, 8, 9}); 80 | EXPECT_TRUE(IList_eq(&res3, &nums)); 81 | 82 | IList_pop_front(&nums); 83 | IList_push_back(&nums, -99); 84 | IList_sort(&nums); 85 | IList res4 = c_make(IList, {-99, 6, 7, 8, 9, 101, 102, 105, 154}); 86 | EXPECT_TRUE(IList_eq(&res4, &nums)); 87 | 88 | c_drop(IList, &nums, &nums2, &res1, &res2, &res3, &res4); 89 | } 90 | -------------------------------------------------------------------------------- /tests/main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2023 Bas van den Berg 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | 18 | #define CTEST_MAIN 19 | 20 | // uncomment lines below to enable/disable features. See README.md for details 21 | //#define CTEST_NO_SEGFAULT 22 | //#define CTEST_NO_COLORS 23 | //#define CTEST_NO_COLOR_OK 24 | 25 | #include "ctest.h" 26 | 27 | int main(int argc, const char *argv[]) 28 | { 29 | return ctest_main(argc, argv); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | tests = get_option('tests').enable_auto_if(root) 2 | 3 | if tests.enabled() 4 | tests_deps = [ 5 | stc_dep, 6 | cc.find_library('m', required: false), 7 | ] 8 | foreach suite, filter : { 9 | 'algorithm': [ 10 | 'cstr_append', 11 | 'c_find_if', 12 | 'c_filter', 13 | ], 14 | 'cregex': [ 15 | 'ISO8601_parse_result', 16 | 'compile_match_char', 17 | 'compile_match_anchors', 18 | 'compile_match_quantifiers1', 19 | 'compile_match_quantifiers2', 20 | 'compile_match_escaped_chars', 21 | 'compile_match_class_simple', 22 | 'compile_match_or', 23 | 'compile_match_class_complex_0', 24 | 'compile_match_class_complex_1', 25 | 'compile_match_cap', 26 | 'search_all', 27 | 'captures_len', 28 | 'captures_cap', 29 | 'replace', 30 | ], 31 | 'cspan': [ 32 | 'subdim', 33 | 'slice', 34 | 'slice2', 35 | 'equality', 36 | ], 37 | 'hmap': [ 38 | 'mapdemo1', 39 | 'mapdemo2', 40 | 'mapdemo3', 41 | ], 42 | 'smap': [ 43 | 'erase', 44 | 'insert', 45 | ], 46 | 'vec': [ 47 | 'basics', 48 | ], 49 | 'deque': [ 50 | 'basics', 51 | ], 52 | 'list': [ 53 | 'splice', 54 | 'erase', 55 | 'misc', 56 | ], 57 | } 58 | test_exe = executable( 59 | f'@suite@_test', 60 | files(f'@suite@_test.c', 'main.c'), 61 | include_directories: inc, 62 | c_args: ['-D_GNU_SOURCE'], 63 | dependencies: tests_deps, 64 | install: false, 65 | ) 66 | foreach unit : filter 67 | test( 68 | unit, 69 | test_exe, 70 | args: [unit], 71 | suite: suite, 72 | ) 73 | endforeach 74 | endforeach 75 | 76 | install_headers('ctest.h', subdir: 'stc') 77 | endif 78 | -------------------------------------------------------------------------------- /tests/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | # tcc compiler: git://repo.or.cz/tinycc.git 3 | # run tests 4 | 5 | cd $(dirname $(realpath $0)) 6 | cc=gcc 7 | if [ ! -z "$1" ]; then 8 | cc=$1 9 | fi 10 | 11 | $cc -O2 -Wall -I../../include *_test.c main.c -o tests.exe -lstc 12 | ./tests.exe 13 | rm -f ./tests.exe 14 | -------------------------------------------------------------------------------- /tests/vec_test.c: -------------------------------------------------------------------------------- 1 | #include "ctest.h" 2 | 3 | #define T IVec, int, (c_use_eq) 4 | #include 5 | 6 | 7 | TEST(vec, basics) { 8 | IVec d = c_make(IVec, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); 9 | EXPECT_EQ(12, IVec_size(&d)); 10 | 11 | IVec_erase_n(&d, 0, 5); 12 | for (c_range32(i, 2, 9)) 13 | IVec_push_back(&d, i*10); 14 | 15 | IVec res = c_make(IVec, {6, 7, 8, 9, 10, 11, 12, 20, 30, 40, 50, 60, 70, 80}); 16 | EXPECT_TRUE(IVec_eq(&res, &d)); 17 | EXPECT_EQ(14, IVec_size(&d)); 18 | 19 | IVec_erase_n(&d, 7, 4); 20 | 21 | IVec_take(&res, c_make(IVec, {6, 7, 8, 9, 10, 11, 12, 60, 70, 80})); 22 | EXPECT_TRUE(IVec_eq(&res, &d)); 23 | 24 | int nums[] = {200, 300, 400, 500}; 25 | IVec_insert_n(&d, 7, nums, 4); 26 | 27 | IVec_take(&res, c_make(IVec, {6, 7, 8, 9, 10, 11, 12, 200, 300, 400, 500, 60, 70, 80})); 28 | EXPECT_TRUE(IVec_eq(&res, &d)); 29 | 30 | EXPECT_EQ(14, IVec_size(&d)); 31 | EXPECT_EQ(200, *IVec_at(&d, 7)); 32 | 33 | c_drop(IVec, &d, &res); 34 | } 35 | --------------------------------------------------------------------------------