From 462adebf55c77697fbb379a62941c00b876c3f6a Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 14 Apr 2023 16:50:52 +0200 Subject: tuning of hash function. Adjusted benchmark balance. --- include/stc/ccommon.h | 8 ++-- misc/benchmarks/plotbench/cdeq_benchmark.cpp | 2 +- misc/benchmarks/plotbench/clist_benchmark.cpp | 2 +- misc/benchmarks/plotbench/cvec_benchmark.cpp | 2 +- misc/benchmarks/shootout_hashmaps.cpp | 2 +- src/singleupdate.sh | 54 +++++++++++++-------------- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index d5508807..bc12e642 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -147,14 +147,14 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { case 0: return 1; } const uint8_t *x = (const uint8_t*)key; - uint64_t h = *x, n = (uint64_t)len >> 3; + uint64_t h = 0xcbf29ce484222325 + *x*0x811c9dc5UL, n = (uint64_t)len >> 3; len &= 7; while (n--) { memcpy(&u8, x, 8), x += 8; - h += u8*0xc6a4a7935bd1e99d; + h = (h ^ u8)*0x01000193UL; } - while (len--) h = (h << 10) - h - *x++; - return c_ROTL(h, 26) ^ h; + while (len--) h = (h ^ *x++)*0x01000193UL; + return h; } STC_INLINE uint64_t cstrhash(const char *str) diff --git a/misc/benchmarks/plotbench/cdeq_benchmark.cpp b/misc/benchmarks/plotbench/cdeq_benchmark.cpp index bb0e28c8..54d7305b 100644 --- a/misc/benchmarks/plotbench/cdeq_benchmark.cpp +++ b/misc/benchmarks/plotbench/cdeq_benchmark.cpp @@ -12,7 +12,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 50000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 60000000, S = 0x3ffc, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } diff --git a/misc/benchmarks/plotbench/clist_benchmark.cpp b/misc/benchmarks/plotbench/clist_benchmark.cpp index 01bfbf83..703222b3 100644 --- a/misc/benchmarks/plotbench/clist_benchmark.cpp +++ b/misc/benchmarks/plotbench/clist_benchmark.cpp @@ -12,7 +12,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 10000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 25000000, S = 0x3ffc, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } diff --git a/misc/benchmarks/plotbench/cvec_benchmark.cpp b/misc/benchmarks/plotbench/cvec_benchmark.cpp index c488a01c..3b4c3d7d 100644 --- a/misc/benchmarks/plotbench/cvec_benchmark.cpp +++ b/misc/benchmarks/plotbench/cvec_benchmark.cpp @@ -12,7 +12,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 80000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 40000000, S = 0x3ffc, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp index bae9a42b..debff31d 100644 --- a/misc/benchmarks/shootout_hashmaps.cpp +++ b/misc/benchmarks/shootout_hashmaps.cpp @@ -35,7 +35,7 @@ KHASH_MAP_INIT_INT64(ii, IValue) // cmap template expansion #define i_key IKey #define i_val IValue -#define i_ssize int32_t // enable 2^K buckets like the rest. +//#define i_ssize int32_t // enable 2^K buckets like the rest. #define i_tag ii #define i_max_load_factor MAX_LOAD_FACTOR / 100.0f #include diff --git a/src/singleupdate.sh b/src/singleupdate.sh index d9a16568..9b1d37a0 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -1,27 +1,27 @@ -d=$(git rev-parse --show-toplevel) -mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc -python singleheader.py $d/include/c11/print.h > $d/../stcsingle/c11/print.h -python singleheader.py $d/include/stc/calgo.h > $d/../stcsingle/stc/calgo.h -python singleheader.py $d/include/stc/carc.h > $d/../stcsingle/stc/carc.h -python singleheader.py $d/include/stc/cbits.h > $d/../stcsingle/stc/cbits.h -python singleheader.py $d/include/stc/cbox.h > $d/../stcsingle/stc/cbox.h -python singleheader.py $d/include/stc/ccommon.h > $d/../stcsingle/stc/ccommon.h -python singleheader.py $d/include/stc/cdeq.h > $d/../stcsingle/stc/cdeq.h -python singleheader.py $d/include/stc/clist.h > $d/../stcsingle/stc/clist.h -python singleheader.py $d/include/stc/cmap.h > $d/../stcsingle/stc/cmap.h -python singleheader.py $d/include/stc/coption.h > $d/../stcsingle/stc/coption.h -python singleheader.py $d/include/stc/cpque.h > $d/../stcsingle/stc/cpque.h -python singleheader.py $d/include/stc/cqueue.h > $d/../stcsingle/stc/cqueue.h -python singleheader.py $d/include/stc/crand.h > $d/../stcsingle/stc/crand.h -python singleheader.py $d/include/stc/cregex.h > $d/../stcsingle/stc/cregex.h -python singleheader.py $d/include/stc/cset.h > $d/../stcsingle/stc/cset.h -python singleheader.py $d/include/stc/csmap.h > $d/../stcsingle/stc/csmap.h -python singleheader.py $d/include/stc/cspan.h > $d/../stcsingle/stc/cspan.h -python singleheader.py $d/include/stc/csset.h > $d/../stcsingle/stc/csset.h -python singleheader.py $d/include/stc/cstack.h > $d/../stcsingle/stc/cstack.h -python singleheader.py $d/include/stc/cstr.h > $d/../stcsingle/stc/cstr.h -python singleheader.py $d/include/stc/csview.h > $d/../stcsingle/stc/csview.h -python singleheader.py $d/include/stc/cvec.h > $d/../stcsingle/stc/cvec.h -python singleheader.py $d/include/stc/extend.h > $d/../stcsingle/stc/extend.h -python singleheader.py $d/include/stc/forward.h > $d/../stcsingle/stc/forward.h -echo "stcsingle headers updated" \ No newline at end of file +d=$(git rev-parse --show-toplevel) +mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc +python singleheader.py $d/include/c11/print.h > $d/../stcsingle/c11/print.h +python singleheader.py $d/include/stc/calgo.h > $d/../stcsingle/stc/calgo.h +python singleheader.py $d/include/stc/carc.h > $d/../stcsingle/stc/carc.h +python singleheader.py $d/include/stc/cbits.h > $d/../stcsingle/stc/cbits.h +python singleheader.py $d/include/stc/cbox.h > $d/../stcsingle/stc/cbox.h +python singleheader.py $d/include/stc/ccommon.h > $d/../stcsingle/stc/ccommon.h +python singleheader.py $d/include/stc/cdeq.h > $d/../stcsingle/stc/cdeq.h +python singleheader.py $d/include/stc/clist.h > $d/../stcsingle/stc/clist.h +python singleheader.py $d/include/stc/cmap.h > $d/../stcsingle/stc/cmap.h +python singleheader.py $d/include/stc/coption.h > $d/../stcsingle/stc/coption.h +python singleheader.py $d/include/stc/cpque.h > $d/../stcsingle/stc/cpque.h +python singleheader.py $d/include/stc/cqueue.h > $d/../stcsingle/stc/cqueue.h +python singleheader.py $d/include/stc/crand.h > $d/../stcsingle/stc/crand.h +python singleheader.py $d/include/stc/cregex.h > $d/../stcsingle/stc/cregex.h +python singleheader.py $d/include/stc/cset.h > $d/../stcsingle/stc/cset.h +python singleheader.py $d/include/stc/csmap.h > $d/../stcsingle/stc/csmap.h +python singleheader.py $d/include/stc/cspan.h > $d/../stcsingle/stc/cspan.h +python singleheader.py $d/include/stc/csset.h > $d/../stcsingle/stc/csset.h +python singleheader.py $d/include/stc/cstack.h > $d/../stcsingle/stc/cstack.h +python singleheader.py $d/include/stc/cstr.h > $d/../stcsingle/stc/cstr.h +python singleheader.py $d/include/stc/csview.h > $d/../stcsingle/stc/csview.h +python singleheader.py $d/include/stc/cvec.h > $d/../stcsingle/stc/cvec.h +python singleheader.py $d/include/stc/extend.h > $d/../stcsingle/stc/extend.h +python singleheader.py $d/include/stc/forward.h > $d/../stcsingle/stc/forward.h +echo "$d/../stcsingle headers updated" -- cgit v1.2.3 From a913490c248f6cfdca3481d81d6d344f4d066cb9 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 18 Apr 2023 17:48:47 +0200 Subject: Removed unneeded custom size type in maps and bits.h. Prepared for possible robin-hood impl. Improved sso_bench.c testing string hash - twice as fast as m.ankeln robin impl !?. --- docs/cmap_api.md | 2 +- docs/cset_api.md | 2 +- docs/csmap_api.md | 1 - docs/csset_api.md | 1 - include/stc/cbits.h | 70 ++-- include/stc/ccommon.h | 6 +- include/stc/cmap.h | 77 ++-- include/stc/csmap.h | 79 ++--- include/stc/forward.h | 23 +- include/stc/priv/template.h | 4 - include/stc/priv/template2.h | 1 - misc/benchmarks/external/ankerl/unordered_dense.h | 414 +++++++++++++++++++--- misc/benchmarks/external/emhash/hash_table7.hpp | 44 +-- misc/benchmarks/shootout_hashmaps.cpp | 2 +- misc/benchmarks/various/sso_bench.cpp | 134 ++++--- 15 files changed, 600 insertions(+), 260 deletions(-) diff --git a/docs/cmap_api.md b/docs/cmap_api.md index d2a94ee8..94f1c54e 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -36,7 +36,7 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain #define i_valto // convertion func i_val* => i_valraw #define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val -#define i_ssize // internal; default int32_t. If defined, table expand 2x (else 1.5x) +#define i_expandby // default 1. If 2, table expand 2x (else 1.5x) #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cset_api.md b/docs/cset_api.md index 026d7462..b9e8ae99 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -19,7 +19,7 @@ A **cset** is an associative container that contains a set of unique objects of #define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy #define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val -#define i_ssize // default int32_t. If defined, table expand 2x (else 1.5x) +#define i_expandby // default 1. If 2, table expand 2x (else 1.5x) #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 93faa4f9..3e643cee 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -33,7 +33,6 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo #define i_valto // convertion func i_val* => i_valraw #define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val -#define i_ssize // internal size rep. defaults to int32_t #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/csset_api.md b/docs/csset_api.md index e83ab857..d095696c 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -19,7 +19,6 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo #define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy #define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_val -#define i_ssize // defaults to int32_t #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/include/stc/cbits.h b/include/stc/cbits.h index 826df847..19e281a8 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -54,11 +54,8 @@ int main() { #include #include -#ifndef i_ssize -#define i_ssize intptr_t -#endif #define _cbits_bit(i) ((uint64_t)1 << ((i) & 63)) -#define _cbits_words(n) (i_ssize)(((n) + 63)>>6) +#define _cbits_words(n) (int64_t)(((n) + 63)>>6) #define _cbits_bytes(n) (_cbits_words(n) * c_sizeof(uint64_t)) #if defined(__GNUC__) @@ -80,23 +77,23 @@ int main() { } #endif -STC_INLINE i_ssize _cbits_count(const uint64_t* set, const i_ssize sz) { - const i_ssize n = sz>>6; - i_ssize count = 0; - for (i_ssize i = 0; i < n; ++i) +STC_INLINE int64_t _cbits_count(const uint64_t* set, const int64_t sz) { + const int64_t n = sz>>6; + int64_t count = 0; + for (int64_t i = 0; i < n; ++i) count += cpopcount64(set[i]); if (sz & 63) count += cpopcount64(set[n] & (_cbits_bit(sz) - 1)); return count; } -STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz, - char* out, i_ssize start, i_ssize stop) { +STC_INLINE char* _cbits_to_str(const uint64_t* set, const int64_t sz, + char* out, int64_t start, int64_t stop) { if (stop > sz) stop = sz; assert(start <= stop); c_memset(out, '0', stop - start); - for (i_ssize i = start; i < stop; ++i) + for (int64_t i = start; i < stop; ++i) if ((set[i>>6] & _cbits_bit(i)) != 0) out[i - start] = '1'; out[stop - start] = '\0'; @@ -104,8 +101,8 @@ STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz, } #define _cbits_OPR(OPR, VAL) \ - const i_ssize n = sz>>6; \ - for (i_ssize i = 0; i < n; ++i) \ + const int64_t n = sz>>6; \ + for (int64_t i = 0; i < n; ++i) \ if ((set[i] OPR other[i]) != VAL) \ return false; \ if (!(sz & 63)) \ @@ -113,10 +110,10 @@ STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz, const uint64_t i = (uint64_t)n, m = _cbits_bit(sz) - 1; \ return ((set[i] OPR other[i]) & m) == (VAL & m) -STC_INLINE bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const i_ssize sz) +STC_INLINE bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const int64_t sz) { _cbits_OPR(|, set[i]); } -STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const i_ssize sz) +STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const int64_t sz) { _cbits_OPR(&, 0); } #endif // CBITS_H_INCLUDED @@ -128,12 +125,12 @@ STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, cons #define _i_assert(x) assert(x) #define i_type cbits -struct { uint64_t *data64; i_ssize _size; } typedef i_type; +struct { uint64_t *data64; int64_t _size; } typedef i_type; STC_INLINE cbits cbits_init(void) { return c_LITERAL(cbits){NULL}; } STC_INLINE void cbits_create(cbits* self) { self->data64 = NULL; self->_size = 0; } STC_INLINE void cbits_drop(cbits* self) { c_free(self->data64); } -STC_INLINE i_ssize cbits_size(const cbits* self) { return self->_size; } +STC_INLINE int64_t cbits_size(const cbits* self) { return self->_size; } STC_INLINE cbits* cbits_take(cbits* self, cbits other) { if (self->data64 != other.data64) { @@ -144,7 +141,7 @@ STC_INLINE cbits* cbits_take(cbits* self, cbits other) { } STC_INLINE cbits cbits_clone(cbits other) { - const i_ssize bytes = _cbits_bytes(other._size); + const int64_t bytes = _cbits_bytes(other._size); cbits set = {(uint64_t *)c_memcpy(c_malloc(bytes), other.data64, bytes), other._size}; return set; } @@ -158,8 +155,8 @@ STC_INLINE cbits* cbits_copy(cbits* self, const cbits* other) { return self; } -STC_INLINE void cbits_resize(cbits* self, const i_ssize size, const bool value) { - const i_ssize new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize); +STC_INLINE void cbits_resize(cbits* self, const int64_t size, const bool value) { + const int64_t new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize); self->data64 = (uint64_t *)c_realloc(self->data64, new_n*8); self->_size = size; if (new_n >= old_n) { @@ -181,13 +178,13 @@ STC_INLINE cbits cbits_move(cbits* self) { return tmp; } -STC_INLINE cbits cbits_with_size(const i_ssize size, const bool value) { +STC_INLINE cbits cbits_with_size(const int64_t size, const bool value) { cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size}; cbits_set_all(&set, value); return set; } -STC_INLINE cbits cbits_with_pattern(const i_ssize size, const uint64_t pattern) { +STC_INLINE cbits cbits_with_pattern(const int64_t size, const uint64_t pattern) { cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size}; cbits_set_pattern(&set, pattern); return set; @@ -205,7 +202,7 @@ struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } typedef i_type; STC_INLINE i_type _i_memb(_init)(void) { return c_LITERAL(i_type){0}; } STC_INLINE void _i_memb(_create)(i_type* self) {} STC_INLINE void _i_memb(_drop)(i_type* self) {} -STC_INLINE i_ssize _i_memb(_size)(const i_type* self) { return i_capacity; } +STC_INLINE int64_t _i_memb(_size)(const i_type* self) { return i_capacity; } STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; } STC_INLINE i_type* _i_memb(_take)(i_type* self, i_type other) @@ -220,13 +217,13 @@ STC_INLINE i_type* _i_memb(_copy)(i_type* self, const i_type* other) STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value); STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern); -STC_INLINE i_type _i_memb(_with_size)(const i_ssize size, const bool value) { +STC_INLINE i_type _i_memb(_with_size)(const int64_t size, const bool value) { assert(size <= i_capacity); i_type set; _i_memb(_set_all)(&set, value); return set; } -STC_INLINE i_type _i_memb(_with_pattern)(const i_ssize size, const uint64_t pattern) { +STC_INLINE i_type _i_memb(_with_pattern)(const int64_t size, const uint64_t pattern) { assert(size <= i_capacity); i_type set; _i_memb(_set_pattern)(&set, pattern); return set; @@ -239,31 +236,31 @@ STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value) { c_memset(self->data64, value? ~0 : 0, _cbits_bytes(_i_memb(_size)(self))); } STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern) { - i_ssize n = _cbits_words(_i_memb(_size)(self)); + int64_t n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] = pattern; } -STC_INLINE bool _i_memb(_test)(const i_type* self, const i_ssize i) +STC_INLINE bool _i_memb(_test)(const i_type* self, const int64_t i) { return (self->data64[i>>6] & _cbits_bit(i)) != 0; } -STC_INLINE bool _i_memb(_at)(const i_type* self, const i_ssize i) +STC_INLINE bool _i_memb(_at)(const i_type* self, const int64_t i) { return (self->data64[i>>6] & _cbits_bit(i)) != 0; } -STC_INLINE void _i_memb(_set)(i_type *self, const i_ssize i) +STC_INLINE void _i_memb(_set)(i_type *self, const int64_t i) { self->data64[i>>6] |= _cbits_bit(i); } -STC_INLINE void _i_memb(_reset)(i_type *self, const i_ssize i) +STC_INLINE void _i_memb(_reset)(i_type *self, const int64_t i) { self->data64[i>>6] &= ~_cbits_bit(i); } -STC_INLINE void _i_memb(_set_value)(i_type *self, const i_ssize i, const bool b) { +STC_INLINE void _i_memb(_set_value)(i_type *self, const int64_t i, const bool b) { self->data64[i>>6] ^= ((uint64_t)-(int)b ^ self->data64[i>>6]) & _cbits_bit(i); } -STC_INLINE void _i_memb(_flip)(i_type *self, const i_ssize i) +STC_INLINE void _i_memb(_flip)(i_type *self, const int64_t i) { self->data64[i>>6] ^= _cbits_bit(i); } STC_INLINE void _i_memb(_flip_all)(i_type *self) { - i_ssize n = _cbits_words(_i_memb(_size)(self)); + int64_t n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] ^= ~(uint64_t)0; } @@ -277,19 +274,19 @@ STC_INLINE i_type _i_memb(_from)(const char* str) { /* Intersection */ STC_INLINE void _i_memb(_intersect)(i_type *self, const i_type* other) { _i_assert(self->_size == other->_size); - i_ssize n = _cbits_words(_i_memb(_size)(self)); + int64_t n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] &= other->data64[n]; } /* Union */ STC_INLINE void _i_memb(_union)(i_type *self, const i_type* other) { _i_assert(self->_size == other->_size); - i_ssize n = _cbits_words(_i_memb(_size)(self)); + int64_t n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] |= other->data64[n]; } /* Exclusive disjunction */ STC_INLINE void _i_memb(_xor)(i_type *self, const i_type* other) { _i_assert(self->_size == other->_size); - i_ssize n = _cbits_words(_i_memb(_size)(self)); + int64_t n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] ^= other->data64[n]; } @@ -312,7 +309,6 @@ STC_INLINE bool _i_memb(_disjoint)(const i_type* self, const i_type* other) { #pragma GCC diagnostic pop #endif #define CBITS_H_INCLUDED -#undef _i_size #undef _i_memb #undef _i_assert #undef i_capacity diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index bc12e642..0735e855 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -147,13 +147,13 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { case 0: return 1; } const uint8_t *x = (const uint8_t*)key; - uint64_t h = 0xcbf29ce484222325 + *x*0x811c9dc5UL, n = (uint64_t)len >> 3; + uint64_t h = *x*0x811c9dc5ULL, n = (uint64_t)len >> 3; len &= 7; while (n--) { memcpy(&u8, x, 8), x += 8; - h = (h ^ u8)*0x01000193UL; + h = (h ^ u8)*0x01000193ULL; } - while (len--) h = (h ^ *x++)*0x01000193UL; + while (len--) h = (h ^ *x++)*0x01000193ULL; return h; } diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 14782b71..cfed5540 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -73,17 +73,12 @@ typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t; #ifndef i_max_load_factor #define i_max_load_factor 0.85f #endif -#ifndef i_ssize - #define i_ssize int32_t - #define _i_size intptr_t - #define _i_expandby 1 -#else - #define _i_expandby 2 - #define _i_size i_ssize +#ifndef i_expandby + #define i_expandby 1 #endif #include "priv/template.h" #ifndef i_is_forward - _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); + _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); #endif _i_MAP_ONLY( struct _cx_value { @@ -98,25 +93,25 @@ typedef _i_SET_ONLY( i_keyraw ) i_valraw second; } ) _cx_raw; -STC_API _cx_self _cx_memb(_with_capacity)(_i_size cap); +STC_API _cx_self _cx_memb(_with_capacity)(intptr_t cap); #if !defined i_no_clone STC_API _cx_self _cx_memb(_clone)(_cx_self map); #endif STC_API void _cx_memb(_drop)(_cx_self* self); STC_API void _cx_memb(_clear)(_cx_self* self); -STC_API bool _cx_memb(_reserve)(_cx_self* self, _i_size capacity); +STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t capacity); STC_API chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr); STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey); STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val); STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self map = {0}; return map; } -STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, self->size); } +STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, (intptr_t)self->size); } STC_INLINE float _cx_memb(_max_load_factor)(const _cx_self* self) { return (float)(i_max_load_factor); } STC_INLINE bool _cx_memb(_empty)(const _cx_self* map) { return !map->size; } -STC_INLINE _i_size _cx_memb(_size)(const _cx_self* map) { return map->size; } -STC_INLINE _i_size _cx_memb(_bucket_count)(_cx_self* map) { return map->bucket_count; } -STC_INLINE _i_size _cx_memb(_capacity)(const _cx_self* map) - { return (_i_size)((float)map->bucket_count * (i_max_load_factor)); } +STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* map) { return (intptr_t)map->size; } +STC_INLINE intptr_t _cx_memb(_bucket_count)(_cx_self* map) { return map->bucket.count; } +STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* map) + { return (intptr_t)((float)map->bucket.count * (i_max_load_factor)); } STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) { return self->size && self->_hashx[_cx_memb(_bucket_)(self, &rkey).idx]; } @@ -197,7 +192,7 @@ _cx_memb(_push)(_cx_self* self, _cx_value _val) { return _res; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) { +STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) { while (n--) #if defined _i_isset && defined i_no_emplace _cx_memb(_insert)(self, *raw++); @@ -210,11 +205,11 @@ STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) #endif } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, _i_size n) +STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { - _cx_iter it = {self->table, self->table+self->bucket_count, self->_hashx}; + _cx_iter it = {self->table, self->table+self->bucket.count, self->_hashx}; if (it._hx) while (*it._hx == 0) ++it.ref, ++it._hx; @@ -243,7 +238,7 @@ _cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) { int64_t idx; if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]) return c_LITERAL(_cx_iter){self->table + idx, - self->table + self->bucket_count, + self->table + self->bucket.count, self->_hashx + idx}; return _cx_memb(_end)(self); } @@ -306,7 +301,7 @@ STC_INLINE uint64_t next_power_of_2(uint64_t n) { #endif // CMAP_H_INCLUDED STC_DEF _cx_self -_cx_memb(_with_capacity)(const _i_size cap) { +_cx_memb(_with_capacity)(const intptr_t cap) { _cx_self h = {0}; _cx_memb(_reserve)(&h, cap); return h; @@ -315,7 +310,7 @@ _cx_memb(_with_capacity)(const _i_size cap) { STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) { if (self->size == 0) return; - _cx_value* e = self->table, *end = e + self->bucket_count; + _cx_value* e = self->table, *end = e + self->bucket.count; uint8_t *hx = self->_hashx; for (; e != end; ++e) if (*hx++) @@ -331,7 +326,7 @@ STC_DEF void _cx_memb(_drop)(_cx_self* self) { STC_DEF void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_wipe_)(self); self->size = 0; - c_memset(self->_hashx, 0, self->bucket_count); + c_memset(self->_hashx, 0, self->bucket.count); } #ifndef _i_isset @@ -366,8 +361,8 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) { STC_DEF chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); - int64_t _cap = self->bucket_count; - chash_bucket_t b = {c_PASTE(fastrange_,_i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; + int64_t _cap = self->bucket.count; + chash_bucket_t b = {c_PASTE(fastrange_,i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; const uint8_t* _hx = self->_hashx; while (_hx[b.idx]) { if (_hx[b.idx] == b.hx) { @@ -384,8 +379,8 @@ _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { STC_DEF _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { _cx_result res = {NULL}; - if (self->size + 2 > (i_ssize)((float)self->bucket_count * (i_max_load_factor))) - if (!_cx_memb(_reserve)(self, self->size*3/2)) + if (self->size + 2 > (intptr_t)((float)self->bucket.count * (i_max_load_factor))) + if (!_cx_memb(_reserve)(self, (intptr_t)(self->size*3/2))) return res; chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); @@ -401,11 +396,11 @@ _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { STC_DEF _cx_self _cx_memb(_clone)(_cx_self m) { if (m.table) { - _cx_value *t = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count), - *dst = t, *m_end = m.table + m.bucket_count; - uint8_t *h = (uint8_t *)c_memcpy(i_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1); + _cx_value *t = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket.count), + *dst = t, *m_end = m.table + m.bucket.count; + uint8_t *h = (uint8_t *)c_memcpy(i_malloc(m.bucket.count + 1), m._hashx, m.bucket.count + 1); if (!(t && h)) - { i_free(t), i_free(h), t = 0, h = 0, m.bucket_count = 0; } + { i_free(t), i_free(h), t = 0, h = 0, m.bucket.count = 0; } else for (; m.table != m_end; ++m.table, ++m._hashx, ++dst) if (*m._hashx) @@ -417,27 +412,27 @@ _cx_memb(_clone)(_cx_self m) { #endif STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const _i_size newcap) { - const i_ssize _oldbuckets = self->bucket_count, _newcap = (i_ssize)newcap; +_cx_memb(_reserve)(_cx_self* self, const intptr_t newcap) { + const intptr_t _oldbuckets = self->bucket.count, _newcap = newcap; if (_newcap != self->size && _newcap <= _oldbuckets) return true; - i_ssize _nbuckets = (i_ssize)((float)_newcap / (i_max_load_factor)) + 4; - #if _i_expandby == 2 - _nbuckets = (i_ssize)next_power_of_2(_nbuckets); + uintptr_t _nbuckets = (uintptr_t)((float)_newcap / (i_max_load_factor)) + 4; + #if i_expandby == 2 + _nbuckets = (intptr_t)next_power_of_2(_nbuckets); #else _nbuckets |= 1; #endif _cx_self m = { (_cx_value *)i_malloc(c_sizeof(_cx_value)*_nbuckets), (uint8_t *)i_calloc(_nbuckets + 1, 1), - self->size, _nbuckets, + self->size, {_nbuckets & ((1ULL << 48) - 1)} }; bool ok = m.table && m._hashx; if (ok) { /* Rehash: */ m._hashx[_nbuckets] = 0xff; const _cx_value* e = self->table; const uint8_t* h = self->_hashx; - for (i_ssize i = 0; i < _oldbuckets; ++i, ++e) if (*h++) { + for (intptr_t i = 0; i < _oldbuckets; ++i, ++e) if (*h++) { _cx_keyraw r = i_keyto(_i_keyref(e)); chash_bucket_t b = _cx_memb(_bucket_)(&m, &r); m.table[b.idx] = *e; @@ -452,8 +447,8 @@ _cx_memb(_reserve)(_cx_self* self, const _i_size newcap) { STC_DEF void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { - i_ssize i = (i_ssize)(_val - self->table), j = i, k; - const i_ssize _cap = self->bucket_count; + intptr_t i = (intptr_t)(_val - self->table), j = i, k; + const intptr_t _cap = self->bucket.count; _cx_value* _slot = self->table; uint8_t* _hashx = self->_hashx; _cx_memb(_value_drop)(_val); @@ -463,7 +458,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { if (! _hashx[j]) break; const _cx_keyraw _raw = i_keyto(_i_keyref(_slot + j)); - k = (i_ssize)c_PASTE(fastrange_,_i_expandby)(i_hash((&_raw)), (uint64_t)_cap); + k = (intptr_t)c_PASTE(fastrange_,i_expandby)(i_hash((&_raw)), (uint64_t)_cap); if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ _slot[i] = _slot[j], _hashx[i] = _hashx[j], i = j; } @@ -473,7 +468,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { #endif // i_implement #undef i_max_load_factor -#undef _i_size +#undef i_expandby #undef _i_isset #undef _i_ismap #undef _i_ishash diff --git a/include/stc/csmap.h b/include/stc/csmap.h index ebfe8d44..dc0387f7 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -70,15 +70,9 @@ int main(void) { #define _i_SET_ONLY c_false #define _i_keyref(vp) (&(vp)->first) #endif -#ifndef i_ssize - #define i_ssize int32_t - #define _i_size intptr_t -#else - #define _i_size i_ssize -#endif #include "priv/template.h" #ifndef i_is_forward - _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); + _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); #endif _i_MAP_ONLY( struct _cx_value { @@ -86,7 +80,7 @@ _i_MAP_ONLY( struct _cx_value { _cx_mapped second; }; ) struct _cx_node { - i_ssize link[2]; + int32_t link[2]; int8_t level; _cx_value value; }; @@ -106,7 +100,7 @@ STC_API _cx_self _cx_memb(_clone)(_cx_self tree); STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)); STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val); STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API bool _cx_memb(_reserve)(_cx_self* self, _i_size cap); +STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t cap); STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out); STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey); STC_API _cx_value* _cx_memb(_front)(const _cx_self* self); @@ -118,8 +112,8 @@ STC_API void _cx_memb(_next)(_cx_iter* it); STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self tree = {0}; return tree; } STC_INLINE bool _cx_memb(_empty)(const _cx_self* cx) { return cx->size == 0; } -STC_INLINE _i_size _cx_memb(_size)(const _cx_self* cx) { return cx->size; } -STC_INLINE _i_size _cx_memb(_capacity)(const _cx_self* cx) { return cx->cap; } +STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* cx) { return cx->size; } +STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* cx) { return cx->cap; } STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; } STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) @@ -130,7 +124,7 @@ STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey) { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); } STC_INLINE _cx_self -_cx_memb(_with_capacity)(const _i_size cap) { +_cx_memb(_with_capacity)(const intptr_t cap) { _cx_self tree = _cx_memb(_init)(); _cx_memb(_reserve)(&tree, cap); return tree; @@ -226,7 +220,7 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { return true; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) { +STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) { while (n--) #if defined _i_isset && defined i_no_emplace _cx_memb(_insert)(self, *raw++); @@ -239,14 +233,14 @@ STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) #endif } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, _i_size n) +STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const _i_size cap) { +_cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { if (cap <= self->cap) return false; _cx_node* nodes = (_cx_node*)i_realloc(self->nodes, (cap + 1)*c_sizeof(_cx_node)); @@ -254,14 +248,14 @@ _cx_memb(_reserve)(_cx_self* self, const _i_size cap) { return false; nodes[0] = c_LITERAL(_cx_node){{0, 0}, 0}; self->nodes = nodes; - self->cap = (i_ssize)cap; + self->cap = (int32_t)cap; return true; } STC_DEF _cx_value* _cx_memb(_front)(const _cx_self* self) { _cx_node *d = self->nodes; - i_ssize tn = self->root; + int32_t tn = self->root; while (d[tn].link[0]) tn = d[tn].link[0]; return &d[tn].value; @@ -270,15 +264,15 @@ _cx_memb(_front)(const _cx_self* self) { STC_DEF _cx_value* _cx_memb(_back)(const _cx_self* self) { _cx_node *d = self->nodes; - i_ssize tn = self->root; + int32_t tn = self->root; while (d[tn].link[1]) tn = d[tn].link[1]; return &d[tn].value; } -static i_ssize +static int32_t _cx_memb(_new_node_)(_cx_self* self, int level) { - i_ssize tn; + int32_t tn; if (self->disp) { tn = self->disp; self->disp = self->nodes[tn].link[1]; @@ -346,7 +340,7 @@ _cx_memb(_push)(_cx_self* self, _cx_value _val) { STC_DEF _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out) { - i_ssize tn = self->root; + int32_t tn = self->root; _cx_node *d = out->_d = self->nodes; out->_top = 0; while (tn) { @@ -366,7 +360,7 @@ _cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey) { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); if (!it.ref && it._top) { - i_ssize tn = it._st[--it._top]; + int32_t tn = it._st[--it._top]; it._tn = it._d[tn].link[1]; it.ref = &it._d[tn].value; } @@ -375,7 +369,7 @@ _cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey) { STC_DEF void _cx_memb(_next)(_cx_iter *it) { - i_ssize tn = it->_tn; + int32_t tn = it->_tn; if (it->_top || tn) { while (tn) { it->_st[it->_top++] = tn; @@ -388,10 +382,10 @@ _cx_memb(_next)(_cx_iter *it) { it->ref = NULL; } -STC_DEF i_ssize -_cx_memb(_skew_)(_cx_node *d, i_ssize tn) { +STC_DEF int32_t +_cx_memb(_skew_)(_cx_node *d, int32_t tn) { if (tn && d[d[tn].link[0]].level == d[tn].level) { - i_ssize tmp = d[tn].link[0]; + int32_t tmp = d[tn].link[0]; d[tn].link[0] = d[tmp].link[1]; d[tmp].link[1] = tn; tn = tmp; @@ -399,10 +393,10 @@ _cx_memb(_skew_)(_cx_node *d, i_ssize tn) { return tn; } -STC_DEF i_ssize -_cx_memb(_split_)(_cx_node *d, i_ssize tn) { +STC_DEF int32_t +_cx_memb(_split_)(_cx_node *d, int32_t tn) { if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) { - i_ssize tmp = d[tn].link[1]; + int32_t tmp = d[tn].link[1]; d[tn].link[1] = d[tmp].link[0]; d[tmp].link[0] = tn; tn = tmp; @@ -411,9 +405,9 @@ _cx_memb(_split_)(_cx_node *d, i_ssize tn) { return tn; } -static i_ssize -_cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _cx_result* _res) { - i_ssize up[64], tx = tn; +static int32_t +_cx_memb(_insert_entry_i_)(_cx_self* self, int32_t tn, const _cx_keyraw* rkey, _cx_result* _res) { + int32_t up[64], tx = tn; _cx_node* d = self->nodes; int c, top = 0, dir = 0; while (tx) { @@ -446,19 +440,19 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _ static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { _cx_result res = {NULL}; - i_ssize tn = _cx_memb(_insert_entry_i_)(self, self->root, &rkey, &res); + int32_t tn = _cx_memb(_insert_entry_i_)(self, self->root, &rkey, &res); self->root = tn; self->size += res.inserted; return res; } -static i_ssize -_cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_keyraw* rkey, int *erased) { +static int32_t +_cx_memb(_erase_r_)(_cx_self *self, int32_t tn, const _cx_keyraw* rkey, int *erased) { _cx_node *d = self->nodes; if (tn == 0) return 0; _cx_keyraw raw = i_keyto(_i_keyref(&d[tn].value)); - i_ssize tx; int c = i_cmp((&raw), rkey); + int32_t tx; int c = i_cmp((&raw), rkey); if (c != 0) d[tn].link[c < 0] = _cx_memb(_erase_r_)(self, d[tn].link[c < 0], rkey, erased); else { @@ -495,7 +489,7 @@ _cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_keyraw* rkey, int *era STC_DEF int _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { int erased = 0; - i_ssize root = _cx_memb(_erase_r_)(self, self->root, &rkey, &erased); + int32_t root = _cx_memb(_erase_r_)(self, self->root, &rkey, &erased); if (!erased) return 0; self->root = root; @@ -537,11 +531,11 @@ _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { } #if !defined i_no_clone -static i_ssize -_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_ssize sn) { +static int32_t +_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, int32_t sn) { if (sn == 0) return 0; - i_ssize tx, tn = _cx_memb(_new_node_)(self, src[sn].level); + int32_t tx, tn = _cx_memb(_new_node_)(self, src[sn].level); self->nodes[tn].value = _cx_memb(_value_clone)(src[sn].value); tx = _cx_memb(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx; tx = _cx_memb(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx; @@ -551,7 +545,7 @@ _cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_ssize sn) { STC_DEF _cx_self _cx_memb(_clone)(_cx_self tree) { _cx_self clone = _cx_memb(_with_capacity)(tree.size); - i_ssize root = _cx_memb(_clone_r_)(&clone, tree.nodes, tree.root); + int32_t root = _cx_memb(_clone_r_)(&clone, tree.nodes, tree.root); clone.root = root; clone.size = tree.size; return clone; @@ -571,7 +565,7 @@ _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe #endif // i_no_emplace static void -_cx_memb(_drop_r_)(_cx_node* d, i_ssize tn) { +_cx_memb(_drop_r_)(_cx_node* d, int32_t tn) { if (tn) { _cx_memb(_drop_r_)(d, d[tn].link[0]); _cx_memb(_drop_r_)(d, d[tn].link[1]); @@ -588,7 +582,6 @@ _cx_memb(_drop)(_cx_self* self) { } #endif // i_implement -#undef _i_size #undef _i_isset #undef _i_ismap #undef _i_keyref diff --git a/include/stc/forward.h b/include/stc/forward.h index 31e67e7d..e543b94a 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -29,12 +29,10 @@ #define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL) #define forward_cdeq(CX, VAL) _c_cdeq_types(CX, VAL) #define forward_clist(CX, VAL) _c_clist_types(CX, VAL) -#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, int32_t, c_true, c_false) -#define forward_cmap64(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, int64_t, c_true, c_false) -#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, int32_t, c_false, c_true) -#define forward_cset64(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, int64_t, c_false, c_true) -#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, int32_t, c_true, c_false) -#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, int32_t, c_false, c_true) +#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, c_true, c_false) +#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, c_false, c_true) +#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, c_true, c_false) +#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, c_false, c_true) #define forward_cstack(CX, VAL) _c_cstack_types(CX, VAL) #define forward_cpque(CX, VAL) _c_cpque_types(CX, VAL) #define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL) @@ -103,10 +101,9 @@ typedef union { SELF##_node *last; \ } SELF -#define _c_chash_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \ +#define _c_chash_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \ typedef KEY SELF##_key; \ typedef VAL SELF##_mapped; \ - typedef SZ SELF##_ssize; \ \ typedef SET_ONLY( SELF##_key ) \ MAP_ONLY( struct SELF##_value ) \ @@ -125,13 +122,13 @@ typedef union { typedef struct SELF { \ SELF##_value* table; \ uint8_t* _hashx; \ - SELF##_ssize size, bucket_count; \ + intptr_t size; \ + struct { uint64_t count: 48, maxdist: 16; } bucket; \ } SELF -#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \ +#define _c_aatree_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \ typedef KEY SELF##_key; \ typedef VAL SELF##_mapped; \ - typedef SZ SELF##_ssize; \ typedef struct SELF##_node SELF##_node; \ \ typedef SET_ONLY( SELF##_key ) \ @@ -147,12 +144,12 @@ typedef union { SELF##_value *ref; \ SELF##_node *_d; \ int _top; \ - SELF##_ssize _tn, _st[36]; \ + int32_t _tn, _st[36]; \ } SELF##_iter; \ \ typedef struct SELF { \ SELF##_node *nodes; \ - SELF##_ssize root, disp, head, size, cap; \ + int32_t root, disp, head, size, cap; \ } SELF #define _c_cstack_fixed(SELF, VAL, CAP) \ diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 16ef51af..2605a434 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -44,10 +44,6 @@ #define i_type c_PASTE(_i_prefix, i_tag) #endif -#ifndef i_ssize - #define i_ssize intptr_t -#endif - #ifndef i_allocator #define i_allocator c #endif diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 27c6a890..2e8a6c8d 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -30,7 +30,6 @@ #undef i_hash #undef i_rawclass #undef i_capacity -#undef i_ssize #undef i_val #undef i_val_str diff --git a/misc/benchmarks/external/ankerl/unordered_dense.h b/misc/benchmarks/external/ankerl/unordered_dense.h index faad051d..dc4de8ab 100644 --- a/misc/benchmarks/external/ankerl/unordered_dense.h +++ b/misc/benchmarks/external/ankerl/unordered_dense.h @@ -1,7 +1,7 @@ ///////////////////////// ankerl::unordered_dense::{map, set} ///////////////////////// // A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion. -// Version 3.1.0 +// Version 4.0.0 // https://github.com/martinus/unordered_dense // // Licensed under the MIT License . @@ -30,12 +30,15 @@ #define ANKERL_UNORDERED_DENSE_H // see https://semver.org/spec/v2.0.0.html -#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 3 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes -#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 1 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality +#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 4 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes +#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality #define ANKERL_UNORDERED_DENSE_VERSION_PATCH 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes // API versioning with inline namespace, see https://www.foonathan.net/2018/11/inline-namespaces/ + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch) v##major##_##minor##_##patch +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define ANKERL_UNORDERED_DENSE_VERSION_CONCAT(major, minor, patch) ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch) #define ANKERL_UNORDERED_DENSE_NAMESPACE \ ANKERL_UNORDERED_DENSE_VERSION_CONCAT( \ @@ -57,9 +60,9 @@ // exceptions #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) -# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1 +# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1 // NOLINT(cppcoreguidelines-macro-usage) #else -# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0 +# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0 // NOLINT(cppcoreguidelines-macro-usage) #endif #ifdef _MSC_VER # define ANKERL_UNORDERED_DENSE_NOINLINE __declspec(noinline) @@ -89,20 +92,13 @@ # include // for abort # endif -# define ANKERL_UNORDERED_DENSE_PMR 0 // NOLINT(cppcoreguidelines-macro-usage) # if defined(__has_include) # if __has_include() -# undef ANKERL_UNORDERED_DENSE_PMR -# define ANKERL_UNORDERED_DENSE_PMR 1 // NOLINT(cppcoreguidelines-macro-usage) -# define ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR \ - std::pmr::polymorphic_allocator // NOLINT(cppcoreguidelines-macro-usage) -# include // for polymorphic_allocator +# define ANKERL_UNORDERED_DENSE_PMR std::pmr // NOLINT(cppcoreguidelines-macro-usage) +# include // for polymorphic_allocator # elif __has_include() -# undef ANKERL_UNORDERED_DENSE_PMR -# define ANKERL_UNORDERED_DENSE_PMR 1 // NOLINT(cppcoreguidelines-macro-usage) -# define ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR \ - std::experimental::pmr::polymorphic_allocator // NOLINT(cppcoreguidelines-macro-usage) -# include // for polymorphic_allocator +# define ANKERL_UNORDERED_DENSE_PMR std::experimental::pmr // NOLINT(cppcoreguidelines-macro-usage) +# include // for polymorphic_allocator # endif # endif @@ -428,7 +424,7 @@ constexpr bool is_map_v = !std::is_void_v; // clang-format off template -constexpr bool is_transparent_v = is_detected_v&& is_detected_v; +constexpr bool is_transparent_v = is_detected_v && is_detected_v; // clang-format on template @@ -446,19 +442,320 @@ struct base_table_type_map { // base type for set doesn't have mapped_type struct base_table_type_set {}; +} // namespace detail + +// Very much like std::deque, but faster for indexing (in most cases). As of now this doesn't implement the full std::vector +// API, but merely what's necessary to work as an underlying container for ankerl::unordered_dense::{map, set}. +// It allocates blocks of equal size and puts them into the m_blocks vector. That means it can grow simply by adding a new +// block to the back of m_blocks, and doesn't double its size like an std::vector. The disadvantage is that memory is not +// linear and thus there is one more indirection necessary for indexing. +template , size_t MaxSegmentSizeBytes = 4096> +class segmented_vector { + template + class iter_t; + +public: + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using difference_type = typename std::allocator_traits::difference_type; + using value_type = T; + using size_type = std::size_t; + using reference = T&; + using const_reference = T const&; + using iterator = iter_t; + using const_iterator = iter_t; + +private: + using vec_alloc = typename std::allocator_traits::template rebind_alloc; + std::vector m_blocks{}; + size_t m_size{}; + + // Calculates the maximum number for x in (s << x) <= max_val + static constexpr auto num_bits_closest(size_t max_val, size_t s) -> size_t { + auto f = size_t{0}; + while (s << (f + 1) <= max_val) { + ++f; + } + return f; + } + + using self_t = segmented_vector; + static constexpr auto num_bits = num_bits_closest(MaxSegmentSizeBytes, sizeof(T)); + static constexpr auto num_elements_in_block = 1U << num_bits; + static constexpr auto mask = num_elements_in_block - 1U; + + /** + * Iterator class doubles as const_iterator and iterator + */ + template + class iter_t { + using ptr_t = typename std::conditional_t; + ptr_t m_data{}; + size_t m_idx{}; + + template + friend class iter_t; + + public: + using difference_type = segmented_vector::difference_type; + using value_type = T; + using reference = typename std::conditional_t; + using pointer = typename std::conditional_t; + using iterator_category = std::forward_iterator_tag; + + iter_t() noexcept = default; + + template ::type> + // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) + constexpr iter_t(iter_t const& other) noexcept + : m_data(other.m_data) + , m_idx(other.m_idx) {} + + constexpr iter_t(ptr_t data, size_t idx) noexcept + : m_data(data) + , m_idx(idx) {} + + template ::type> + constexpr auto operator=(iter_t const& other) noexcept -> iter_t& { + m_data = other.m_data; + m_idx = other.m_idx; + return *this; + } + + constexpr auto operator++() noexcept -> iter_t& { + ++m_idx; + return *this; + } + + constexpr auto operator+(difference_type diff) noexcept -> iter_t { + return {m_data, static_cast(static_cast(m_idx) + diff)}; + } + + template + constexpr auto operator-(iter_t const& other) noexcept -> difference_type { + return static_cast(m_idx) - static_cast(other.m_idx); + } + + constexpr auto operator*() const noexcept -> reference { + return m_data[m_idx >> num_bits][m_idx & mask]; + } + + constexpr auto operator->() const noexcept -> pointer { + return &m_data[m_idx >> num_bits][m_idx & mask]; + } + + template + constexpr auto operator==(iter_t const& o) const noexcept -> bool { + return m_idx == o.m_idx; + } + + template + constexpr auto operator!=(iter_t const& o) const noexcept -> bool { + return !(*this == o); + } + }; + + // slow path: need to allocate a new segment every once in a while + void increase_capacity() { + auto ba = Allocator(m_blocks.get_allocator()); + pointer block = std::allocator_traits::allocate(ba, num_elements_in_block); + m_blocks.push_back(block); + } + + // Moves everything from other + void append_everything_from(segmented_vector&& other) { + reserve(size() + other.size()); + for (auto&& o : other) { + emplace_back(std::move(o)); + } + } + + // Copies everything from other + void append_everything_from(segmented_vector const& other) { + reserve(size() + other.size()); + for (auto const& o : other) { + emplace_back(o); + } + } + + void dealloc() { + auto ba = Allocator(m_blocks.get_allocator()); + for (auto ptr : m_blocks) { + std::allocator_traits::deallocate(ba, ptr, num_elements_in_block); + } + } + + [[nodiscard]] static constexpr auto calc_num_blocks_for_capacity(size_t capacity) { + return (capacity + num_elements_in_block - 1U) / num_elements_in_block; + } + +public: + segmented_vector() = default; + + // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) + segmented_vector(Allocator alloc) + : m_blocks(vec_alloc(alloc)) {} + + segmented_vector(segmented_vector&& other, Allocator alloc) + : m_blocks(vec_alloc(alloc)) { + if (other.get_allocator() == alloc) { + *this = std::move(other); + } else { + // Oh my, allocator is different so we need to copy everything. + append_everything_from(std::move(other)); + } + } + + segmented_vector(segmented_vector&& other) noexcept + : m_blocks(std::move(other.m_blocks)) + , m_size(std::exchange(other.m_size, {})) {} + + segmented_vector(segmented_vector const& other, Allocator alloc) + : m_blocks(vec_alloc(alloc)) { + append_everything_from(other); + } + + segmented_vector(segmented_vector const& other) { + append_everything_from(other); + } + + auto operator=(segmented_vector const& other) -> segmented_vector& { + if (this == &other) { + return *this; + } + clear(); + append_everything_from(other); + return *this; + } + + auto operator=(segmented_vector&& other) noexcept -> segmented_vector& { + clear(); + dealloc(); + m_blocks = std::move(other.m_blocks); + m_size = std::exchange(other.m_size, {}); + return *this; + } + + ~segmented_vector() { + clear(); + dealloc(); + } + + [[nodiscard]] constexpr auto size() const -> size_t { + return m_size; + } + + [[nodiscard]] constexpr auto capacity() const -> size_t { + return m_blocks.size() * num_elements_in_block; + } + + // Indexing is highly performance critical + [[nodiscard]] constexpr auto operator[](size_t i) const noexcept -> T const& { + return m_blocks[i >> num_bits][i & mask]; + } + + [[nodiscard]] constexpr auto operator[](size_t i) noexcept -> T& { + return m_blocks[i >> num_bits][i & mask]; + } + + [[nodiscard]] constexpr auto begin() -> iterator { + return {m_blocks.data(), 0U}; + } + [[nodiscard]] constexpr auto begin() const -> const_iterator { + return {m_blocks.data(), 0U}; + } + [[nodiscard]] constexpr auto cbegin() const -> const_iterator { + return {m_blocks.data(), 0U}; + } + + [[nodiscard]] constexpr auto end() -> iterator { + return {m_blocks.data(), m_size}; + } + [[nodiscard]] constexpr auto end() const -> const_iterator { + return {m_blocks.data(), m_size}; + } + [[nodiscard]] constexpr auto cend() const -> const_iterator { + return {m_blocks.data(), m_size}; + } + + [[nodiscard]] constexpr auto back() -> reference { + return operator[](m_size - 1); + } + [[nodiscard]] constexpr auto back() const -> const_reference { + return operator[](m_size - 1); + } + + void pop_back() { + back().~T(); + --m_size; + } + + [[nodiscard]] auto empty() const { + return 0 == m_size; + } + + void reserve(size_t new_capacity) { + m_blocks.reserve(calc_num_blocks_for_capacity(new_capacity)); + while (new_capacity > capacity()) { + increase_capacity(); + } + } + + [[nodiscard]] auto get_allocator() const -> allocator_type { + return allocator_type{m_blocks.get_allocator()}; + } + + template + auto emplace_back(Args&&... args) -> reference { + if (m_size == capacity()) { + increase_capacity(); + } + auto* ptr = static_cast(&operator[](m_size)); + auto& ref = *new (ptr) T(std::forward(args)...); + ++m_size; + return ref; + } + + void clear() { + if constexpr (!std::is_trivially_destructible_v) { + for (size_t i = 0, s = size(); i < s; ++i) { + operator[](i).~T(); + } + } + m_size = 0; + } + + void shrink_to_fit() { + auto ba = Allocator(m_blocks.get_allocator()); + auto num_blocks_required = calc_num_blocks_for_capacity(m_size); + while (m_blocks.size() > num_blocks_required) { + std::allocator_traits::deallocate(ba, m_blocks.back(), num_elements_in_block); + m_blocks.pop_back(); + } + m_blocks.shrink_to_fit(); + } +}; + +namespace detail { + // This is it, the table. Doubles as map and set, and uses `void` for T when its used as a set. template + class Bucket, + bool IsSegmented> class table : public std::conditional_t, base_table_type_map, base_table_type_set> { + using underlying_value_type = typename std::conditional_t, std::pair, Key>; + using underlying_container_type = std::conditional_t, + std::vector>; + public: - using value_container_type = std::conditional_t< - is_detected_v, - AllocatorOrContainer, - typename std::vector, std::pair, Key>, AllocatorOrContainer>>; + using value_container_type = std:: + conditional_t, AllocatorOrContainer, underlying_container_type>; private: using bucket_alloc = @@ -492,7 +789,8 @@ private: static_assert(std::is_trivially_copyable_v, "assert we can just memset / memcpy"); value_container_type m_values{}; // Contains all the key-value pairs in one densely stored container. No holes. - typename std::allocator_traits::pointer m_buckets{}; + using bucket_pointer = typename std::allocator_traits::pointer; + bucket_pointer m_buckets{}; size_t m_num_buckets = 0; size_t m_max_bucket_capacity = 0; float m_max_load_factor = default_max_load_factor; @@ -507,8 +805,7 @@ private: } // Helper to access bucket through pointer types - [[nodiscard]] static constexpr auto at(typename std::allocator_traits::pointer bucket_ptr, size_t offset) - -> Bucket& { + [[nodiscard]] static constexpr auto at(bucket_pointer bucket_ptr, size_t offset) -> Bucket& { return *(bucket_ptr + static_cast::difference_type>(offset)); } @@ -578,7 +875,7 @@ private: } [[nodiscard]] static constexpr auto calc_num_buckets(uint8_t shifts) -> size_t { - return std::min(max_bucket_count(), size_t{1} << (64U - shifts)); + return (std::min)(max_bucket_count(), size_t{1} << (64U - shifts)); } [[nodiscard]] constexpr auto calc_shifts_for_size(size_t s) const -> uint8_t { @@ -983,7 +1280,7 @@ public: } [[nodiscard]] static constexpr auto max_size() noexcept -> size_t { - if constexpr (std::numeric_limits::max() == std::numeric_limits::max()) { + if constexpr ((std::numeric_limits::max)() == (std::numeric_limits::max)()) { return size_t{1} << (sizeof(value_idx_type) * 8 - 1); } else { return size_t{1} << (sizeof(value_idx_type) * 8); @@ -1272,7 +1569,7 @@ public: auto const last_to_end = std::distance(last, cend()); // remove elements from left to right which moves elements from the end back - auto const mid = idx_first + std::min(first_to_last, last_to_end); + auto const mid = idx_first + (std::min)(first_to_last, last_to_end); auto idx = idx_first; while (idx != mid) { erase(begin() + idx); @@ -1439,8 +1736,8 @@ public: } void rehash(size_t count) { - count = std::min(count, max_size()); - auto shifts = calc_shifts_for_size(std::max(count, size())); + count = (std::min)(count, max_size()); + auto shifts = calc_shifts_for_size((std::max)(count, size())); if (shifts != m_shifts) { m_shifts = shifts; deallocate_buckets(); @@ -1451,12 +1748,12 @@ public: } void reserve(size_t capa) { - capa = std::min(capa, max_size()); + capa = (std::min)(capa, max_size()); if constexpr (has_reserve) { // std::deque doesn't have reserve(). Make sure we only call when available m_values.reserve(capa); } - auto shifts = calc_shifts_for_size(std::max(capa, size())); + auto shifts = calc_shifts_for_size((std::max)(capa, size())); if (0 == m_num_buckets || shifts < m_shifts) { m_shifts = shifts; deallocate_buckets(); @@ -1519,16 +1816,31 @@ template , class AllocatorOrContainer = std::allocator>, class Bucket = bucket_type::standard> -using map = detail::table; +using map = detail::table; + +template , + class KeyEqual = std::equal_to, + class AllocatorOrContainer = std::allocator>, + class Bucket = bucket_type::standard> +using segmented_map = detail::table; + +template , + class KeyEqual = std::equal_to, + class AllocatorOrContainer = std::allocator, + class Bucket = bucket_type::standard> +using set = detail::table; template , class KeyEqual = std::equal_to, class AllocatorOrContainer = std::allocator, class Bucket = bucket_type::standard> -using set = detail::table; +using segmented_set = detail::table; -# if ANKERL_UNORDERED_DENSE_PMR +# if defined(ANKERL_UNORDERED_DENSE_PMR) namespace pmr { @@ -1537,10 +1849,23 @@ template , class KeyEqual = std::equal_to, class Bucket = bucket_type::standard> -using map = detail::table>, Bucket>; +using map = + detail::table>, Bucket, false>; + +template , + class KeyEqual = std::equal_to, + class Bucket = bucket_type::standard> +using segmented_map = + detail::table>, Bucket, true>; + +template , class KeyEqual = std::equal_to, class Bucket = bucket_type::standard> +using set = detail::table, Bucket, false>; template , class KeyEqual = std::equal_to, class Bucket = bucket_type::standard> -using set = detail::table, Bucket>; +using segmented_set = + detail::table, Bucket, true>; } // namespace pmr @@ -1558,11 +1883,18 @@ using set = detail::table +template // NOLINTNEXTLINE(cert-dcl58-cpp) -auto erase_if(ankerl::unordered_dense::detail::table& map, Pred pred) - -> size_t { - using map_t = ankerl::unordered_dense::detail::table; +auto erase_if(ankerl::unordered_dense::detail::table& map, + Pred pred) -> size_t { + using map_t = ankerl::unordered_dense::detail::table; // going back to front because erase() invalidates the end iterator auto const old_size = map.size(); diff --git a/misc/benchmarks/external/emhash/hash_table7.hpp b/misc/benchmarks/external/emhash/hash_table7.hpp index 8f8982f9..c21e145b 100644 --- a/misc/benchmarks/external/emhash/hash_table7.hpp +++ b/misc/benchmarks/external/emhash/hash_table7.hpp @@ -92,7 +92,7 @@ of resizing granularity. Ignoring variance, the expected occurrences of list siz #include "wyhash.h" #endif -#ifdef EMH_KEY +#ifdef EMH_NEW #undef EMH_KEY #undef EMH_VAL #undef EMH_PKV @@ -547,10 +547,10 @@ public: static PairT* alloc_bucket(size_type num_buckets) { -#if _WIN32 - auto* new_pairs = (PairT*)malloc(AllocSize(num_buckets)); -#else +#ifdef EMH_ALLOC auto* new_pairs = (PairT*)aligned_alloc(EMH_MALIGN, AllocSize(num_buckets)); +#else + auto* new_pairs = (PairT*)malloc(AllocSize(num_buckets)); #endif return new_pairs; } @@ -1668,16 +1668,10 @@ private: // key is not in this map. Find a place to put it. size_type find_empty_bucket(const size_type bucket_from, const size_type main_bucket) { -#ifdef EMH_ALIGN64 // only works 64bit - const auto boset = bucket_from % MASK_BIT; - auto* const align = _bitmask + bucket_from / MASK_BIT; - const auto bmask = ((size_t)align[1] << (MASK_BIT - boset)) | (align[0] >> boset); - if (EMH_LIKELY(bmask != 0)) - return bucket_from + CTZ(bmask); -#elif EMH_ITER_SAFE +#if EMH_ITER_SAFE const auto boset = bucket_from % 8; - auto* const start = (uint8_t*)_bitmask + bucket_from / 8; - size_t bmask; memcpy(&bmask, start + 0, sizeof(bmask)); bmask >>= boset;// bmask |= ((size_t)start[8] << (SIZE_BIT - boset)); + auto* const align = (uint8_t*)_bitmask + bucket_from / 8;(void)main_bucket; + size_t bmask; memcpy(&bmask, align + 0, sizeof(bmask)); bmask >>= boset;// bmask |= ((size_t)align[8] << (SIZE_BIT - boset)); if (EMH_LIKELY(bmask != 0)) return bucket_from + CTZ(bmask); #else @@ -1715,21 +1709,15 @@ private: } // key is not in this map. Find a place to put it. - size_type find_unique_empty(const size_type bucket_from, const size_t main_bucket) - { -#ifdef EMH_ALIGN64 - const auto boset = bucket_from % MASK_BIT; - auto* const align = _bitmask + bucket_from / MASK_BIT; - const auto bmask = ((size_t)align[1] << (MASK_BIT - boset)) | (align[0] >> boset); - static_assert(sizeof(size_t) > 4); -#elif EMH_ITER_SAFE + size_type find_unique_empty(const size_type bucket_from) + { const auto boset = bucket_from % 8; - auto* const start = (uint8_t*)_bitmask + bucket_from / 8; - size_t bmask; memcpy(&bmask, start + 0, sizeof(bmask)); bmask >>= boset; -#else - const auto boset = bucket_from % 8; (void)main_bucket; auto* const align = (uint8_t*)_bitmask + bucket_from / 8; - const auto bmask = (*(size_t*)(align) >> boset); //maybe not aligned and warning + +#if EMH_ITER_SAFE + size_t bmask; memcpy(&bmask, align + 0, sizeof(bmask)); bmask >>= boset; +#else + const auto bmask = (*(size_t*)(align) >> boset); //maybe not aligned and warning #endif if (EMH_LIKELY(bmask != 0)) return bucket_from + CTZ(bmask); @@ -1789,12 +1777,12 @@ private: next_bucket = find_last_bucket(next_bucket); //find a new empty and link it to tail - return EMH_BUCKET(_pairs, next_bucket) = find_unique_empty(next_bucket, bucket); + return EMH_BUCKET(_pairs, next_bucket) = find_unique_empty(next_bucket); } #if EMH_INT_HASH static constexpr uint64_t KC = UINT64_C(11400714819323198485); - inline uint64_t hash64(uint64_t key) + inline static uint64_t hash64(uint64_t key) { #if __SIZEOF_INT128__ && EMH_INT_HASH == 1 __uint128_t r = key; r *= KC; diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp index debff31d..05ec33e7 100644 --- a/misc/benchmarks/shootout_hashmaps.cpp +++ b/misc/benchmarks/shootout_hashmaps.cpp @@ -35,7 +35,7 @@ KHASH_MAP_INIT_INT64(ii, IValue) // cmap template expansion #define i_key IKey #define i_val IValue -//#define i_ssize int32_t // enable 2^K buckets like the rest. +#define i_expandby 2 // enable 2^K buckets like the rest. #define i_tag ii #define i_max_load_factor MAX_LOAD_FACTOR / 100.0f #include diff --git a/misc/benchmarks/various/sso_bench.cpp b/misc/benchmarks/various/sso_bench.cpp index 993ff1bb..9841c296 100644 --- a/misc/benchmarks/various/sso_bench.cpp +++ b/misc/benchmarks/various/sso_bench.cpp @@ -10,58 +10,61 @@ #include #define i_type StcSet +#define i_expandby 2 #define i_val_str -#include +#include #include using StdVec = std::vector; -#include -using StdSet = std::set; +//#include "../external/ankerl/robin_hood.h" +//using StdSet = robin_hood::unordered_flat_set; -static const int BENCHMARK_SIZE = 2000000; -static const int MAX_STRING_SIZE = 50; +#include +using StdSet = std::unordered_set; + + +static const int BENCHMARK_SIZE = 250000; +static const int MAX_STRING_SIZE = 100; static const char CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=+-"; using time_point = std::chrono::high_resolution_clock::time_point; -static inline std::string randomString_STD(int strsize) { - std::string s(strsize, 0); - char* p = &s[0]; +static inline const char* randomString(int strsize) { + static char str[256]; union { uint64_t u8; uint8_t b[8]; } r; for (int i = 0; i < strsize; ++i) { if ((i & 7) == 0) r.u8 = crand() & 0x3f3f3f3f3f3f3f3f; - p[i] = CHARS[r.b[i & 7]]; + str[i] = CHARS[r.b[i & 7]]; } - return s; + str[strsize] = 0; + return str; } -static inline cstr randomString_STC(int strsize) { - cstr s = cstr_with_size(strsize, 0); - char* p = cstr_data(&s); - union { uint64_t u8; uint8_t b[8]; } r; - for (int i = 0; i < strsize; ++i) { - if ((i & 7) == 0) r.u8 = crand() & 0x3f3f3f3f3f3f3f3f; - p[i] = CHARS[r.b[i & 7]]; - } - return s; + + +static inline void addRandomString(StdVec& vec, int strsize) { + vec.push_back(randomString(strsize)); } +static inline void addRandomString(StcVec& vec, int strsize) { + StcVec_emplace(&vec, randomString(strsize)); +} -void addRandomString(StdVec& vec, int strsize) { - vec.push_back(std::move(randomString_STD(strsize))); +static inline void addRandomString(StdSet& set, int strsize) { + set.insert(randomString(strsize)); } -void addRandomString(StcVec& vec, int strsize) { - StcVec_push(&vec, randomString_STC(strsize)); +static inline void addRandomString(StcSet& set, int strsize) { + StcSet_emplace(&set, randomString(strsize)); } -void addRandomString(StdSet& set, int strsize) { - set.insert(std::move(randomString_STD(strsize))); +static inline bool getRandomString(const StdSet& set, int strsize) { + return set.find(randomString(strsize)) != set.end(); } -void addRandomString(StcSet& set, int strsize) { - StcSet_insert(&set, randomString_STC(strsize)); +static inline bool getRandomString(const StcSet& set, int strsize) { + return StcSet_contains(&set, randomString(strsize)); } @@ -78,6 +81,22 @@ int benchmark(C& container, const int n, const int strsize) { return (int)duration; } +template +int benchmark_lookup(C& container, const int n, const int strsize) { + for (int i = 0; i < n; i++) + addRandomString(container, strsize); + + time_point t1 = std::chrono::high_resolution_clock::now(); + int found = 0; + for (int i = 0; i < n; i++) + found += (int)getRandomString(container, strsize); + + time_point t2 = std::chrono::high_resolution_clock::now(); + const auto duration = std::chrono::duration_cast(t2 - t1).count(); + std::cerr << (strsize ? strsize : 32) << "\t" << duration << '\t' << found; + return (int)duration; +} + int main() { uint64_t seed = 4321; @@ -88,48 +107,75 @@ int main() { csrand(seed); sum = 0, n = 0; std::cerr << "\nstrsize\tmsecs\tstd::vector, size=" << BENCHMARK_SIZE << "\n"; - for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { StdVec vec; vec.reserve(BENCHMARK_SIZE); sum += benchmark(vec, BENCHMARK_SIZE, strsize), ++n; std::cout << '\t' << vec.front() << '\n'; } - std::cout << "Avg:\t" << sum/n << '\n'; + std::cout << "Avg:\t" << sum/n << "ms\n"; csrand(seed); sum = 0, n = 0; std::cerr << "\nstrsize\tmsecs\tcvec, size=" << BENCHMARK_SIZE << "\n"; - for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { StcVec vec = StcVec_with_capacity(BENCHMARK_SIZE); sum += benchmark(vec, BENCHMARK_SIZE, strsize), ++n; std::cout << '\t' << cstr_str(&vec.data[0]) << '\n'; StcVec_drop(&vec); } - std::cout << "Avg:\t" << sum/n << '\n'; + std::cout << "Avg:\t" << sum/n << "ms\n"; + + // INSERT: SORTED SET WITH STRINGS + + csrand(seed); + sum = 0, n = 0; + std::cerr << "\nstrsize\tmsecs\tinsert: robin_hood::unordered_flat_set, size=" << BENCHMARK_SIZE/2 << "\n"; + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { + StdSet set; set.reserve(BENCHMARK_SIZE/2); + sum += benchmark(set, BENCHMARK_SIZE/2, strsize), ++n; + std::cout << '\t' << *set.begin() << '\n'; + } + std::cout << "Avg:\t" << sum/n << "ms\n"; - // SORTED SET WITH STRINGS csrand(seed); sum = 0, n = 0; - std::cerr << "\nstrsize\tmsecs\tstd::set, size=" << BENCHMARK_SIZE/16 << "\n"; - for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { - StdSet set; - sum += benchmark(set, BENCHMARK_SIZE/16, strsize), ++n; + std::cerr << "\nstrsize\tmsecs\tinsert: cset, size=" << BENCHMARK_SIZE/2 << "\n"; + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { + StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/2); + sum += benchmark(set, BENCHMARK_SIZE/2, strsize), ++n; + std::cout << '\t' << cstr_str(StcSet_begin(&set).ref) << '\n'; + StcSet_drop(&set); + } + std::cout << "Avg:\t" << sum/n << "ms\n"; + + // LOOKUP: SORTED SET WITH STRINGS + + csrand(seed); + sum = 0, n = 0; + std::cerr << "\nstrsize\tmsecs\tfind: robin_hood::unordered_flat_set, size=" << BENCHMARK_SIZE/2 << "\n"; + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { + StdSet set; set.reserve(BENCHMARK_SIZE/2); + sum += benchmark_lookup(set, BENCHMARK_SIZE/2, strsize), ++n; std::cout << '\t' << *set.begin() << '\n'; } - std::cout << "Avg:\t" << sum/n << '\n'; + std::cout << "Avg:\t" << sum/n << "ms\n"; csrand(seed); sum = 0, n = 0; - std::cerr << "\nstrsize\tmsecs\tcsset, size=" << BENCHMARK_SIZE/16 << "\n"; - for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { - StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/16); - sum += benchmark(set, BENCHMARK_SIZE/16, strsize), ++n; - std::cout << '\t' << cstr_str(StcSet_front(&set)) << '\n'; + std::cerr << "\nstrsize\tmsecs\tfind: cset, size=" << BENCHMARK_SIZE/2 << "\n"; + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { + StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/2); + sum += benchmark_lookup(set, BENCHMARK_SIZE/2, strsize), ++n; + std::cout << '\t' << cstr_str(StcSet_begin(&set).ref) << '\n'; StcSet_drop(&set); } - std::cout << "Avg:\t" << sum/n << '\n'; + std::cout << "Avg:\t" << sum/n << "ms\n"; + std::cerr << "sizeof(std::string) : " << sizeof(std::string) << std::endl - << "sizeof(cstr) : " << sizeof(cstr) << std::endl; + << "sizeof(cstr) : " << sizeof(cstr) << std::endl + << "sizeof(StdSet) : " << sizeof(StdSet) << std::endl + << "sizeof(StcSet) : " << sizeof(StcSet) << std::endl; return 0; } -- cgit v1.2.3 From 25679f9af707818df02a71ef7c996b2a806dae28 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 19 Apr 2023 20:25:32 +0200 Subject: Internal refactoring in cmap. Should be easy to convert to robinhood hash from here. --- include/stc/cmap.h | 140 +++++++++++++++++++++++++------------------------- include/stc/forward.h | 6 +-- 2 files changed, 74 insertions(+), 72 deletions(-) diff --git a/include/stc/cmap.h b/include/stc/cmap.h index cfed5540..4b970c86 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -53,7 +53,8 @@ int main(void) { #include "forward.h" #include #include -typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t; +typedef struct { int64_t idx; uint8_t hashx; } chash_bucket; +typedef struct chash_slot { uint8_t hashx/*, psl*/; } chash_slot; #endif // CMAP_H_INCLUDED #ifndef _i_prefix @@ -100,7 +101,7 @@ STC_API _cx_self _cx_memb(_clone)(_cx_self map); STC_API void _cx_memb(_drop)(_cx_self* self); STC_API void _cx_memb(_clear)(_cx_self* self); STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t capacity); -STC_API chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr); +STC_API chash_bucket _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr); STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey); STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val); @@ -113,7 +114,7 @@ STC_INLINE intptr_t _cx_memb(_bucket_count)(_cx_self* map) { return map->buc STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* map) { return (intptr_t)((float)map->bucket.count * (i_max_load_factor)); } STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) - { return self->size && self->_hashx[_cx_memb(_bucket_)(self, &rkey).idx]; } + { return self->size && self->slot[_cx_memb(_bucket_)(self, &rkey).idx].hashx; } #ifndef _i_isset STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped); @@ -123,9 +124,9 @@ STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rke STC_INLINE const _cx_mapped* _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey) { - chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); - assert(self->_hashx[b.idx]); - return &self->table[b.idx].second; + chash_bucket b = _cx_memb(_bucket_)(self, &rkey); + assert(self->slot[b.idx].hashx); + return &self->data[b.idx].second; } STC_INLINE _cx_mapped* _cx_memb(_at_mut)(_cx_self* self, _cx_keyraw rkey) @@ -134,7 +135,7 @@ STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rke #if !defined i_no_clone STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) { - if (self->table == other->table) + if (self->data == other->data) return; _cx_memb(_drop)(self); *self = _cx_memb(_clone)(*other); @@ -209,10 +210,10 @@ STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { - _cx_iter it = {self->table, self->table+self->bucket.count, self->_hashx}; - if (it._hx) - while (*it._hx == 0) - ++it.ref, ++it._hx; + _cx_iter it = {self->data, self->data+self->bucket.count, self->slot}; + if (it.spos) + while (it.spos->hashx == 0) + ++it.ref, ++it.spos; if (it.ref == it._end) it.ref = NULL; return it; } @@ -223,7 +224,7 @@ _cx_memb(_end)(const _cx_self* self) STC_INLINE void _cx_memb(_next)(_cx_iter* it) { - while ((++it->ref, *++it->_hx == 0)) ; + while ((++it->ref, (++it->spos)->hashx == 0)) ; if (it->ref == it->_end) it->ref = NULL; } @@ -236,18 +237,18 @@ _cx_memb(_advance)(_cx_iter it, size_t n) { STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) { int64_t idx; - if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]) - return c_LITERAL(_cx_iter){self->table + idx, - self->table + self->bucket.count, - self->_hashx + idx}; + if (self->size && self->slot[idx = _cx_memb(_bucket_)(self, &rkey).idx].hashx) + return c_LITERAL(_cx_iter){self->data + idx, + self->data + self->bucket.count, + self->slot + idx}; return _cx_memb(_end)(self); } STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey) { int64_t idx; - if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]) - return self->table + idx; + if (self->size && self->slot[idx = _cx_memb(_bucket_)(self, &rkey).idx].hashx) + return self->data + idx; return NULL; } @@ -259,14 +260,14 @@ STC_INLINE int _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { if (self->size == 0) return 0; - chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); - return self->_hashx[b.idx] ? _cx_memb(_erase_entry)(self, self->table + b.idx), 1 : 0; + chash_bucket b = _cx_memb(_bucket_)(self, &rkey); + return self->slot[b.idx].hashx ? _cx_memb(_erase_entry)(self, self->data + b.idx), 1 : 0; } STC_INLINE _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { _cx_memb(_erase_entry)(self, it.ref); - if (*it._hx == 0) + if (it.spos->hashx == 0) _cx_memb(_next)(&it); return it; } @@ -310,23 +311,23 @@ _cx_memb(_with_capacity)(const intptr_t cap) { STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) { if (self->size == 0) return; - _cx_value* e = self->table, *end = e + self->bucket.count; - uint8_t *hx = self->_hashx; - for (; e != end; ++e) - if (*hx++) - _cx_memb(_value_drop)(e); + _cx_value* d = self->data, *_end = d + self->bucket.count; + chash_slot *_slot = self->slot; + for (; d != _end; ++d) + if ((_slot++)->hashx) + _cx_memb(_value_drop)(d); } STC_DEF void _cx_memb(_drop)(_cx_self* self) { _cx_memb(_wipe_)(self); - i_free(self->_hashx); - i_free((void *) self->table); + i_free(self->slot); + i_free(self->data); } STC_DEF void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_wipe_)(self); self->size = 0; - c_memset(self->_hashx, 0, self->bucket.count); + c_memset(self->slot, 0, sizeof(chash_slot)*self->bucket.count); } #ifndef _i_isset @@ -358,15 +359,15 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) { #endif // !i_no_emplace #endif // !_i_isset -STC_DEF chash_bucket_t +STC_DEF chash_bucket _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); int64_t _cap = self->bucket.count; - chash_bucket_t b = {c_PASTE(fastrange_,i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; - const uint8_t* _hx = self->_hashx; - while (_hx[b.idx]) { - if (_hx[b.idx] == b.hx) { - const _cx_keyraw _raw = i_keyto(_i_keyref(self->table + b.idx)); + chash_bucket b = {c_PASTE(fastrange_,i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; + const chash_slot* _slot = self->slot; + while (_slot[b.idx].hashx) { + if (_slot[b.idx].hashx == b.hashx) { + const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + b.idx)); if (i_eq((&_raw), rkeyptr)) break; } @@ -383,10 +384,10 @@ _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { if (!_cx_memb(_reserve)(self, (intptr_t)(self->size*3/2))) return res; - chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); - res.ref = &self->table[b.idx]; - if ((res.inserted = !self->_hashx[b.idx])) { - self->_hashx[b.idx] = b.hx; + chash_bucket b = _cx_memb(_bucket_)(self, &rkey); + res.ref = &self->data[b.idx]; + if ((res.inserted = !self->slot[b.idx].hashx)) { + self->slot[b.idx].hashx = b.hashx; ++self->size; } return res; @@ -395,17 +396,18 @@ _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { #if !defined i_no_clone STC_DEF _cx_self _cx_memb(_clone)(_cx_self m) { - if (m.table) { - _cx_value *t = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket.count), - *dst = t, *m_end = m.table + m.bucket.count; - uint8_t *h = (uint8_t *)c_memcpy(i_malloc(m.bucket.count + 1), m._hashx, m.bucket.count + 1); - if (!(t && h)) - { i_free(t), i_free(h), t = 0, h = 0, m.bucket.count = 0; } + if (m.data) { + _cx_value *d = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket.count), + *_dst = d, *_end = m.data + m.bucket.count; + const intptr_t _mem = c_sizeof(chash_slot)*(m.bucket.count + 1); + chash_slot *_slot = (chash_slot *)c_memcpy(i_malloc(_mem), m.slot, _mem); + if (!(d && _slot)) + { i_free(d), i_free(_slot), d = 0, _slot = 0, m.bucket.count = 0; } else - for (; m.table != m_end; ++m.table, ++m._hashx, ++dst) - if (*m._hashx) - *dst = _cx_memb(_value_clone)(*m.table); - m.table = t, m._hashx = h; + for (; m.data != _end; ++m.data, ++m.slot, ++_dst) + if (m.slot->hashx) + *_dst = _cx_memb(_value_clone)(*m.data); + m.data = d, m.slot = _slot; } return m; } @@ -424,45 +426,45 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t newcap) { #endif _cx_self m = { (_cx_value *)i_malloc(c_sizeof(_cx_value)*_nbuckets), - (uint8_t *)i_calloc(_nbuckets + 1, 1), + (chash_slot *)i_calloc(_nbuckets + 1, sizeof(chash_slot)), self->size, {_nbuckets & ((1ULL << 48) - 1)} }; - bool ok = m.table && m._hashx; - if (ok) { /* Rehash: */ - m._hashx[_nbuckets] = 0xff; - const _cx_value* e = self->table; - const uint8_t* h = self->_hashx; - for (intptr_t i = 0; i < _oldbuckets; ++i, ++e) if (*h++) { - _cx_keyraw r = i_keyto(_i_keyref(e)); - chash_bucket_t b = _cx_memb(_bucket_)(&m, &r); - m.table[b.idx] = *e; - m._hashx[b.idx] = b.hx; + bool ok = m.data && m.slot; + if (ok) { // Rehash: + m.slot[_nbuckets].hashx = 0xff; + const _cx_value* d = self->data; + const chash_slot* _slot = self->slot; + for (intptr_t i = 0; i < _oldbuckets; ++i, ++d) if ((_slot++)->hashx) { + _cx_keyraw r = i_keyto(_i_keyref(d)); + chash_bucket b = _cx_memb(_bucket_)(&m, &r); + m.data[b.idx] = *d; // move + m.slot[b.idx].hashx = b.hashx; } c_swap(_cx_self, self, &m); } - i_free(m._hashx); - i_free(m.table); + i_free(m.slot); + i_free(m.data); return ok; } STC_DEF void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { - intptr_t i = (intptr_t)(_val - self->table), j = i, k; + _cx_value* d = self->data; + chash_slot* _slot = self->slot; + intptr_t i = (intptr_t)(_val - d), j = i, k; const intptr_t _cap = self->bucket.count; - _cx_value* _slot = self->table; - uint8_t* _hashx = self->_hashx; _cx_memb(_value_drop)(_val); for (;;) { /* delete without leaving tombstone */ if (++j == _cap) j = 0; - if (! _hashx[j]) + if (! _slot[j].hashx) break; - const _cx_keyraw _raw = i_keyto(_i_keyref(_slot + j)); + const _cx_keyraw _raw = i_keyto(_i_keyref(d + j)); k = (intptr_t)c_PASTE(fastrange_,i_expandby)(i_hash((&_raw)), (uint64_t)_cap); if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ - _slot[i] = _slot[j], _hashx[i] = _hashx[j], i = j; + d[i] = d[j], _slot[i] = _slot[j], i = j; } - _hashx[i] = 0; + _slot[i].hashx = 0; --self->size; } diff --git a/include/stc/forward.h b/include/stc/forward.h index e543b94a..e79be580 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -116,12 +116,12 @@ typedef union { \ typedef struct { \ SELF##_value *ref, *_end; \ - uint8_t* _hx; \ + struct chash_slot* spos; \ } SELF##_iter; \ \ typedef struct SELF { \ - SELF##_value* table; \ - uint8_t* _hashx; \ + SELF##_value* data; \ + struct chash_slot* slot; \ intptr_t size; \ struct { uint64_t count: 48, maxdist: 16; } bucket; \ } SELF -- cgit v1.2.3 From 119de13b8506e5f13d7b4d5ba3edbd394b6f3218 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 20 Apr 2023 09:31:57 +0200 Subject: Minor internal cmap updates. --- include/stc/cmap.h | 61 +++++++++++++++++++++++++-------------------------- include/stc/forward.h | 8 ++++--- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 4b970c86..e5a810a9 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -54,7 +54,6 @@ int main(void) { #include #include typedef struct { int64_t idx; uint8_t hashx; } chash_bucket; -typedef struct chash_slot { uint8_t hashx/*, psl*/; } chash_slot; #endif // CMAP_H_INCLUDED #ifndef _i_prefix @@ -211,9 +210,9 @@ STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { _cx_iter it = {self->data, self->data+self->bucket.count, self->slot}; - if (it.spos) - while (it.spos->hashx == 0) - ++it.ref, ++it.spos; + if (it.sref) + while (it.sref->hashx == 0) + ++it.ref, ++it.sref; if (it.ref == it._end) it.ref = NULL; return it; } @@ -224,7 +223,7 @@ _cx_memb(_end)(const _cx_self* self) STC_INLINE void _cx_memb(_next)(_cx_iter* it) { - while ((++it->ref, (++it->spos)->hashx == 0)) ; + while ((++it->ref, (++it->sref)->hashx == 0)) ; if (it->ref == it->_end) it->ref = NULL; } @@ -267,7 +266,7 @@ _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { STC_INLINE _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { _cx_memb(_erase_entry)(self, it.ref); - if (it.spos->hashx == 0) + if (it.sref->hashx == 0) _cx_memb(_next)(&it); return it; } @@ -312,9 +311,9 @@ STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) { if (self->size == 0) return; _cx_value* d = self->data, *_end = d + self->bucket.count; - chash_slot *_slot = self->slot; + chash_slot* s = self->slot; for (; d != _end; ++d) - if ((_slot++)->hashx) + if ((s++)->hashx) _cx_memb(_value_drop)(d); } @@ -364,9 +363,9 @@ _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); int64_t _cap = self->bucket.count; chash_bucket b = {c_PASTE(fastrange_,i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; - const chash_slot* _slot = self->slot; - while (_slot[b.idx].hashx) { - if (_slot[b.idx].hashx == b.hashx) { + const chash_slot* s = self->slot; + while (s[b.idx].hashx) { + if (s[b.idx].hashx == b.hashx) { const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + b.idx)); if (i_eq((&_raw), rkeyptr)) break; @@ -400,41 +399,41 @@ _cx_memb(_clone)(_cx_self m) { _cx_value *d = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket.count), *_dst = d, *_end = m.data + m.bucket.count; const intptr_t _mem = c_sizeof(chash_slot)*(m.bucket.count + 1); - chash_slot *_slot = (chash_slot *)c_memcpy(i_malloc(_mem), m.slot, _mem); - if (!(d && _slot)) - { i_free(d), i_free(_slot), d = 0, _slot = 0, m.bucket.count = 0; } + chash_slot *s = (chash_slot *)c_memcpy(i_malloc(_mem), m.slot, _mem); + if (!(d && s)) + { i_free(d), i_free(s), d = 0, s = 0, m.bucket.count = 0; } else for (; m.data != _end; ++m.data, ++m.slot, ++_dst) if (m.slot->hashx) *_dst = _cx_memb(_value_clone)(*m.data); - m.data = d, m.slot = _slot; + m.data = d, m.slot = s; } return m; } #endif STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const intptr_t newcap) { - const intptr_t _oldbuckets = self->bucket.count, _newcap = newcap; - if (_newcap != self->size && _newcap <= _oldbuckets) +_cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { + const intptr_t _oldbucks = self->bucket.count; + if (_newcap != self->size && _newcap <= _oldbucks) return true; - uintptr_t _nbuckets = (uintptr_t)((float)_newcap / (i_max_load_factor)) + 4; + uintptr_t _newbucks = (uintptr_t)((float)_newcap / (i_max_load_factor)) + 4; #if i_expandby == 2 - _nbuckets = (intptr_t)next_power_of_2(_nbuckets); + _newbucks = (intptr_t)next_power_of_2(_newbucks); #else - _nbuckets |= 1; + _newbucks |= 1; #endif _cx_self m = { - (_cx_value *)i_malloc(c_sizeof(_cx_value)*_nbuckets), - (chash_slot *)i_calloc(_nbuckets + 1, sizeof(chash_slot)), - self->size, {_nbuckets & ((1ULL << 48) - 1)} + (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), + (chash_slot *)i_calloc(_newbucks + 1, sizeof(chash_slot)), + self->size, {_newbucks & ((1ULL << 48) - 1)} }; bool ok = m.data && m.slot; if (ok) { // Rehash: - m.slot[_nbuckets].hashx = 0xff; + m.slot[_newbucks].hashx = 0xff; const _cx_value* d = self->data; - const chash_slot* _slot = self->slot; - for (intptr_t i = 0; i < _oldbuckets; ++i, ++d) if ((_slot++)->hashx) { + const chash_slot* s = self->slot; + for (intptr_t i = 0; i < _oldbucks; ++i, ++d) if ((s++)->hashx) { _cx_keyraw r = i_keyto(_i_keyref(d)); chash_bucket b = _cx_memb(_bucket_)(&m, &r); m.data[b.idx] = *d; // move @@ -450,21 +449,21 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t newcap) { STC_DEF void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { _cx_value* d = self->data; - chash_slot* _slot = self->slot; + chash_slot* s = self->slot; intptr_t i = (intptr_t)(_val - d), j = i, k; const intptr_t _cap = self->bucket.count; _cx_memb(_value_drop)(_val); for (;;) { /* delete without leaving tombstone */ if (++j == _cap) j = 0; - if (! _slot[j].hashx) + if (! s[j].hashx) break; const _cx_keyraw _raw = i_keyto(_i_keyref(d + j)); k = (intptr_t)c_PASTE(fastrange_,i_expandby)(i_hash((&_raw)), (uint64_t)_cap); if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ - d[i] = d[j], _slot[i] = _slot[j], i = j; + d[i] = d[j], s[i] = s[j], i = j; } - _slot[i].hashx = 0; + s[i].hashx = 0; --self->size; } diff --git a/include/stc/forward.h b/include/stc/forward.h index e79be580..78ec23a2 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -101,6 +101,8 @@ typedef union { SELF##_node *last; \ } SELF +typedef struct { uint8_t hashx/*, psl*/; } chash_slot; + #define _c_chash_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \ typedef KEY SELF##_key; \ typedef VAL SELF##_mapped; \ @@ -116,14 +118,14 @@ typedef union { \ typedef struct { \ SELF##_value *ref, *_end; \ - struct chash_slot* spos; \ + chash_slot* sref; \ } SELF##_iter; \ \ typedef struct SELF { \ SELF##_value* data; \ - struct chash_slot* slot; \ + chash_slot* slot; \ intptr_t size; \ - struct { uint64_t count: 48, maxdist: 16; } bucket; \ + struct { uint64_t count: 48, maxpsl: 16; } bucket; \ } SELF #define _c_aatree_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \ -- cgit v1.2.3 From 4375640bdf856866fa2a1e7010103736077b9738 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 20 Apr 2023 21:33:49 +0200 Subject: cmap Updates to dev43 standard. --- include/stc/cmap.h | 38 +++++++++++++++++------------------ include/stc/forward.h | 5 ++--- misc/benchmarks/shootout_hashmaps.cpp | 6 +++--- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/include/stc/cmap.h b/include/stc/cmap.h index e5a810a9..d0ad7886 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -53,7 +53,7 @@ int main(void) { #include "forward.h" #include #include -typedef struct { int64_t idx; uint8_t hashx; } chash_bucket; +typedef struct { intptr_t idx; uint8_t hashx; } chash_bucket; #endif // CMAP_H_INCLUDED #ifndef _i_prefix @@ -109,9 +109,9 @@ STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_res STC_INLINE float _cx_memb(_max_load_factor)(const _cx_self* self) { return (float)(i_max_load_factor); } STC_INLINE bool _cx_memb(_empty)(const _cx_self* map) { return !map->size; } STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* map) { return (intptr_t)map->size; } -STC_INLINE intptr_t _cx_memb(_bucket_count)(_cx_self* map) { return map->bucket.count; } +STC_INLINE intptr_t _cx_memb(_bucket_count)(_cx_self* map) { return map->bucket_count; } STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* map) - { return (intptr_t)((float)map->bucket.count * (i_max_load_factor)); } + { return (intptr_t)((float)map->bucket_count * (i_max_load_factor)); } STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) { return self->size && self->slot[_cx_memb(_bucket_)(self, &rkey).idx].hashx; } @@ -209,7 +209,7 @@ STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { - _cx_iter it = {self->data, self->data+self->bucket.count, self->slot}; + _cx_iter it = {self->data, self->data+self->bucket_count, self->slot}; if (it.sref) while (it.sref->hashx == 0) ++it.ref, ++it.sref; @@ -235,17 +235,17 @@ _cx_memb(_advance)(_cx_iter it, size_t n) { STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) { - int64_t idx; + intptr_t idx; if (self->size && self->slot[idx = _cx_memb(_bucket_)(self, &rkey).idx].hashx) return c_LITERAL(_cx_iter){self->data + idx, - self->data + self->bucket.count, + self->data + self->bucket_count, self->slot + idx}; return _cx_memb(_end)(self); } STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey) { - int64_t idx; + intptr_t idx; if (self->size && self->slot[idx = _cx_memb(_bucket_)(self, &rkey).idx].hashx) return self->data + idx; return NULL; @@ -310,7 +310,7 @@ _cx_memb(_with_capacity)(const intptr_t cap) { STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) { if (self->size == 0) return; - _cx_value* d = self->data, *_end = d + self->bucket.count; + _cx_value* d = self->data, *_end = d + self->bucket_count; chash_slot* s = self->slot; for (; d != _end; ++d) if ((s++)->hashx) @@ -326,7 +326,7 @@ STC_DEF void _cx_memb(_drop)(_cx_self* self) { STC_DEF void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_wipe_)(self); self->size = 0; - c_memset(self->slot, 0, sizeof(chash_slot)*self->bucket.count); + c_memset(self->slot, 0, c_sizeof(chash_slot)*self->bucket_count); } #ifndef _i_isset @@ -361,7 +361,7 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) { STC_DEF chash_bucket _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); - int64_t _cap = self->bucket.count; + intptr_t _cap = self->bucket_count; chash_bucket b = {c_PASTE(fastrange_,i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; const chash_slot* s = self->slot; while (s[b.idx].hashx) { @@ -379,7 +379,7 @@ _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { STC_DEF _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { _cx_result res = {NULL}; - if (self->size + 2 > (intptr_t)((float)self->bucket.count * (i_max_load_factor))) + if (self->size + 2 > (intptr_t)((float)self->bucket_count * (i_max_load_factor))) if (!_cx_memb(_reserve)(self, (intptr_t)(self->size*3/2))) return res; @@ -396,12 +396,12 @@ _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { STC_DEF _cx_self _cx_memb(_clone)(_cx_self m) { if (m.data) { - _cx_value *d = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket.count), - *_dst = d, *_end = m.data + m.bucket.count; - const intptr_t _mem = c_sizeof(chash_slot)*(m.bucket.count + 1); + _cx_value *d = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count), + *_dst = d, *_end = m.data + m.bucket_count; + const intptr_t _mem = c_sizeof(chash_slot)*(m.bucket_count + 1); chash_slot *s = (chash_slot *)c_memcpy(i_malloc(_mem), m.slot, _mem); if (!(d && s)) - { i_free(d), i_free(s), d = 0, s = 0, m.bucket.count = 0; } + { i_free(d), i_free(s), d = 0, s = 0, m.bucket_count = 0; } else for (; m.data != _end; ++m.data, ++m.slot, ++_dst) if (m.slot->hashx) @@ -414,10 +414,10 @@ _cx_memb(_clone)(_cx_self m) { STC_DEF bool _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { - const intptr_t _oldbucks = self->bucket.count; + const intptr_t _oldbucks = self->bucket_count; if (_newcap != self->size && _newcap <= _oldbucks) return true; - uintptr_t _newbucks = (uintptr_t)((float)_newcap / (i_max_load_factor)) + 4; + intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4; #if i_expandby == 2 _newbucks = (intptr_t)next_power_of_2(_newbucks); #else @@ -426,7 +426,7 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { _cx_self m = { (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), (chash_slot *)i_calloc(_newbucks + 1, sizeof(chash_slot)), - self->size, {_newbucks & ((1ULL << 48) - 1)} + self->size, _newbucks }; bool ok = m.data && m.slot; if (ok) { // Rehash: @@ -451,7 +451,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { _cx_value* d = self->data; chash_slot* s = self->slot; intptr_t i = (intptr_t)(_val - d), j = i, k; - const intptr_t _cap = self->bucket.count; + const intptr_t _cap = self->bucket_count; _cx_memb(_value_drop)(_val); for (;;) { /* delete without leaving tombstone */ if (++j == _cap) diff --git a/include/stc/forward.h b/include/stc/forward.h index 78ec23a2..ae49dc31 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -101,7 +101,7 @@ typedef union { SELF##_node *last; \ } SELF -typedef struct { uint8_t hashx/*, psl*/; } chash_slot; +typedef struct { uint8_t hashx; } chash_slot; #define _c_chash_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \ typedef KEY SELF##_key; \ @@ -124,8 +124,7 @@ typedef struct { uint8_t hashx/*, psl*/; } chash_slot; typedef struct SELF { \ SELF##_value* data; \ chash_slot* slot; \ - intptr_t size; \ - struct { uint64_t count: 48, maxpsl: 16; } bucket; \ + intptr_t size, bucket_count; \ } SELF #define _c_aatree_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \ diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp index 05ec33e7..886bb345 100644 --- a/misc/benchmarks/shootout_hashmaps.cpp +++ b/misc/benchmarks/shootout_hashmaps.cpp @@ -2,7 +2,7 @@ #include #include -#define MAX_LOAD_FACTOR 85 +#define MAX_LOAD_FACTOR 80 #ifdef __cplusplus #include @@ -335,8 +335,8 @@ int main(int argc, char* argv[]) printf("\nT1: Insert %g mill. random keys range [0, 2^%u): map[rnd] = i;\n", N1/1000000.0, keybits); RUN_TEST(1) - //printf("\nT2: Insert %g mill. SEQUENTIAL keys, erase them in same order:\n", N2/1000000.0); - //RUN_TEST(2) + printf("\nT2: Insert %g mill. SEQUENTIAL keys, erase them in same order:\n", N2/1000000.0); + RUN_TEST(2) printf("\nT3: Erase all elements by lookup (%u mill. random inserts), key range [0, 2^%u)\n", n_mill*2, keybits); RUN_TEST(3) -- cgit v1.2.3 From feea8547482d8822a288977201e08eded1551e59 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 21 Apr 2023 14:41:47 +0200 Subject: Householding. --- include/stc/ccommon.h | 11 ++++++ include/stc/cmap.h | 67 +++++++++++++++-------------------- include/stc/crand.h | 13 ------- misc/benchmarks/shootout_hashmaps.cpp | 6 ++-- 4 files changed, 43 insertions(+), 54 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 0735e855..2453143c 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -216,6 +216,17 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle, #define c_drop(C, ...) \ do { c_forlist (_i, C*, {__VA_ARGS__}) C##_drop(*_i.ref); } while(0) +#if defined(__SIZEOF_INT128__) + #define c_umul128(a, b, lo, hi) \ + do { __uint128_t _z = (__uint128_t)(a)*(b); \ + *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0) +#elif defined(_MSC_VER) && defined(_WIN64) + #include + #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi))) +#elif defined(__x86_64__) + #define c_umul128(a, b, lo, hi) \ + asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) +#endif #endif // CCOMMON_H_INCLUDED #undef STC_API diff --git a/include/stc/cmap.h b/include/stc/cmap.h index d0ad7886..3fea78f0 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -53,7 +53,7 @@ int main(void) { #include "forward.h" #include #include -typedef struct { intptr_t idx; uint8_t hashx; } chash_bucket; +typedef struct { intptr_t idx; uint8_t hashx, found; } chash_bucket; #endif // CMAP_H_INCLUDED #ifndef _i_prefix @@ -71,10 +71,10 @@ typedef struct { intptr_t idx; uint8_t hashx; } chash_bucket; #endif #define _i_ishash #ifndef i_max_load_factor - #define i_max_load_factor 0.85f + #define i_max_load_factor 0.82f #endif -#ifndef i_expandby - #define i_expandby 1 +#ifndef i_sizebits + #define i_sizebits 32 #endif #include "priv/template.h" #ifndef i_is_forward @@ -113,7 +113,7 @@ STC_INLINE intptr_t _cx_memb(_bucket_count)(_cx_self* map) { return map->buc STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* map) { return (intptr_t)((float)map->bucket_count * (i_max_load_factor)); } STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) - { return self->size && self->slot[_cx_memb(_bucket_)(self, &rkey).idx].hashx; } + { return _cx_memb(_bucket_)(self, &rkey).found; } #ifndef _i_isset STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped); @@ -124,7 +124,7 @@ STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rke STC_INLINE const _cx_mapped* _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey) { chash_bucket b = _cx_memb(_bucket_)(self, &rkey); - assert(self->slot[b.idx].hashx); + assert(b.found); return &self->data[b.idx].second; } STC_INLINE _cx_mapped* @@ -235,19 +235,19 @@ _cx_memb(_advance)(_cx_iter it, size_t n) { STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) { - intptr_t idx; - if (self->size && self->slot[idx = _cx_memb(_bucket_)(self, &rkey).idx].hashx) - return c_LITERAL(_cx_iter){self->data + idx, + chash_bucket b; + if (self->size && (b = _cx_memb(_bucket_)(self, &rkey)).found) + return c_LITERAL(_cx_iter){self->data + b.idx, self->data + self->bucket_count, - self->slot + idx}; + self->slot + b.idx}; return _cx_memb(_end)(self); } STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey) { - intptr_t idx; - if (self->size && self->slot[idx = _cx_memb(_bucket_)(self, &rkey).idx].hashx) - return self->data + idx; + chash_bucket b; + if (self->size && (b = _cx_memb(_bucket_)(self, &rkey)).found) + return self->data + b.idx; return NULL; } @@ -257,10 +257,10 @@ _cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey) STC_INLINE int _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { - if (self->size == 0) - return 0; - chash_bucket b = _cx_memb(_bucket_)(self, &rkey); - return self->slot[b.idx].hashx ? _cx_memb(_erase_entry)(self, self->data + b.idx), 1 : 0; + chash_bucket b = {0}; + if (self->size && (b = _cx_memb(_bucket_)(self, &rkey)).found) + _cx_memb(_erase_entry)(self, self->data + b.idx); + return b.found; } STC_INLINE _cx_iter @@ -285,18 +285,12 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { #if defined(i_implement) #ifndef CMAP_H_INCLUDED -STC_INLINE int64_t fastrange_1(uint64_t x, uint64_t n) - { return (int64_t)((uint32_t)x*n >> 32); } // n < 2^32 - -STC_INLINE int64_t fastrange_2(uint64_t x, uint64_t n) - { return (int64_t)(x & (n - 1)); } // n power of 2. - -STC_INLINE uint64_t next_power_of_2(uint64_t n) { - n--; - n |= n >> 1, n |= n >> 2; - n |= n >> 4, n |= n >> 8; - n |= n >> 16, n |= n >> 32; - return n + 1; +STC_INLINE int64_t fastrange_32(uint64_t x, uint64_t n) + { return (int64_t)((uint32_t)x*n >> 32); } // n < 2^31 + +STC_INLINE int64_t fastrange_64(uint64_t x, uint64_t n) { + uint64_t lo, hi; c_umul128(x, n, &lo, &hi); + return (int64_t)hi; } #endif // CMAP_H_INCLUDED @@ -362,13 +356,13 @@ STC_DEF chash_bucket _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); intptr_t _cap = self->bucket_count; - chash_bucket b = {c_PASTE(fastrange_,i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; + chash_bucket b = {c_PASTE(fastrange_,i_sizebits)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; const chash_slot* s = self->slot; while (s[b.idx].hashx) { if (s[b.idx].hashx == b.hashx) { const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + b.idx)); if (i_eq((&_raw), rkeyptr)) - break; + {b.found = true; break;} } if (++b.idx == _cap) b.idx = 0; @@ -385,7 +379,8 @@ _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { chash_bucket b = _cx_memb(_bucket_)(self, &rkey); res.ref = &self->data[b.idx]; - if ((res.inserted = !self->slot[b.idx].hashx)) { + if (!b.found) { + res.inserted = true; self->slot[b.idx].hashx = b.hashx; ++self->size; } @@ -418,11 +413,7 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { if (_newcap != self->size && _newcap <= _oldbucks) return true; intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4; - #if i_expandby == 2 - _newbucks = (intptr_t)next_power_of_2(_newbucks); - #else _newbucks |= 1; - #endif _cx_self m = { (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), (chash_slot *)i_calloc(_newbucks + 1, sizeof(chash_slot)), @@ -459,7 +450,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { if (! s[j].hashx) break; const _cx_keyraw _raw = i_keyto(_i_keyref(d + j)); - k = (intptr_t)c_PASTE(fastrange_,i_expandby)(i_hash((&_raw)), (uint64_t)_cap); + k = (intptr_t)c_PASTE(fastrange_,i_sizebits)(i_hash((&_raw)), (uint64_t)_cap); if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ d[i] = d[j], s[i] = s[j], i = j; } @@ -469,7 +460,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { #endif // i_implement #undef i_max_load_factor -#undef i_expandby +#undef i_sizebits #undef _i_isset #undef _i_ismap #undef _i_ishash diff --git a/include/stc/crand.h b/include/stc/crand.h index a1b7250d..f566c1cf 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -127,18 +127,6 @@ STC_DEF crand_unif_t crand_unif_init(int64_t low, int64_t high) { return dist; } -#if defined(__SIZEOF_INT128__) - #define c_umul128(a, b, lo, hi) \ - do { __uint128_t _z = (__uint128_t)(a)*(b); \ - *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0) -#elif defined(_MSC_VER) && defined(_WIN64) - #include - #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi))) -#elif defined(__x86_64__) - #define c_umul128(a, b, lo, hi) \ - asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) -#endif - /* Int64 uniform distributed RNG, range [low, high]. */ STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) { uint64_t lo, hi; @@ -164,7 +152,6 @@ STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) { dist->next = u2*m; return (u1*m)*dist->stddev + dist->mean; } - #endif #endif #undef i_opt diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp index 886bb345..8eb36b34 100644 --- a/misc/benchmarks/shootout_hashmaps.cpp +++ b/misc/benchmarks/shootout_hashmaps.cpp @@ -35,7 +35,7 @@ KHASH_MAP_INIT_INT64(ii, IValue) // cmap template expansion #define i_key IKey #define i_val IValue -#define i_expandby 2 // enable 2^K buckets like the rest. +//#define i_sizebits 64 // more than 2.2 billion elements? #define i_tag ii #define i_max_load_factor MAX_LOAD_FACTOR / 100.0f #include @@ -335,8 +335,8 @@ int main(int argc, char* argv[]) printf("\nT1: Insert %g mill. random keys range [0, 2^%u): map[rnd] = i;\n", N1/1000000.0, keybits); RUN_TEST(1) - printf("\nT2: Insert %g mill. SEQUENTIAL keys, erase them in same order:\n", N2/1000000.0); - RUN_TEST(2) + //printf("\nT2: Insert %g mill. SEQUENTIAL keys, erase them in same order:\n", N2/1000000.0); + //RUN_TEST(2) printf("\nT3: Erase all elements by lookup (%u mill. random inserts), key range [0, 2^%u)\n", n_mill*2, keybits); RUN_TEST(3) -- cgit v1.2.3 From e78f0ed961c3d0f34b63e113247194fc9eafa636 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sat, 22 Apr 2023 22:47:53 +0200 Subject: Fixed a regression bug in cmap_X_contains()- --- include/stc/cmap.h | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 3fea78f0..986771e5 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -113,7 +113,7 @@ STC_INLINE intptr_t _cx_memb(_bucket_count)(_cx_self* map) { return map->buc STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* map) { return (intptr_t)((float)map->bucket_count * (i_max_load_factor)); } STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) - { return _cx_memb(_bucket_)(self, &rkey).found; } + { return self->size && _cx_memb(_bucket_)(self, &rkey).found; } #ifndef _i_isset STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped); @@ -361,11 +361,12 @@ _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { while (s[b.idx].hashx) { if (s[b.idx].hashx == b.hashx) { const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + b.idx)); - if (i_eq((&_raw), rkeyptr)) - {b.found = true; break;} + if (i_eq((&_raw), rkeyptr)) { + b.found = true; + break; + } } - if (++b.idx == _cap) - b.idx = 0; + if (++b.idx == _cap) b.idx = 0; } return b; } @@ -380,8 +381,8 @@ _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { chash_bucket b = _cx_memb(_bucket_)(self, &rkey); res.ref = &self->data[b.idx]; if (!b.found) { - res.inserted = true; self->slot[b.idx].hashx = b.hashx; + res.inserted = true; ++self->size; } return res; @@ -427,8 +428,8 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { for (intptr_t i = 0; i < _oldbucks; ++i, ++d) if ((s++)->hashx) { _cx_keyraw r = i_keyto(_i_keyref(d)); chash_bucket b = _cx_memb(_bucket_)(&m, &r); - m.data[b.idx] = *d; // move m.slot[b.idx].hashx = b.hashx; + m.data[b.idx] = *d; // move } c_swap(_cx_self, self, &m); } @@ -441,18 +442,20 @@ STC_DEF void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { _cx_value* d = self->data; chash_slot* s = self->slot; - intptr_t i = (intptr_t)(_val - d), j = i, k; + intptr_t i = _val - d, j = i, k; const intptr_t _cap = self->bucket_count; _cx_memb(_value_drop)(_val); - for (;;) { /* delete without leaving tombstone */ - if (++j == _cap) - j = 0; + for (;;) { // delete without leaving tombstone + if (++j == _cap) j = 0; if (! s[j].hashx) break; const _cx_keyraw _raw = i_keyto(_i_keyref(d + j)); k = (intptr_t)c_PASTE(fastrange_,i_sizebits)(i_hash((&_raw)), (uint64_t)_cap); - if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ - d[i] = d[j], s[i] = s[j], i = j; + if ((j < i) ^ (k <= i) ^ (k > j)) { // is k outside (i, j]? + d[i] = d[j]; + s[i] = s[j]; + i = j; + } } s[i].hashx = 0; --self->size; -- cgit v1.2.3 From ee619c6ef061c4adb2b13985ebb7d2c67551c84a Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 23 Apr 2023 20:02:29 +0200 Subject: Tuned cmap.h and hash function. --- include/stc/ccommon.h | 6 ++-- include/stc/cmap.h | 40 +++++++++++++-------- misc/benchmarks/shootout_hashmaps.cpp | 1 - misc/benchmarks/various/sso_bench.cpp | 67 +++++++++++++++++++++-------------- 4 files changed, 68 insertions(+), 46 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 2453143c..bac25fb1 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -147,13 +147,13 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { case 0: return 1; } const uint8_t *x = (const uint8_t*)key; - uint64_t h = *x*0x811c9dc5ULL, n = (uint64_t)len >> 3; + uint64_t h = *x | (*x << 15), n = (uint64_t)len >> 3; len &= 7; while (n--) { memcpy(&u8, x, 8), x += 8; - h = (h ^ u8)*0x01000193ULL; + h = (h ^ u8)*0x9e3779b97f4a7c15; } - while (len--) h = (h ^ *x++)*0x01000193ULL; + while (len--) h = (h ^ *x++)*0xbf58476d1ce4e5b9; return h; } diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 986771e5..1aeb63df 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -71,10 +71,10 @@ typedef struct { intptr_t idx; uint8_t hashx, found; } chash_bucket; #endif #define _i_ishash #ifndef i_max_load_factor - #define i_max_load_factor 0.82f + #define i_max_load_factor 0.80f #endif -#ifndef i_sizebits - #define i_sizebits 32 +#ifndef i_expandby + #define i_expandby 1 #endif #include "priv/template.h" #ifndef i_is_forward @@ -285,20 +285,26 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { #if defined(i_implement) #ifndef CMAP_H_INCLUDED -STC_INLINE int64_t fastrange_32(uint64_t x, uint64_t n) - { return (int64_t)((uint32_t)x*n >> 32); } // n < 2^31 - -STC_INLINE int64_t fastrange_64(uint64_t x, uint64_t n) { - uint64_t lo, hi; c_umul128(x, n, &lo, &hi); - return (int64_t)hi; +STC_INLINE int64_t fastrange_1(uint64_t x, uint64_t n) + { return (int64_t)((uint32_t)x*n >> 32); } // n < 2^32 + +STC_INLINE int64_t fastrange_2(uint64_t x, uint64_t n) + { return (int64_t)(x & (n - 1)); } // n power of 2. + +STC_INLINE uint64_t next_power_of_2(uint64_t n) { + n--; + n |= n >> 1, n |= n >> 2; + n |= n >> 4, n |= n >> 8; + n |= n >> 16, n |= n >> 32; + return n + 1; } #endif // CMAP_H_INCLUDED STC_DEF _cx_self _cx_memb(_with_capacity)(const intptr_t cap) { - _cx_self h = {0}; - _cx_memb(_reserve)(&h, cap); - return h; + _cx_self map = {0}; + _cx_memb(_reserve)(&map, cap); + return map; } STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) { @@ -356,7 +362,7 @@ STC_DEF chash_bucket _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); intptr_t _cap = self->bucket_count; - chash_bucket b = {c_PASTE(fastrange_,i_sizebits)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; + chash_bucket b = {c_PASTE(fastrange_,i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; const chash_slot* s = self->slot; while (s[b.idx].hashx) { if (s[b.idx].hashx == b.hashx) { @@ -414,7 +420,11 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { if (_newcap != self->size && _newcap <= _oldbucks) return true; intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4; + #if i_expandby == 2 + _newbucks = (intptr_t)next_power_of_2(_newbucks); + #else _newbucks |= 1; + #endif _cx_self m = { (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), (chash_slot *)i_calloc(_newbucks + 1, sizeof(chash_slot)), @@ -450,7 +460,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { if (! s[j].hashx) break; const _cx_keyraw _raw = i_keyto(_i_keyref(d + j)); - k = (intptr_t)c_PASTE(fastrange_,i_sizebits)(i_hash((&_raw)), (uint64_t)_cap); + k = (intptr_t)c_PASTE(fastrange_,i_expandby)(i_hash((&_raw)), (uint64_t)_cap); if ((j < i) ^ (k <= i) ^ (k > j)) { // is k outside (i, j]? d[i] = d[j]; s[i] = s[j]; @@ -463,7 +473,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { #endif // i_implement #undef i_max_load_factor -#undef i_sizebits +#undef i_expandby #undef _i_isset #undef _i_ismap #undef _i_ishash diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp index 8eb36b34..54680402 100644 --- a/misc/benchmarks/shootout_hashmaps.cpp +++ b/misc/benchmarks/shootout_hashmaps.cpp @@ -35,7 +35,6 @@ KHASH_MAP_INIT_INT64(ii, IValue) // cmap template expansion #define i_key IKey #define i_val IValue -//#define i_sizebits 64 // more than 2.2 billion elements? #define i_tag ii #define i_max_load_factor MAX_LOAD_FACTOR / 100.0f #include diff --git a/misc/benchmarks/various/sso_bench.cpp b/misc/benchmarks/various/sso_bench.cpp index 9841c296..71d123e8 100644 --- a/misc/benchmarks/various/sso_bench.cpp +++ b/misc/benchmarks/various/sso_bench.cpp @@ -9,19 +9,32 @@ #define i_val_str #include -#define i_type StcSet -#define i_expandby 2 -#define i_val_str -#include - #include using StdVec = std::vector; -//#include "../external/ankerl/robin_hood.h" -//using StdSet = robin_hood::unordered_flat_set; #include -using StdSet = std::unordered_set; +#include "../external/ankerl/robin_hood.h" + +struct string_hash { + using is_transparent = void; + [[nodiscard]] size_t operator()(const char *txt) const { + return std::hash{}(txt); + } + [[nodiscard]] size_t operator()(std::string_view txt) const { + return std::hash{}(txt); + } + [[nodiscard]] size_t operator()(const std::string &txt) const { + return std::hash{}(txt); + } +}; +using StdSet = robin_hood::unordered_flat_set>; +//using StdSet = std::unordered_set; + +#define i_type StcSet +#define i_val_str +//#define i_hash(txtp) std::hash{}(*txtp) +#include static const int BENCHMARK_SIZE = 250000; @@ -43,28 +56,28 @@ static inline const char* randomString(int strsize) { -static inline void addRandomString(StdVec& vec, int strsize) { - vec.push_back(randomString(strsize)); +static inline void addRandomString(StdVec& vec, const char* str) { + vec.push_back(str); } -static inline void addRandomString(StcVec& vec, int strsize) { - StcVec_emplace(&vec, randomString(strsize)); +static inline void addRandomString(StcVec& vec, const char* str) { + StcVec_emplace(&vec, str); } -static inline void addRandomString(StdSet& set, int strsize) { - set.insert(randomString(strsize)); +static inline void addRandomString(StdSet& set, const char* str) { + set.insert(str); } -static inline void addRandomString(StcSet& set, int strsize) { - StcSet_emplace(&set, randomString(strsize)); +static inline void addRandomString(StcSet& set, const char* str) { + StcSet_emplace(&set, str); } -static inline bool getRandomString(const StdSet& set, int strsize) { - return set.find(randomString(strsize)) != set.end(); +static inline bool getRandomString(const StdSet& set, const char* str) { + return set.find(str) != set.end(); } -static inline bool getRandomString(const StcSet& set, int strsize) { - return StcSet_contains(&set, randomString(strsize)); +static inline bool getRandomString(const StcSet& set, const char* str) { + return StcSet_contains(&set, str); } @@ -73,7 +86,7 @@ int benchmark(C& container, const int n, const int strsize) { time_point t1 = std::chrono::high_resolution_clock::now(); for (int i = 0; i < n; i++) - addRandomString(container, strsize); + addRandomString(container, randomString(strsize)); time_point t2 = std::chrono::high_resolution_clock::now(); const auto duration = std::chrono::duration_cast(t2 - t1).count(); @@ -84,12 +97,12 @@ int benchmark(C& container, const int n, const int strsize) { template int benchmark_lookup(C& container, const int n, const int strsize) { for (int i = 0; i < n; i++) - addRandomString(container, strsize); + addRandomString(container, randomString(strsize)); time_point t1 = std::chrono::high_resolution_clock::now(); int found = 0; for (int i = 0; i < n; i++) - found += (int)getRandomString(container, strsize); + found += (int)getRandomString(container, randomString(strsize)); time_point t2 = std::chrono::high_resolution_clock::now(); const auto duration = std::chrono::duration_cast(t2 - t1).count(); @@ -97,9 +110,9 @@ int benchmark_lookup(C& container, const int n, const int strsize) { return (int)duration; } - +#include int main() { - uint64_t seed = 4321; + uint64_t seed = time(NULL); // 4321; int sum, n; // VECTOR WITH STRINGS @@ -154,7 +167,7 @@ int main() { csrand(seed); sum = 0, n = 0; std::cerr << "\nstrsize\tmsecs\tfind: robin_hood::unordered_flat_set, size=" << BENCHMARK_SIZE/2 << "\n"; - for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { StdSet set; set.reserve(BENCHMARK_SIZE/2); sum += benchmark_lookup(set, BENCHMARK_SIZE/2, strsize), ++n; std::cout << '\t' << *set.begin() << '\n'; @@ -164,7 +177,7 @@ int main() { csrand(seed); sum = 0, n = 0; std::cerr << "\nstrsize\tmsecs\tfind: cset, size=" << BENCHMARK_SIZE/2 << "\n"; - for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/2); sum += benchmark_lookup(set, BENCHMARK_SIZE/2, strsize), ++n; std::cout << '\t' << cstr_str(StcSet_begin(&set).ref) << '\n'; -- cgit v1.2.3 From 3139f550e2af86003e08f0795e395690c120d63e Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 24 Apr 2023 06:38:10 +0200 Subject: Set i_expandby 2 by default. --- include/stc/cmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 1aeb63df..34a9ec79 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -74,7 +74,7 @@ typedef struct { intptr_t idx; uint8_t hashx, found; } chash_bucket; #define i_max_load_factor 0.80f #endif #ifndef i_expandby - #define i_expandby 1 + #define i_expandby 2 #endif #include "priv/template.h" #ifndef i_is_forward -- cgit v1.2.3 From 38aab1d6ae8f929084ae6c67256a87760cc07705 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 24 Apr 2023 08:52:15 +0200 Subject: Fixed another cmap issue --- include/stc/ccommon.h | 2 +- include/stc/cmap.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index bac25fb1..121bc566 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -147,7 +147,7 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { case 0: return 1; } const uint8_t *x = (const uint8_t*)key; - uint64_t h = *x | (*x << 15), n = (uint64_t)len >> 3; + uint64_t h = (*x << 15) - *x, n = (uint64_t)len >> 3; len &= 7; while (n--) { memcpy(&u8, x, 8), x += 8; diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 34a9ec79..533e8a16 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -380,8 +380,8 @@ _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { STC_DEF _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { _cx_result res = {NULL}; - if (self->size + 2 > (intptr_t)((float)self->bucket_count * (i_max_load_factor))) - if (!_cx_memb(_reserve)(self, (intptr_t)(self->size*3/2))) + if (self->size >= (intptr_t)((float)self->bucket_count * (i_max_load_factor))) + if (!_cx_memb(_reserve)(self, (intptr_t)(self->size*3/2 + 2))) return res; chash_bucket b = _cx_memb(_bucket_)(self, &rkey); -- cgit v1.2.3 From 3dcd44ce50df89e698bc9d85cc36518f033b8462 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 24 Apr 2023 09:42:50 +0200 Subject: Final hash constants tunings. --- include/stc/ccommon.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 121bc566..c1f73e20 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -151,9 +151,9 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { len &= 7; while (n--) { memcpy(&u8, x, 8), x += 8; - h = (h ^ u8)*0x9e3779b97f4a7c15; + h = (h ^ u8)*0xc6a4a7935bd1e99d; } - while (len--) h = (h ^ *x++)*0xbf58476d1ce4e5b9; + while (len--) h = (h ^ *x++)*0x100000001b3; return h; } -- cgit v1.2.3 From bf118447590bd10d8c6b205a19b25038d84274c2 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 24 Apr 2023 14:00:58 +0200 Subject: Final hashing tweak --- include/stc/ccommon.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index c1f73e20..4f9fa398 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -147,14 +147,14 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { case 0: return 1; } const uint8_t *x = (const uint8_t*)key; - uint64_t h = (*x << 15) - *x, n = (uint64_t)len >> 3; + uint64_t h = *x << 7, n = (uint64_t)len >> 3; len &= 7; while (n--) { memcpy(&u8, x, 8), x += 8; h = (h ^ u8)*0xc6a4a7935bd1e99d; } while (len--) h = (h ^ *x++)*0x100000001b3; - return h; + return h ^ c_ROTL(h, 26); } STC_INLINE uint64_t cstrhash(const char *str) -- cgit v1.2.3 From 9d5766ae528595050dcfe0db4c1c3c0c058b186c Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Wed, 26 Apr 2023 13:13:47 +0200 Subject: Internal. --- include/stc/cmap.h | 1 + include/stc/forward.h | 2 +- misc/benchmarks/plotbench/run_clang.sh | 10 +++++----- misc/benchmarks/plotbench/run_gcc.sh | 10 +++++----- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 533e8a16..65e4a544 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -53,6 +53,7 @@ int main(void) { #include "forward.h" #include #include +struct chash_slot { uint8_t hashx; }; typedef struct { intptr_t idx; uint8_t hashx, found; } chash_bucket; #endif // CMAP_H_INCLUDED diff --git a/include/stc/forward.h b/include/stc/forward.h index ae49dc31..b534e48b 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -101,7 +101,7 @@ typedef union { SELF##_node *last; \ } SELF -typedef struct { uint8_t hashx; } chash_slot; +typedef struct chash_slot chash_slot; #define _c_chash_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \ typedef KEY SELF##_key; \ diff --git a/misc/benchmarks/plotbench/run_clang.sh b/misc/benchmarks/plotbench/run_clang.sh index 096e71be..c9dbac31 100644 --- a/misc/benchmarks/plotbench/run_clang.sh +++ b/misc/benchmarks/plotbench/run_clang.sh @@ -1,10 +1,10 @@ exe='' if [ "$OS" = "Windows_NT" ] ; then exe=".exe" ; fi -clang++ -I../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp -clang++ -I../include -O3 -o clist_benchmark$exe clist_benchmark.cpp -clang++ -I../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp -clang++ -I../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp -clang++ -I../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp +clang++ -I../../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp +clang++ -I../../include -O3 -o clist_benchmark$exe clist_benchmark.cpp +clang++ -I../../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp +clang++ -I../../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp +clang++ -I../../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp c='Win-Clang-14.0.1' ./cdeq_benchmark$exe $c diff --git a/misc/benchmarks/plotbench/run_gcc.sh b/misc/benchmarks/plotbench/run_gcc.sh index 5249ed1e..14d89b9a 100644 --- a/misc/benchmarks/plotbench/run_gcc.sh +++ b/misc/benchmarks/plotbench/run_gcc.sh @@ -1,8 +1,8 @@ -g++ -I../include -O3 -o cdeq_benchmark cdeq_benchmark.cpp -g++ -I../include -O3 -o clist_benchmark clist_benchmark.cpp -g++ -I../include -O3 -o cmap_benchmark cmap_benchmark.cpp -g++ -I../include -O3 -o csmap_benchmark csmap_benchmark.cpp -g++ -I../include -O3 -o cvec_benchmark cvec_benchmark.cpp +g++ -I../../include -O3 -o cdeq_benchmark cdeq_benchmark.cpp +g++ -I../../include -O3 -o clist_benchmark clist_benchmark.cpp +g++ -I../../include -O3 -o cmap_benchmark cmap_benchmark.cpp +g++ -I../../include -O3 -o csmap_benchmark csmap_benchmark.cpp +g++ -I../../include -O3 -o cvec_benchmark cvec_benchmark.cpp c='Mingw-g++-11.3.0' ./cdeq_benchmark $c -- cgit v1.2.3 From ba3f2284731e50100d249cf1d825b8d24efad658 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 27 Apr 2023 12:41:24 +0200 Subject: removing compiler warning ++. --- README.md | 2 +- docs/cmap_api.md | 4 ++-- include/stc/algo/filter.h | 9 ++++----- include/stc/ccommon.h | 2 +- include/stc/cmap.h | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 65d00324..f571c280 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ STC - Smart Template Containers =============================== -### [Version 4.2](#version-history) +### [Version 4.3 beta](#version-history) --- Description diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 94f1c54e..cdb57534 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -9,8 +9,8 @@ hashing (aka open addressing) with linear probing, and without leaving tombstone ***Iterator invalidation***: References and iterators are invalidated after erase. No iterators are invalidated after insert, unless the hash-table need to be extended. The hash table size can be reserved prior to inserts if the total max size is known. -The order of elements is preserved after erase and insert. This makes it possible to erase individual elements while iterating -through the container by using the returned iterator from *erase_at()*, which references the next element. +The order of elements may not be preserved after erase. It is still possible to erase elements when iterating through +the container by setting the iterator to the value returned from *erase_at()*, which references the next element. Note that a small number of elements may be visited twice when doing this, but all elements will be visited. See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/container/unordered_map) for a functional description. diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index e133577c..db076ae4 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -89,8 +89,7 @@ int main() // Use with: clist, cmap, cset, csmap, csset: #define c_erase_if(it, C, cnt, pred) do { \ C* _cnt = &cnt; \ - intptr_t _index = 0; \ - for (C##_iter it = C##_begin(_cnt); it.ref; ++_index) { \ + for (C##_iter it = C##_begin(_cnt); it.ref; ) { \ if (pred) it = C##_erase_at(_cnt, it); \ else C##_next(&it); \ } \ @@ -100,11 +99,11 @@ int main() // Use with: cstack, cvec, cdeq, cqueue: #define c_eraseremove_if(it, C, cnt, pred) do { \ C* _cnt = &cnt; \ - intptr_t _n = 0, _index = 0; \ + intptr_t _n = 0; \ C##_iter it = C##_begin(_cnt), _i; \ while (it.ref && !(pred)) \ - C##_next(&it), ++_index; \ - for (_i = it; it.ref; C##_next(&it), ++_index) \ + C##_next(&it); \ + for (_i = it; it.ref; C##_next(&it)) \ if (pred) C##_value_drop(it.ref), ++_n; \ else *_i.ref = *it.ref, C##_next(&_i); \ _cnt->_len -= _n; \ diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 4f9fa398..73a3d5ef 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -147,7 +147,7 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { case 0: return 1; } const uint8_t *x = (const uint8_t*)key; - uint64_t h = *x << 7, n = (uint64_t)len >> 3; + uint64_t h = (uint64_t)*x << 7, n = (uint64_t)len >> 3; len &= 7; while (n--) { memcpy(&u8, x, 8), x += 8; diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 65e4a544..9f21b811 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -422,7 +422,7 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { return true; intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4; #if i_expandby == 2 - _newbucks = (intptr_t)next_power_of_2(_newbucks); + _newbucks = (intptr_t)next_power_of_2((uint64_t)_newbucks); #else _newbucks |= 1; #endif -- cgit v1.2.3 From a922157394a9a3e0cffe26a5fa4d29c9d78ecc06 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 27 Apr 2023 17:55:31 +0200 Subject: Reshuffled code in csmap.h and cmap.h --- include/stc/cmap.h | 81 ++++++++++++++++++++-------------------- include/stc/csmap.h | 105 ++++++++++++++++++++++++++-------------------------- 2 files changed, 94 insertions(+), 92 deletions(-) diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 9f21b811..cd8878ea 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -70,13 +70,6 @@ typedef struct { intptr_t idx; uint8_t hashx, found; } chash_bucket; #define _i_SET_ONLY c_false #define _i_keyref(vp) (&(vp)->first) #endif -#define _i_ishash -#ifndef i_max_load_factor - #define i_max_load_factor 0.80f -#endif -#ifndef i_expandby - #define i_expandby 2 -#endif #include "priv/template.h" #ifndef i_is_forward _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); @@ -104,15 +97,14 @@ STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t capacity); STC_API chash_bucket _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr); STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey); STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val); +STC_API float _cx_memb(_max_load_factor)(const _cx_self* self); +STC_API intptr_t _cx_memb(_capacity)(const _cx_self* map); STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self map = {0}; return map; } STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, (intptr_t)self->size); } -STC_INLINE float _cx_memb(_max_load_factor)(const _cx_self* self) { return (float)(i_max_load_factor); } STC_INLINE bool _cx_memb(_empty)(const _cx_self* map) { return !map->size; } STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* map) { return (intptr_t)map->size; } STC_INLINE intptr_t _cx_memb(_bucket_count)(_cx_self* map) { return map->bucket_count; } -STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* map) - { return (intptr_t)((float)map->bucket_count * (i_max_load_factor)); } STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) { return self->size && _cx_memb(_bucket_)(self, &rkey).found; } @@ -161,14 +153,12 @@ _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe } #endif // !i_no_emplace -STC_INLINE _cx_raw -_cx_memb(_value_toraw)(const _cx_value* val) { +STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* val) { return _i_SET_ONLY( i_keyto(val) ) _i_MAP_ONLY( c_LITERAL(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} ); } -STC_INLINE void -_cx_memb(_value_drop)(_cx_value* _val) { +STC_INLINE void _cx_memb(_value_drop)(_cx_value* _val) { i_keydrop(_i_keyref(_val)); _i_MAP_ONLY( i_valdrop((&_val->second)); ) } @@ -183,14 +173,13 @@ _cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { return _res; } -STC_INLINE _cx_result -_cx_memb(_push)(_cx_self* self, _cx_value _val) { +STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value _val) { _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); if (_res.inserted) *_res.ref = _val; else _cx_memb(_value_drop)(&_val); - return _res; + return _res.ref; } STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) { @@ -209,27 +198,17 @@ STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } -STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { - _cx_iter it = {self->data, self->data+self->bucket_count, self->slot}; - if (it.sref) - while (it.sref->hashx == 0) - ++it.ref, ++it.sref; - if (it.ref == it._end) it.ref = NULL; - return it; -} +STC_API _cx_iter _cx_memb(_begin)(const _cx_self* self); -STC_INLINE _cx_iter -_cx_memb(_end)(const _cx_self* self) +STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) { return c_LITERAL(_cx_iter){NULL}; } -STC_INLINE void -_cx_memb(_next)(_cx_iter* it) { +STC_INLINE void _cx_memb(_next)(_cx_iter* it) { while ((++it->ref, (++it->sref)->hashx == 0)) ; if (it->ref == it->_end) it->ref = NULL; } -STC_INLINE _cx_iter -_cx_memb(_advance)(_cx_iter it, size_t n) { +STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) { while (n-- && it.ref) _cx_memb(_next)(&it); return it; } @@ -284,13 +263,19 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) +#ifndef i_max_load_factor + #define i_max_load_factor 0.80f +#endif +#ifndef i_expandby + #define i_expandby 2 +#endif #ifndef CMAP_H_INCLUDED -STC_INLINE int64_t fastrange_1(uint64_t x, uint64_t n) - { return (int64_t)((uint32_t)x*n >> 32); } // n < 2^32 +STC_INLINE intptr_t fastrange_1(uint64_t x, uint64_t n) + { return (intptr_t)((uint32_t)x*n >> 32); } // n < 2^32 -STC_INLINE int64_t fastrange_2(uint64_t x, uint64_t n) - { return (int64_t)(x & (n - 1)); } // n power of 2. +STC_INLINE intptr_t fastrange_2(uint64_t x, uint64_t n) + { return (intptr_t)(x & (n - 1)); } // n power of 2. STC_INLINE uint64_t next_power_of_2(uint64_t n) { n--; @@ -301,8 +286,24 @@ STC_INLINE uint64_t next_power_of_2(uint64_t n) { } #endif // CMAP_H_INCLUDED -STC_DEF _cx_self -_cx_memb(_with_capacity)(const intptr_t cap) { +STC_DEF _cx_iter _cx_memb(_begin)(const _cx_self* self) { + _cx_iter it = {self->data, self->data+self->bucket_count, self->slot}; + if (it.sref) + while (it.sref->hashx == 0) + ++it.ref, ++it.sref; + if (it.ref == it._end) it.ref = NULL; + return it; +} + +STC_DEF float _cx_memb(_max_load_factor)(const _cx_self* self) { + return (float)(i_max_load_factor); +} + +STC_DEF intptr_t _cx_memb(_capacity)(const _cx_self* map) { + return (intptr_t)((float)map->bucket_count * (i_max_load_factor)); +} + +STC_DEF _cx_self _cx_memb(_with_capacity)(const intptr_t cap) { _cx_self map = {0}; _cx_memb(_reserve)(&map, cap); return map; @@ -471,13 +472,13 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { s[i].hashx = 0; --self->size; } - -#endif // i_implement #undef i_max_load_factor #undef i_expandby +#elif defined i_max_load_factor || defined i_expandby +#error i_max_load_factor and i_expandby may only be defined for the implementation. +#endif // i_implement #undef _i_isset #undef _i_ismap -#undef _i_ishash #undef _i_keyref #undef _i_MAP_ONLY #undef _i_SET_ONLY diff --git a/include/stc/csmap.h b/include/stc/csmap.h index dc0387f7..cd7c1d95 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -97,8 +97,6 @@ STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MA #if !defined i_no_clone STC_API _cx_self _cx_memb(_clone)(_cx_self tree); #endif // !i_no_clone -STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)); -STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val); STC_API void _cx_memb(_drop)(_cx_self* self); STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t cap); STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out); @@ -108,6 +106,7 @@ STC_API _cx_value* _cx_memb(_back)(const _cx_self* self); STC_API int _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey); STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it); STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2); +STC_API _cx_iter _cx_memb(_begin)(const _cx_self* self); STC_API void _cx_memb(_next)(_cx_iter* it); STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self tree = {0}; return tree; } @@ -184,17 +183,6 @@ _cx_memb(_shrink_to_fit)(_cx_self *self) { { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; } #endif // !_i_isset -STC_INLINE _cx_iter -_cx_memb(_begin)(const _cx_self* self) { - _cx_iter it; - it.ref = NULL; - it._d = self->nodes, it._top = 0; - it._tn = self->root; - if (it._tn) - _cx_memb(_next)(&it); - return it; -} - STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) { (void)self; @@ -220,7 +208,30 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { return true; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) { +static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey); + +STC_INLINE _cx_result +_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { + _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); + if (_res.inserted) + { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} + else + { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )} + return _res; +} + +STC_INLINE _cx_value* +_cx_memb(_push)(_cx_self* self, _cx_value _val) { + _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); + if (_res.inserted) + *_res.ref = _val; + else + _cx_memb(_value_drop)(&_val); + return _res.ref; +} + +STC_INLINE void +_cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) { while (n--) #if defined _i_isset && defined i_no_emplace _cx_memb(_insert)(self, *raw++); @@ -233,12 +244,39 @@ STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) #endif } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) +STC_INLINE _cx_self +_cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) +STC_DEF void +_cx_memb(_next)(_cx_iter *it) { + int32_t tn = it->_tn; + if (it->_top || tn) { + while (tn) { + it->_st[it->_top++] = tn; + tn = it->_d[tn].link[0]; + } + tn = it->_st[--it->_top]; + it->_tn = it->_d[tn].link[1]; + it->ref = &it->_d[tn].value; + } else + it->ref = NULL; +} + +STC_DEF _cx_iter +_cx_memb(_begin)(const _cx_self* self) { + _cx_iter it; + it.ref = NULL; + it._d = self->nodes, it._top = 0; + it._tn = self->root; + if (it._tn) + _cx_memb(_next)(&it); + return it; +} + STC_DEF bool _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { if (cap <= self->cap) @@ -287,28 +325,6 @@ _cx_memb(_new_node_)(_cx_self* self, int level) { return tn; } -static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey); - -STC_DEF _cx_result -_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); - if (_res.inserted) - { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} - else - { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )} - return _res; -} - -STC_DEF _cx_result -_cx_memb(_push)(_cx_self* self, _cx_value _val) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); - if (_res.inserted) - *_res.ref = _val; - else - _cx_memb(_value_drop)(&_val); - return _res; -} - #ifndef _i_isset STC_DEF _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) { @@ -367,21 +383,6 @@ _cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey) { return it; } -STC_DEF void -_cx_memb(_next)(_cx_iter *it) { - int32_t tn = it->_tn; - if (it->_top || tn) { - while (tn) { - it->_st[it->_top++] = tn; - tn = it->_d[tn].link[0]; - } - tn = it->_st[--it->_top]; - it->_tn = it->_d[tn].link[1]; - it->ref = &it->_d[tn].value; - } else - it->ref = NULL; -} - STC_DEF int32_t _cx_memb(_skew_)(_cx_node *d, int32_t tn) { if (tn && d[d[tn].link[0]].level == d[tn].level) { -- cgit v1.2.3 From 49e7d9cc0a888b0b19aa4e737d55a2bc33bec824 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 28 Apr 2023 17:01:58 +0200 Subject: Removed crandom.h and altnames.h. Housholding. --- README.md | 8 +- include/stc/algo/crange.h | 4 +- include/stc/algo/csort.h | 20 ++--- include/stc/carc.h | 2 - include/stc/cbox.h | 2 - include/stc/ccommon.h | 1 - include/stc/clist.h | 2 - include/stc/cmap.h | 21 ++--- include/stc/cpque.h | 3 - include/stc/cqueue.h | 2 - include/stc/crandom.h | 197 -------------------------------------------- include/stc/cset.h | 3 - include/stc/csmap.h | 13 ++- include/stc/csset.h | 3 - include/stc/cstack.h | 2 - include/stc/cvec.h | 2 - include/stc/priv/altnames.h | 34 -------- 17 files changed, 33 insertions(+), 286 deletions(-) delete mode 100644 include/stc/crandom.h delete mode 100644 include/stc/priv/altnames.h diff --git a/README.md b/README.md index f571c280..74c2238f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ STC - Smart Template Containers =============================== -### [Version 4.3 beta](#version-history) +### [Version 4.3 RC](#version-history) --- Description @@ -611,6 +611,12 @@ STC is generally very memory efficient. Memory usage for the different container --- # Version History + +## Version 4.3 +- Removed deprecated uppercase flow-control macro names. +- Removed deprecated crandom.h. Use crand.h with new API. +- Improved default string hash function. + ## Version 4.2 - New home! And online single headers for https://godbolt.org - Library: https://github.com/stclib/STC diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h index ca06c258..56c317da 100644 --- a/include/stc/algo/crange.h +++ b/include/stc/algo/crange.h @@ -63,10 +63,10 @@ STC_INLINE crange crange_make_3(crange_value start, crange_value stop, crange_va STC_INLINE crange_iter crange_begin(crange* self) { self->value = self->start; crange_iter it = {&self->value, self->end, self->step}; return it; } -STC_INLINE crange_iter crange_end(crange* self) +STC_INLINE crange_iter crange_end(crange* self) { crange_iter it = {NULL}; return it; } -STC_INLINE void crange_next(crange_iter* it) +STC_INLINE void crange_next(crange_iter* it) { *it->ref += it->step; if ((it->step > 0) == (*it->ref > it->end)) it->ref = NULL; } #endif diff --git a/include/stc/algo/csort.h b/include/stc/algo/csort.h index 53fe9fcc..e01a2893 100644 --- a/include/stc/algo/csort.h +++ b/include/stc/algo/csort.h @@ -20,9 +20,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "../ccommon.h" -#include "../priv/template.h" - /* Generic Quicksort in C, performs as fast as c++ std::sort(). template params: #define i_val - value type [required] @@ -44,10 +41,13 @@ int main() { puts(""); } */ +#include "../ccommon.h" +#define _i_prefix csort_ +#include "../priv/template.h" -typedef i_val c_PASTE(c_CONCAT(csort_, i_tag), _value); +typedef i_val _cx_value; -static inline void c_PASTE(cisort_, i_tag)(i_val arr[], intptr_t lo, intptr_t hi) { +static inline void _cx_memb(_insertion)(i_val arr[], intptr_t lo, intptr_t hi) { for (intptr_t j = lo, i = lo + 1; i <= hi; j = i, ++i) { i_val key = arr[i]; while (j >= 0 && (i_less((&key), (&arr[j])))) { @@ -58,7 +58,7 @@ static inline void c_PASTE(cisort_, i_tag)(i_val arr[], intptr_t lo, intptr_t hi } } -static inline void c_PASTE(cqsort_, i_tag)(i_val arr[], intptr_t lo, intptr_t hi) { +static inline void _cx_memb(_quicksort)(i_val arr[], intptr_t lo, intptr_t hi) { intptr_t i = lo, j; while (lo < hi) { i_val pivot = arr[lo + (hi - lo)*7/16]; @@ -77,13 +77,13 @@ static inline void c_PASTE(cqsort_, i_tag)(i_val arr[], intptr_t lo, intptr_t hi c_swap(intptr_t, &hi, &j); } - if (j - lo > 64) c_PASTE(cqsort_, i_tag)(arr, lo, j); - else if (j > lo) c_PASTE(cisort_, i_tag)(arr, lo, j); + if (j - lo > 64) _cx_memb(_quicksort)(arr, lo, j); + else if (j > lo) _cx_memb(_insertion)(arr, lo, j); lo = i; } } -static inline void c_PASTE(csort_, i_tag)(i_val arr[], intptr_t n) - { c_PASTE(cqsort_, i_tag)(arr, 0, n - 1); } +static inline void _cx_self(i_val arr[], intptr_t n) + { _cx_memb(_quicksort)(arr, 0, n - 1); } #include "../priv/template2.h" diff --git a/include/stc/carc.h b/include/stc/carc.h index 8ef80b12..74205caf 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -74,9 +74,7 @@ int main() { #define carc_NULL {NULL, NULL} #endif // CARC_H_INCLUDED -#ifndef _i_prefix #define _i_prefix carc_ -#endif #ifdef i_eq #define _i_eq #endif diff --git a/include/stc/cbox.h b/include/stc/cbox.h index ca88fc66..393b904b 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -67,9 +67,7 @@ int main() { #define cbox_NULL {NULL} #endif // CBOX_H_INCLUDED -#ifndef _i_prefix #define _i_prefix cbox_ -#endif #ifdef i_eq #define _i_eq #endif diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 73a3d5ef..1882646c 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -29,7 +29,6 @@ #include #include #include -#include "priv/altnames.h" #include "priv/raii.h" #define c_NPOS INTPTR_MAX diff --git a/include/stc/clist.h b/include/stc/clist.h index f7fb4152..65a1ac87 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -77,9 +77,7 @@ #endif // CLIST_H_INCLUDED -#ifndef _i_prefix #define _i_prefix clist_ -#endif #include "priv/template.h" #ifndef i_is_forward diff --git a/include/stc/cmap.h b/include/stc/cmap.h index cd8878ea..ec3238f6 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -58,17 +58,16 @@ typedef struct { intptr_t idx; uint8_t hashx, found; } chash_bucket; #endif // CMAP_H_INCLUDED #ifndef _i_prefix -#define _i_prefix cmap_ -#endif -#ifdef _i_isset - #define _i_MAP_ONLY c_false - #define _i_SET_ONLY c_true - #define _i_keyref(vp) (vp) -#else + #define _i_prefix cmap_ #define _i_ismap #define _i_MAP_ONLY c_true #define _i_SET_ONLY c_false #define _i_keyref(vp) (&(vp)->first) +#else + #define _i_isset + #define _i_MAP_ONLY c_false + #define _i_SET_ONLY c_true + #define _i_keyref(vp) (vp) #endif #include "priv/template.h" #ifndef i_is_forward @@ -421,11 +420,9 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { const intptr_t _oldbucks = self->bucket_count; if (_newcap != self->size && _newcap <= _oldbucks) return true; - intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4; + intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) | 1; #if i_expandby == 2 _newbucks = (intptr_t)next_power_of_2((uint64_t)_newbucks); - #else - _newbucks |= 1; #endif _cx_self m = { (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), @@ -472,11 +469,9 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { s[i].hashx = 0; --self->size; } +#endif // i_implement #undef i_max_load_factor #undef i_expandby -#elif defined i_max_load_factor || defined i_expandby -#error i_max_load_factor and i_expandby may only be defined for the implementation. -#endif // i_implement #undef _i_isset #undef _i_ismap #undef _i_keyref diff --git a/include/stc/cpque.h b/include/stc/cpque.h index b95b5020..c76621cd 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -27,10 +27,7 @@ #include "forward.h" #endif -#ifndef _i_prefix #define _i_prefix cpque_ -#endif - #include "priv/template.h" #ifndef i_is_forward _cx_deftypes(_c_cpque_types, _cx_self, i_key); diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 1934305a..254bc834 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -53,9 +53,7 @@ int main() { } */ -#ifndef _i_prefix #define _i_prefix cqueue_ -#endif #define _i_queue #define _pop_front _pop diff --git a/include/stc/crandom.h b/include/stc/crandom.h deleted file mode 100644 index a9374602..00000000 --- a/include/stc/crandom.h +++ /dev/null @@ -1,197 +0,0 @@ -/* MIT License - * - * Copyright (c) 2023 Tyge Løvset - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "ccommon.h" - -#ifndef CRANDOM_H_INCLUDED -#define CRANDOM_H_INCLUDED -/* -// crandom: Pseudo-random number generator -#include "stc/crandom.h" -int main() { - uint64_t seed = 123456789; - stc64_t rng = stc64_new(seed); - stc64_uniform_t dist1 = stc64_uniform_new(1, 6); - stc64_uniformf_t dist2 = stc64_uniformf_new(1.0, 10.0); - stc64_normalf_t dist3 = stc64_normalf_new(1.0, 10.0); - - uint64_t i = stc64_rand(&rng); - int64_t iu = stc64_uniform(&rng, &dist1); - double xu = stc64_uniformf(&rng, &dist2); - double xn = stc64_normalf(&rng, &dist3); -} -*/ -#include -#include - -typedef struct stc64 { uint64_t state[5]; } stc64_t; -typedef struct stc64_uniform { int64_t lower; uint64_t range, threshold; } stc64_uniform_t; -typedef struct stc64_uniformf { double lower, range; } stc64_uniformf_t; -typedef struct stc64_normalf { double mean, stddev, next; int has_next; } stc64_normalf_t; - -/* PRNG stc64. - * Very fast PRNG suited for parallel usage with Weyl-sequence parameter. - * 320-bit state, 256 bit is mutable. - * Noticable faster than xoshiro and pcg, slighly slower than wyrand64 and - * Romu, but these have restricted capacity for larger parallel jobs or unknown minimum periods. - * stc64 supports 2^63 unique threads with a minimum 2^64 period lengths each. - * Passes all statistical tests, e.g PractRand and correlation tests, i.e. interleaved - * streams with one-bit diff state. Even the 16-bit version (LR=6, RS=5, LS=3) passes - * PractRand to multiple TB input. - */ - -/* Global stc64 PRNGs */ -STC_API void csrandom(uint64_t seed); -STC_API uint64_t crandom(void); -STC_API double crandomf(void); - -/* Init stc64 prng with and without sequence number */ -STC_API stc64_t stc64_with_seq(uint64_t seed, uint64_t seq); -STC_INLINE stc64_t stc64_new(uint64_t seed) - { return stc64_with_seq(seed, seed + 0x3504f333d3aa0b37); } - -/* Unbiased bounded uniform distribution. range [low, high] */ -STC_API stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high); -STC_API int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* dist); - -/* Normal distribution PRNG */ -STC_API double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist); - - -/* Main stc64 prng */ -STC_INLINE uint64_t stc64_rand(stc64_t* rng) { - uint64_t *s = rng->state; enum {LR=24, RS=11, LS=3}; - const uint64_t result = (s[0] ^ (s[3] += s[4])) + s[1]; - s[0] = s[1] ^ (s[1] >> RS); - s[1] = s[2] + (s[2] << LS); - s[2] = ((s[2] << LR) | (s[2] >> (64 - LR))) + result; - return result; -} - -/* Float64 random number in range [0.0, 1.0). */ -STC_INLINE double stc64_randf(stc64_t* rng) { - union {uint64_t i; double f;} u = {0x3FF0000000000000ull | (stc64_rand(rng) >> 12)}; - return u.f - 1.0; -} - -/* Float64 uniform distributed RNG, range [low, high). */ -STC_INLINE double stc64_uniformf(stc64_t* rng, stc64_uniformf_t* dist) { - return stc64_randf(rng)*dist->range + dist->lower; -} - -/* Init uniform distributed float64 RNG, range [low, high). */ -STC_INLINE stc64_uniformf_t stc64_uniformf_new(double low, double high) { - return c_LITERAL(stc64_uniformf_t){low, high - low}; -} - -/* Marsaglia polar method for gaussian/normal distribution, float64. */ -STC_INLINE stc64_normalf_t stc64_normalf_new(double mean, double stddev) { - return c_LITERAL(stc64_normalf_t){mean, stddev, 0.0, 0}; -} - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) - -/* Global random() */ -static stc64_t stc64_global = {{ - 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04, - 0x504f333d3aa0b359, 0x9e3779b97f4a7c15, - 0x6a09e667a754166b -}}; - -STC_DEF void csrandom(uint64_t seed) { - stc64_global = stc64_new(seed); -} - -STC_DEF uint64_t crandom(void) { - return stc64_rand(&stc64_global); -} - -STC_DEF double crandomf(void) { - return stc64_randf(&stc64_global); -} - -/* rng.state[4] must be odd */ -STC_DEF stc64_t stc64_with_seq(uint64_t seed, uint64_t seq) { - stc64_t rng = {{seed+0x26aa069ea2fb1a4d, seed+0x70c72c95cd592d04, - seed+0x504f333d3aa0b359, seed, seq<<1 | 1}}; - for (int i = 0; i < 6; ++i) stc64_rand(&rng); - return rng; -} - -/* Init unbiased uniform uint RNG with bounds [low, high] */ -STC_DEF stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high) { - stc64_uniform_t dist = {low, (uint64_t) (high - low + 1)}; - dist.threshold = (uint64_t)(0 - dist.range) % dist.range; - return dist; -} - -#if defined(__SIZEOF_INT128__) - #define c_umul128(a, b, lo, hi) \ - do { __uint128_t _z = (__uint128_t)(a)*(b); \ - *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0) -#elif defined(_MSC_VER) && defined(_WIN64) - #include - #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi))) -#elif defined(__x86_64__) - #define c_umul128(a, b, lo, hi) \ - asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) -#endif - -/* Int uniform distributed RNG, range [low, high]. */ -STC_DEF int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* d) { -#ifdef c_umul128 - uint64_t lo, hi; - do { c_umul128(stc64_rand(rng), d->range, &lo, &hi); } while (lo < d->threshold); - return d->lower + (int64_t)hi; -#else - uint64_t x, r; - do { - x = stc64_rand(rng); - r = x % d->range; - } while (x - r > -d->range); - return d->lower + r; -#endif -} - -/* Normal distribution PRNG */ -STC_DEF double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist) { - double u1, u2, s, m; - if (dist->has_next++ & 1) - return dist->next * dist->stddev + dist->mean; - do { - u1 = 2.0 * stc64_randf(rng) - 1.0; - u2 = 2.0 * stc64_randf(rng) - 1.0; - s = u1*u1 + u2*u2; - } while (s >= 1.0 || s == 0.0); - m = sqrt(-2.0 * log(s) / s); - dist->next = u2 * m; - return (u1 * m) * dist->stddev + dist->mean; -} - -#endif -#endif -#undef i_opt -#undef i_static -#undef i_header -#undef i_implement -#undef i_extern diff --git a/include/stc/cset.h b/include/stc/cset.h index 58cbeb3e..c89a144d 100644 --- a/include/stc/cset.h +++ b/include/stc/cset.h @@ -39,8 +39,5 @@ int main(void) { } */ -#ifndef _i_prefix #define _i_prefix cset_ -#endif -#define _i_isset #include "cmap.h" diff --git a/include/stc/csmap.h b/include/stc/csmap.h index cd7c1d95..6b8475eb 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -58,17 +58,16 @@ int main(void) { #endif // CSMAP_H_INCLUDED #ifndef _i_prefix -#define _i_prefix csmap_ -#endif -#ifdef _i_isset - #define _i_MAP_ONLY c_false - #define _i_SET_ONLY c_true - #define _i_keyref(vp) (vp) -#else + #define _i_prefix csmap_ #define _i_ismap #define _i_MAP_ONLY c_true #define _i_SET_ONLY c_false #define _i_keyref(vp) (&(vp)->first) +#else + #define _i_isset + #define _i_MAP_ONLY c_false + #define _i_SET_ONLY c_true + #define _i_keyref(vp) (vp) #endif #include "priv/template.h" #ifndef i_is_forward diff --git a/include/stc/csset.h b/include/stc/csset.h index c14d2a6a..29810c7c 100644 --- a/include/stc/csset.h +++ b/include/stc/csset.h @@ -42,8 +42,5 @@ int main(void) { } */ -#ifndef _i_prefix #define _i_prefix csset_ -#endif -#define _i_isset #include "csmap.h" diff --git a/include/stc/cstack.h b/include/stc/cstack.h index c2792358..87ef9405 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -28,9 +28,7 @@ #include "forward.h" #endif // CSTACK_H_INCLUDED -#ifndef _i_prefix #define _i_prefix cstack_ -#endif #include "priv/template.h" #ifndef i_is_forward diff --git a/include/stc/cvec.h b/include/stc/cvec.h index a1aa74b2..3cbd90b7 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -68,9 +68,7 @@ int main() { #define _it_ptr(it) (it.ref ? it.ref : it.end) #endif // CVEC_H_INCLUDED -#ifndef _i_prefix #define _i_prefix cvec_ -#endif #include "priv/template.h" #ifndef i_is_forward diff --git a/include/stc/priv/altnames.h b/include/stc/priv/altnames.h deleted file mode 100644 index 723b6a66..00000000 --- a/include/stc/priv/altnames.h +++ /dev/null @@ -1,34 +0,0 @@ -/* MIT License - * - * Copyright (c) 2023 Tyge Løvset - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#define c_FORLIST c_forlist -#define c_FORRANGE c_forrange -#define c_FOREACH c_foreach -#define c_FORPAIR c_forpair -#define c_FORFILTER c_forfilter -#define c_FORMATCH c_formatch -#define c_FORTOKEN c_fortoken -#define c_FORTOKEN_SV c_fortoken_sv -#define c_AUTO c_auto -#define c_WITH c_with -#define c_SCOPE c_scope -#define c_DEFER c_defer -- cgit v1.2.3 From f916573e2b3652d9b3f6fb82aadd5f2cfb3ce2fe Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 1 May 2023 10:00:07 +0200 Subject: Remove warnings when using -Wextra. --- include/stc/cbits.h | 4 ++-- include/stc/csmap.h | 2 +- misc/benchmarks/shootout_hashmaps.cpp | 1 + misc/examples/birthday.c | 4 ++-- misc/examples/complex.c | 2 +- misc/examples/gauss2.c | 2 +- misc/examples/inits.c | 2 +- misc/examples/make.sh | 4 ++-- misc/examples/new_list.c | 2 +- misc/examples/new_map.c | 6 +++--- misc/examples/new_pque.c | 2 +- misc/examples/new_queue.c | 2 +- misc/examples/new_smap.c | 2 +- misc/examples/new_vec.c | 4 ++-- misc/examples/prime.c | 12 ++++++------ misc/examples/random.c | 14 +++++++------- misc/examples/regex_match.c | 2 +- misc/examples/shape.c | 8 ++++---- src/cregex.c | 9 +++++---- 19 files changed, 43 insertions(+), 41 deletions(-) diff --git a/include/stc/cbits.h b/include/stc/cbits.h index 19e281a8..855d6eb7 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -125,7 +125,7 @@ STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, cons #define _i_assert(x) assert(x) #define i_type cbits -struct { uint64_t *data64; int64_t _size; } typedef i_type; +typedef struct { uint64_t *data64; int64_t _size; } i_type; STC_INLINE cbits cbits_init(void) { return c_LITERAL(cbits){NULL}; } STC_INLINE void cbits_create(cbits* self) { self->data64 = NULL; self->_size = 0; } @@ -197,7 +197,7 @@ STC_INLINE cbits cbits_with_pattern(const int64_t size, const uint64_t pattern) #define i_type c_PASTE(cbits, i_capacity) #endif -struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } typedef i_type; +typedef struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } i_type; STC_INLINE i_type _i_memb(_init)(void) { return c_LITERAL(i_type){0}; } STC_INLINE void _i_memb(_create)(i_type* self) {} diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 6b8475eb..fbfea8dd 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -283,7 +283,7 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { _cx_node* nodes = (_cx_node*)i_realloc(self->nodes, (cap + 1)*c_sizeof(_cx_node)); if (!nodes) return false; - nodes[0] = c_LITERAL(_cx_node){{0, 0}, 0}; + nodes[0] = c_LITERAL(_cx_node){0}; self->nodes = nodes; self->cap = (int32_t)cap; return true; diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp index 54680402..c6a81777 100644 --- a/misc/benchmarks/shootout_hashmaps.cpp +++ b/misc/benchmarks/shootout_hashmaps.cpp @@ -36,6 +36,7 @@ KHASH_MAP_INIT_INT64(ii, IValue) #define i_key IKey #define i_val IValue #define i_tag ii +//#define i_expandby 1 #define i_max_load_factor MAX_LOAD_FACTOR / 100.0f #include diff --git a/misc/examples/birthday.c b/misc/examples/birthday.c index c301128a..2820c42f 100644 --- a/misc/examples/birthday.c +++ b/misc/examples/birthday.c @@ -13,8 +13,8 @@ static uint64_t seed = 12345; static void test_repeats(void) { enum {BITS = 46, BITS_TEST = BITS/2 + 2}; - const static uint64_t N = 1ull << BITS_TEST; - const static uint64_t mask = (1ull << BITS) - 1; + static const uint64_t N = 1ull << BITS_TEST; + static const uint64_t mask = (1ull << BITS) - 1; printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST); crand_t rng = crand_init(seed); diff --git a/misc/examples/complex.c b/misc/examples/complex.c index 7dde981d..c730db33 100644 --- a/misc/examples/complex.c +++ b/misc/examples/complex.c @@ -44,7 +44,7 @@ int main() const ListMap* lmap_p = MapMap_at(&mmap, "first"); const StackList* list_p = ListMap_at(lmap_p, 42); const FloatStack* stack_p = StackList_back(list_p); - printf("value is: %f\n", *FloatStack_at(stack_p, 3)); // pi + printf("value is: %f\n", (double)*FloatStack_at(stack_p, 3)); // pi MapMap_drop(&mmap); } diff --git a/misc/examples/gauss2.c b/misc/examples/gauss2.c index df709d03..e786824b 100644 --- a/misc/examples/gauss2.c +++ b/misc/examples/gauss2.c @@ -14,7 +14,7 @@ int main() enum {N = 5000000}; uint64_t seed = (uint64_t)time(NULL); crand_t rng = crand_init(seed); - const double Mean = round(crand_f64(&rng)*98.f - 49.f), StdDev = crand_f64(&rng)*10.f + 1.f, Scale = 74.f; + const double Mean = round(crand_f64(&rng)*98.0 - 49.0), StdDev = crand_f64(&rng)*10.0 + 1.0, Scale = 74.0; printf("Demo of gaussian / normal distribution of %d random samples\n", N); printf("Mean %f, StdDev %f\n", Mean, StdDev); diff --git a/misc/examples/inits.c b/misc/examples/inits.c index 81bcdd3e..e098422e 100644 --- a/misc/examples/inits.c +++ b/misc/examples/inits.c @@ -45,7 +45,7 @@ int main(void) puts("\npop and show high priorites first:"); while (! cpque_f_empty(&floats)) { - printf("%.1f ", *cpque_f_top(&floats)); + printf("%.1f ", (double)*cpque_f_top(&floats)); cpque_f_pop(&floats); } puts("\n"); diff --git a/misc/examples/make.sh b/misc/examples/make.sh index 0297e5a1..ee8d2267 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -1,12 +1,12 @@ #!/bin/sh if [ "$(uname)" = 'Linux' ]; then - sanitize='-fsanitize=address' + sanitize='-fsanitize=address -fsanitize=undefined -fsanitize-trap' clibs='-lm' # -pthread oflag='-o ' fi -cc=gcc; cflags="-s -O3 -std=c99 -Wconversion -Wpedantic -Wall -Wsign-compare -Wwrite-strings" +cc=gcc; cflags="-s -O3 -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized -Wno-missing-field-initializers" #cc=gcc; cflags="-g -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" #cc=tcc; cflags="-Wall -std=c99" #cc=clang; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall -Wno-unused-function -Wsign-compare -Wwrite-strings" diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index 8b291d34..14fabb4a 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -61,7 +61,7 @@ int main() clist_float_sort(&flst); c_foreach (i, clist_float, flst) - printf(" %g", *i.ref); + printf(" %g", (double)*i.ref); puts(""); clist_float_drop(&flst); diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c index 3a4f934d..f01db64f 100644 --- a/misc/examples/new_map.c +++ b/misc/examples/new_map.c @@ -3,10 +3,10 @@ forward_cmap(cmap_pnt, struct Point, int); -struct MyStruct { +typedef struct MyStruct { cmap_pnt pntmap; cstr name; -} typedef MyStruct; +} MyStruct; // int => int map #define i_key int @@ -14,7 +14,7 @@ struct MyStruct { #include // Point => int map -struct Point { int x, y; } typedef Point; +typedef struct Point { int x, y; } Point; int point_cmp(const Point* a, const Point* b) { int c = a->x - b->x; diff --git a/misc/examples/new_pque.c b/misc/examples/new_pque.c index 9147e3f2..5b26b3de 100644 --- a/misc/examples/new_pque.c +++ b/misc/examples/new_pque.c @@ -1,6 +1,6 @@ #include -struct Point { int x, y; } typedef Point; +typedef struct Point { int x, y; } Point; #define i_type PointQ #define i_val Point diff --git a/misc/examples/new_queue.c b/misc/examples/new_queue.c index 916f4dbc..b784bc18 100644 --- a/misc/examples/new_queue.c +++ b/misc/examples/new_queue.c @@ -5,7 +5,7 @@ forward_cqueue(cqueue_pnt, struct Point); -struct Point { int x, y; } typedef Point; +typedef struct Point { int x, y; } Point; int point_cmp(const Point* a, const Point* b) { int c = c_default_cmp(&a->x, &b->x); return c ? c : c_default_cmp(&a->y, &b->y); diff --git a/misc/examples/new_smap.c b/misc/examples/new_smap.c index d8245b8b..f930eba2 100644 --- a/misc/examples/new_smap.c +++ b/misc/examples/new_smap.c @@ -10,7 +10,7 @@ typedef struct { } MyStruct; // Point => int map -struct Point { int x, y; } typedef Point; +typedef struct Point { int x, y; } Point; int point_cmp(const Point* a, const Point* b) { int c = a->x - b->x; return c ? c : a->y - b->y; diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c index df443b7f..d4b66883 100644 --- a/misc/examples/new_vec.c +++ b/misc/examples/new_vec.c @@ -4,10 +4,10 @@ forward_cvec(cvec_i32, int); forward_cvec(cvec_pnt, struct Point); -struct MyStruct { +typedef struct MyStruct { cvec_i32 intvec; cvec_pnt pntvec; -} typedef MyStruct; +} MyStruct; #define i_val int #define i_is_forward diff --git a/misc/examples/prime.c b/misc/examples/prime.c index d0887353..7efa26ff 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -26,15 +26,15 @@ cbits sieveOfEratosthenes(int64_t n) int main(void) { - int64_t n = 1000000000; - printf("Computing prime numbers up to %" c_ZI "\n", n); + int n = 1000000000; + printf("Computing prime numbers up to %d\n", n); - clock_t t1 = clock(); + clock_t t = clock(); cbits primes = sieveOfEratosthenes(n + 1); - int64_t np = cbits_count(&primes); - clock_t t2 = clock(); + int np = (int)cbits_count(&primes); + t = t - clock(); - printf("Number of primes: %" c_ZI ", time: %f\n\n", np, (float)(t2 - t1) / (float)CLOCKS_PER_SEC); + printf("Number of primes: %d, time: %f\n\n", np, (double)t/CLOCKS_PER_SEC); puts("Show all the primes in the range [2, 1000):"); printf("2"); c_forrange (i, 3, 1000, 2) diff --git a/misc/examples/random.c b/misc/examples/random.c index ea9c483e..e783fe55 100644 --- a/misc/examples/random.c +++ b/misc/examples/random.c @@ -4,7 +4,7 @@ int main() { - const size_t N = 1000000000; + const int N = 1000000000; const uint64_t seed = (uint64_t)time(NULL), range = 1000000; crand_t rng = crand_init(seed); @@ -18,8 +18,8 @@ int main() sum += (uint32_t)crand_u64(&rng); } diff = clock() - before; - printf("full range\t\t: %f secs, %" c_ZI ", avg: %f\n", - (float)diff / CLOCKS_PER_SEC, N, (float)sum / (float)N); + printf("full range\t\t: %f secs, %d, avg: %f\n", + (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); crand_unif_t dist1 = crand_unif_init(0, range); rng = crand_init(seed); @@ -29,8 +29,8 @@ int main() sum += crand_unif(&rng, &dist1); // unbiased } diff = clock() - before; - printf("unbiased 0-%" PRIu64 "\t: %f secs, %" c_ZI ", avg: %f\n", - range, (float)diff/CLOCKS_PER_SEC, N, (float)sum / (float)N); + printf("unbiased 0-%" PRIu64 "\t: %f secs, %d, avg: %f\n", + range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); sum = 0; rng = crand_init(seed); @@ -39,7 +39,7 @@ int main() sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased } diff = clock() - before; - printf("biased 0-%" PRIu64 " \t: %f secs, %" c_ZI ", avg: %f\n", - range, (float)diff / CLOCKS_PER_SEC, N, (float)sum / (float)N); + printf("biased 0-%" PRIu64 " \t: %f secs, %d, avg: %f\n", + range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); } diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c index def0ae7a..e49ebd0b 100644 --- a/misc/examples/regex_match.c +++ b/misc/examples/regex_match.c @@ -24,7 +24,7 @@ int main() cstack_float_push(&vec, (float)atof(i.match[0].str)); c_foreach (i, cstack_float, vec) - printf(" %g\n", *i.ref); + printf(" %g\n", (double)*i.ref); // extracts the numbers only to a comma separated string. cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_R_STRIP); diff --git a/misc/examples/shape.c b/misc/examples/shape.c index d7116039..22e993db 100644 --- a/misc/examples/shape.c +++ b/misc/examples/shape.c @@ -62,9 +62,9 @@ static void Triangle_draw(const Shape* shape) { const Triangle* self = DYN_CAST(Triangle, shape); printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n", - self->p[0].x, self->p[0].y, - self->p[1].x, self->p[1].y, - self->p[2].x, self->p[2].y); + (double)self->p[0].x, (double)self->p[0].y, + (double)self->p[1].x, (double)self->p[1].y, + (double)self->p[2].x, (double)self->p[2].y); } struct ShapeAPI Triangle_api = { @@ -109,7 +109,7 @@ static void Polygon_draw(const Shape* shape) const Polygon* self = DYN_CAST(Polygon, shape); printf("Polygon :"); c_foreach (i, PointVec, self->points) - printf(" (%g,%g)", i.ref->x, i.ref->y); + printf(" (%g,%g)", (double)i.ref->x, (double)i.ref->y); puts(""); } diff --git a/src/cregex.c b/src/cregex.c index 0688d9e1..a1d43944 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -842,16 +842,17 @@ _bldcclass(_Parser *par) static _Reprog* -_regcomp1(_Reprog *progp, _Parser *par, const char *s, int cflags) +_regcomp1(_Reprog *pp, _Parser *par, const char *s, int cflags) { _Token token; /* get memory for the program. estimated max usage */ par->instcap = 5U + 6*strlen(s); - _Reprog* pp = (_Reprog *)c_realloc(progp, sizeof(_Reprog) + par->instcap*sizeof(_Reinst)); - if (pp == NULL) { + _Reprog* old_pp = pp; + pp = (_Reprog *)c_realloc(pp, sizeof(_Reprog) + par->instcap*sizeof(_Reinst)); + if (! pp) { + c_free(old_pp); par->error = CREG_OUTOFMEMORY; - c_free(progp); return NULL; } pp->flags.icase = (cflags & CREG_C_ICASE) != 0; -- cgit v1.2.3 From 399eb8d0e1de2839d826a9e0cf123d90d00b0018 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 1 May 2023 23:11:45 +0200 Subject: Replaced cco_yield(corocall, ctx, retval) with cco_await(cond) and cco_await_while(cond). --- docs/ccommon_api.md | 15 ++++++++------- include/stc/algo/coroutine.h | 16 ++++++---------- misc/examples/coroutines.c | 24 +++++++++++------------- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 7a3c3196..549eff4e 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -355,15 +355,16 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_final:` | Obligatory label in coroutine | | | `cco_return;` | Early return from the coroutine | | `bool` | `cco_alive(ctx)` | Is coroutine in initial or suspended state? | +| `bool` | `cco_done(ctx)` | Is coroutine not alive? | | `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? | | `void` | `cco_begin(ctx)` | Begin coroutine block | -| `rettype` | `cco_end(retval)` | End coroutine block with return value | -| `void` | `cco_end()` | End coroutine block | -| `rettype` | `cco_yield(retval)` | Suspend execution and return a value | -| `void` | `cco_yield()` | Suspend execution | -| `rettype` | `cco_yield(corocall2, ctx2, retval)` | Yield from another coroutine and return val | -| `void` | `cco_yield(corocall2, ctx2)` | Yield from another coroutine | -| | From the caller side: | | +| `rettype` | `cco_end(retval)` | End coroutine block and return retval | +| `void` | `cco_end()` | End coroutine block (return void) | +| `rettype` | `cco_yield(retval)` | Suspend execution and return retval | +| `void` | `cco_yield()` | Suspend execution (return void) | +| `rettype` | `cco_await_while(cond, retval)` | If cond, suspend execution and return retval | +| `bool` | `cco_await(cond)` | If not cond, suspend execution and return true | +| | From caller side: | | | `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index b0ecd6b7..6c1d7d28 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -64,6 +64,7 @@ enum { #define cco_suspended(ctx) ((ctx)->cco_state > 0) #define cco_alive(ctx) ((ctx)->cco_state != cco_state_done) +#define cco_done(ctx) ((ctx)->cco_state == cco_state_done) #define cco_begin(ctx) \ int *_state = &(ctx)->cco_state; \ @@ -76,25 +77,20 @@ enum { } \ return retval -#define cco_yield(...) c_MACRO_OVERLOAD(cco_yield, __VA_ARGS__) -#define cco_yield_1(retval) \ +#define cco_yield(retval) \ do { \ *_state = __LINE__; return retval; \ case __LINE__:; \ } while (0) -#define cco_yield_2(corocall2, ctx2) \ - cco_yield_3(corocall2, ctx2, ) - -#define cco_yield_3(corocall2, ctx2, retval) \ +#define cco_await_while(cond, retval) \ do { \ *_state = __LINE__; \ - do { \ - corocall2; if (cco_suspended(ctx2)) return retval; \ - case __LINE__:; \ - } while (cco_alive(ctx2)); \ + case __LINE__: if (cond) return retval; \ } while (0) +#define cco_await(cond) cco_await_while(!(cond), true) + #define cco_final \ case cco_state_final: \ _cco_final_ diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index b11b8532..af9fef81 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -78,29 +78,27 @@ struct combined { int cco_state; }; + bool combined(struct combined* C) { cco_begin(C); - cco_yield(prime(&C->prm), &C->prm, true); - cco_yield(fibonacci(&C->fib), &C->fib, true); + cco_await(prime(&C->prm) == false); + cco_await(fibonacci(&C->fib) == false); // Reuse the C->prm context and extend the count: C->prm.count = 8; C->prm.result += 2; cco_reset(&C->prm); - cco_yield(prime(&C->prm), &C->prm, true); + cco_await(prime(&C->prm) == false); cco_final: puts("final comb"); cco_end(false); } -int main(void) { +int main(void) +{ struct combined comb = {.prm={.count=8}, .fib={14}}; - if (true) - while (combined(&comb)) - printf("Prime(%d)=%lld, Fib(%d)=%lld\n", - comb.prm.idx, (long long)comb.prm.result, - comb.fib.idx, (long long)comb.fib.result); - else - while (prime(&comb.prm)) - printf("Prime(%d)=%lld\n", - comb.prm.idx, (long long)comb.prm.result); + + while (combined(&comb)) + printf("Prime(%d)=%lld, Fib(%d)=%lld\n", + comb.prm.idx, (long long)comb.prm.result, + comb.fib.idx, (long long)comb.fib.result); } -- cgit v1.2.3 From 2adea8b3b06ebe1b2152870862100f7e7985cfdf Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 2 May 2023 07:20:29 +0200 Subject: Improved coroutine.h, added new coro examples. --- docs/ccommon_api.md | 28 +++++++++------- include/stc/algo/coroutine.h | 49 ++++++++++++++++++++++------ misc/examples/cointerleave.c | 60 ++++++++++++++++++++++++++++++++++ misc/examples/coread.c | 14 ++++---- misc/examples/coroutines.c | 20 ++++++------ misc/examples/scheduler.c | 76 ++++++++++++++++++++++++++++++++++++++++++++ misc/examples/triples.c | 8 ++--- 7 files changed, 212 insertions(+), 43 deletions(-) create mode 100644 misc/examples/cointerleave.c create mode 100644 misc/examples/scheduler.c diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 549eff4e..27df13ce 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -302,13 +302,13 @@ struct triples { int cco_state; // required member }; -bool triples_next(struct triples* i) { // coroutine +bool triples(struct triples* i) { // coroutine cco_begin(i); for (i->c = 5; i->n; ++i->c) { for (i->a = 1; i->a < i->c; ++i->a) { for (i->b = i->a + 1; i->b < i->c; ++i->b) { if ((int64_t)i->a*i->a + (int64_t)i->b*i->b == (int64_t)i->c*i->c) { - cco_yield(true); + cco_yield(false); if (--i->n == 0) cco_return; } } @@ -316,7 +316,7 @@ bool triples_next(struct triples* i) { // coroutine } cco_final: // required label puts("done"); - cco_end(false); + cco_end(true); } int gcd(int a, int b) { // greatest common denominator @@ -333,7 +333,7 @@ int main() struct triples t = {.n=INT32_MAX}; int n = 0; - while (triples_next(&t)) { + while (!triples(&t)) { // Skip triples with GCD(a,b) > 1 if (gcd(t.a, t.b) > 1) continue; @@ -353,20 +353,24 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| | | `cco_final:` | Obligatory label in coroutine | -| | `cco_return;` | Early return from the coroutine | +| | `cco_return` | Early return from the coroutine (no arg) | | `bool` | `cco_alive(ctx)` | Is coroutine in initial or suspended state? | | `bool` | `cco_done(ctx)` | Is coroutine not alive? | | `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? | -| `void` | `cco_begin(ctx)` | Begin coroutine block | -| `rettype` | `cco_end(retval)` | End coroutine block and return retval | -| `void` | `cco_end()` | End coroutine block (return void) | -| `rettype` | `cco_yield(retval)` | Suspend execution and return retval | -| `void` | `cco_yield()` | Suspend execution (return void) | -| `rettype` | `cco_await_while(cond, retval)` | If cond, suspend execution and return retval | -| `bool` | `cco_await(cond)` | If not cond, suspend execution and return true | +| | `cco_begin(ctx)` | Begin coroutine block | +| | `cco_end(retval)` | End coroutine block and return retval | +| | `cco_end()` | End coroutine block (return void) | +| | `cco_yield(retval)` | Suspend execution and return retval | +| | `cco_yield()` | Suspend execution (return void) | +| | `cco_await(promise)` | Suspend and return false until promise is true | +| | `cco_await_while(cond, retval)` | Suspend and return retval while cond is true | | | From caller side: | | | `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | +| | Semaphores: | | +| | `cco_semaphore` | Semaphore type | +| | `cco_await_sem(sem)` | Await for the semaphore count > 0 | +| | `cco_signal_sem(sem)` | Signal the semaphore by increasing count| --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 6c1d7d28..4b7bee5f 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -26,38 +26,38 @@ #include #include -struct iterate { +struct coroutine { int max_x, max_y; int x, y; int cco_state; // required member }; -bool iterate(struct iterate* I) { +bool coroutine(struct coroutine* I) { cco_begin(I); for (I->x = 0; I->x < I->max_x; I->x++) for (I->y = 0; I->y < I->max_y; I->y++) - cco_yield(true); + cco_yield(false); cco_final: - puts("final"); - cco_end(false); + puts("final"); + cco_end(true); } int main(void) { - struct iterate it = {.max_x=3, .max_y=3}; + struct coroutine it = {.max_x=3, .max_y=3}; int n = 0; - while (iterate(&it)) + while (!coroutine(&it)) { printf("%d %d\n", it.x, it.y); // example of early stop: - if (++n == 20) cco_stop(&it); // signal to stop at next + if (++n == 7) cco_stop(&it); // signal to stop at next } return 0; } */ #include -enum { +enum cco_states { cco_state_final = -1, cco_state_done = -2, }; @@ -89,7 +89,7 @@ enum { case __LINE__: if (cond) return retval; \ } while (0) -#define cco_await(cond) cco_await_while(!(cond), true) +#define cco_await(promise) cco_await_while(!(promise), false) #define cco_final \ case cco_state_final: \ @@ -110,4 +110,33 @@ enum { if (*_state == cco_state_done) *_state = 0; \ } while (0) + +typedef struct { + int count; +} cco_semaphore; + +/** + * Wait for a semaphore + * + * This macro carries out the "wait" operation on the semaphore. The + * wait operation causes the "thread" to block while the counter is + * zero. When the counter reaches a value larger than zero, the + * protothread will continue. + */ +#define cco_await_sem(sem) \ + do { \ + cco_await((sem)->count > 0); \ + --(sem)->count; \ + } while (0) + +/** + * Signal a semaphore + * + * This macro carries out the "signal" operation on the semaphore. The + * signal operation increments the counter inside the semaphore, which + * eventually will cause waiting "threads" to continue executing. + */ +#define cco_signal_sem(sem) ++(sem)->count +#define cco_reset_sem(sem, value) ((sem)->count = value) + #endif diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c new file mode 100644 index 00000000..64473d96 --- /dev/null +++ b/misc/examples/cointerleave.c @@ -0,0 +1,60 @@ +// https://www.youtube.com/watch?v=8sEe-4tig_A +#include +#include +#define i_type IVec +#define i_val int +#include + +struct GenValue { + IVec *v; + IVec_iter it; + int cco_state; +}; + +static int next_value(struct GenValue* g) +{ + cco_begin(g); + for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) + cco_yield(*g->it.ref); + cco_final: + cco_end(0); +} + +struct Generator { + struct GenValue x, y; + int cco_state; + int value; +}; + +bool interleaved(struct Generator* g) +{ + cco_begin(g); + while (cco_alive(&g->x) || cco_alive(&g->y)) + { + g->value = next_value(&g->x); + if (cco_alive(&g->x)) cco_yield(false); + + g->value = next_value(&g->y); + if (cco_alive(&g->y)) cco_yield(false); + } + cco_final: + cco_end(true); +} + +void Use(void) +{ + IVec a = c_make(IVec, {2, 4, 6, 8, 10, 11}); + IVec b = c_make(IVec, {3, 5, 7, 9}); + + struct Generator g = {{&a}, {&b}}; + + while (!interleaved(&g)) + printf("%d\n", g.value); + + c_drop(IVec, &a, &b); +} + +int main() +{ + Use(); +} diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 0a7f4816..d5385a87 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -4,36 +4,36 @@ // Read file line by line using coroutines: -struct file_nextline { +struct file_read { const char* filename; int cco_state; FILE* fp; cstr line; }; -bool file_nextline(struct file_nextline* U) +bool file_read(struct file_read* U) { cco_begin(U) U->fp = fopen(U->filename, "r"); U->line = cstr_init(); while (cstr_getline(&U->line, U->fp)) - cco_yield(true); + cco_yield(false); cco_final: // this label is required. printf("finish\n"); cstr_drop(&U->line); fclose(U->fp); - cco_end(false); + cco_end(true); } int main(void) { - struct file_nextline it = {__FILE__}; + struct file_read g = {__FILE__}; int n = 0; - while (file_nextline(&it)) + while (!file_read(&g)) { - printf("%3d %s\n", ++n, cstr_str(&it.line)); + printf("%3d %s\n", ++n, cstr_str(&g.line)); //if (n == 10) cco_stop(&it); } } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index af9fef81..3fddf913 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -23,7 +23,7 @@ bool prime(struct prime* U) { if (U->result == 2) { if (U->count-- == 0) cco_return; ++U->idx; - cco_yield(true); + cco_yield(false); } U->result += !(U->result & 1); for (U->pos = U->result; U->count > 0; U->pos += 2) { @@ -31,12 +31,12 @@ bool prime(struct prime* U) { --U->count; ++U->idx; U->result = U->pos; - cco_yield(true); + cco_yield(false); } } cco_final: printf("final prm\n"); - cco_end(false); + cco_end(true); } @@ -63,11 +63,11 @@ bool fibonacci(struct fibonacci* F) { F->result = F->b; F->b = sum; } - cco_yield(true); + cco_yield(false); } cco_final: printf("final fib\n"); - cco_end(false); + cco_end(true); } // Combine @@ -81,23 +81,23 @@ struct combined { bool combined(struct combined* C) { cco_begin(C); - cco_await(prime(&C->prm) == false); - cco_await(fibonacci(&C->fib) == false); + cco_await(prime(&C->prm)); + cco_await(fibonacci(&C->fib)); // Reuse the C->prm context and extend the count: C->prm.count = 8; C->prm.result += 2; cco_reset(&C->prm); - cco_await(prime(&C->prm) == false); + cco_await(prime(&C->prm)); cco_final: puts("final comb"); - cco_end(false); + cco_end(true); } int main(void) { struct combined comb = {.prm={.count=8}, .fib={14}}; - while (combined(&comb)) + while (!combined(&comb)) printf("Prime(%d)=%lld, Fib(%d)=%lld\n", comb.prm.idx, (long long)comb.prm.result, comb.fib.idx, (long long)comb.fib.result); diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c new file mode 100644 index 00000000..1809f2ec --- /dev/null +++ b/misc/examples/scheduler.c @@ -0,0 +1,76 @@ +// https://www.youtube.com/watch?v=8sEe-4tig_A +#include +#include + +struct Scheduler; +struct Task { + bool (*resume)(struct Task*); + struct Scheduler* sched; + int cco_state; +}; + +#define i_type Scheduler +#define i_val struct Task +#define i_no_cmp +#include + +static bool schedule(Scheduler* sched) +{ + struct Task task = *Scheduler_front(sched); + Scheduler_pop_front(sched); + + if (cco_alive(&task)) + task.resume(&task); + + return !Scheduler_empty(sched); +} + +static bool resume_task(const struct Task* task) +{ + Scheduler_push_back(task->sched, *task); + return false; +} + + +static bool taskA(struct Task* task) +{ + cco_begin(task); + puts("Hello, from task A"); + cco_yield(resume_task(task)); + puts("A is back doing work"); + cco_yield(resume_task(task)); + puts("A is back doing more work"); + cco_yield(resume_task(task)); + puts("A is back doing even more work"); + cco_final: + cco_end(true); +} + +static bool taskB(struct Task* task) +{ + cco_begin(task); + puts("Hello, from task B"); + cco_yield(resume_task(task)); + puts("B is back doing work"); + cco_yield(resume_task(task)); + puts("B is back doing more work"); + cco_final: + cco_end(true); +} + +void Use(void) +{ + Scheduler scheduler = c_make(Scheduler, { + {taskA, &scheduler}, + {taskB, &scheduler}, + }); + + while (schedule(&scheduler)) {} + + Scheduler_drop(&scheduler); +} + +int main() +{ + Use(); +} diff --git a/misc/examples/triples.c b/misc/examples/triples.c index 520bf012..2e0211c3 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -23,13 +23,13 @@ struct triples { int cco_state; }; -bool triples_next(struct triples* I) { +bool triples_coro(struct triples* I) { cco_begin(I); for (I->c = 5; I->n; ++I->c) { for (I->a = 1; I->a < I->c; ++I->a) { for (I->b = I->a + 1; I->b < I->c; ++I->b) { if ((int64_t)I->a*I->a + (int64_t)I->b*I->b == (int64_t)I->c*I->c) { - cco_yield(true); + cco_yield(false); if (--I->n == 0) cco_return; } } @@ -37,7 +37,7 @@ bool triples_next(struct triples* I) { } cco_final: puts("done"); - cco_end(false); + cco_end(true); } int gcd(int a, int b) { @@ -58,7 +58,7 @@ int main() struct triples t = {INT32_MAX}; int n = 0; - while (triples_next(&t)) { + while (!triples_coro(&t)) { if (gcd(t.a, t.b) > 1) continue; if (t.c < 100) -- cgit v1.2.3 From ab7a91c501fb3b7054e836a931754caae578c5f2 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 2 May 2023 13:09:16 +0200 Subject: Removed cco_alive(), was same as !cco_done() --- docs/ccommon_api.md | 3 +-- include/stc/algo/coroutine.h | 1 - misc/examples/cointerleave.c | 6 +++--- misc/examples/coroutines.c | 46 ++++++++++++++++++++++---------------------- misc/examples/scheduler.c | 2 +- 5 files changed, 28 insertions(+), 30 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 27df13ce..407ddac4 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -354,9 +354,8 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c |:----------|:-------------------------------------|:----------------------------------------| | | `cco_final:` | Obligatory label in coroutine | | | `cco_return` | Early return from the coroutine (no arg) | -| `bool` | `cco_alive(ctx)` | Is coroutine in initial or suspended state? | -| `bool` | `cco_done(ctx)` | Is coroutine not alive? | | `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? | +| `bool` | `cco_done(ctx)` | Is coroutine done? | | | `cco_begin(ctx)` | Begin coroutine block | | | `cco_end(retval)` | End coroutine block and return retval | | | `cco_end()` | End coroutine block (return void) | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 4b7bee5f..f6769162 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -63,7 +63,6 @@ enum cco_states { }; #define cco_suspended(ctx) ((ctx)->cco_state > 0) -#define cco_alive(ctx) ((ctx)->cco_state != cco_state_done) #define cco_done(ctx) ((ctx)->cco_state == cco_state_done) #define cco_begin(ctx) \ diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 64473d96..9ef7d561 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -29,13 +29,13 @@ struct Generator { bool interleaved(struct Generator* g) { cco_begin(g); - while (cco_alive(&g->x) || cco_alive(&g->y)) + while (!cco_done(&g->x) || !cco_done(&g->y)) { g->value = next_value(&g->x); - if (cco_alive(&g->x)) cco_yield(false); + if (!cco_done(&g->x)) cco_yield(false); g->value = next_value(&g->y); - if (cco_alive(&g->y)) cco_yield(false); + if (!cco_done(&g->y)) cco_yield(false); } cco_final: cco_end(true); diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 3fddf913..bbe85874 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -17,20 +17,20 @@ struct prime { int cco_state; }; -bool prime(struct prime* U) { - cco_begin(U); - if (U->result < 2) U->result = 2; - if (U->result == 2) { - if (U->count-- == 0) cco_return; - ++U->idx; +bool prime(struct prime* g) { + cco_begin(g); + if (g->result < 2) g->result = 2; + if (g->result == 2) { + if (g->count-- == 0) cco_return; + ++g->idx; cco_yield(false); } - U->result += !(U->result & 1); - for (U->pos = U->result; U->count > 0; U->pos += 2) { - if (is_prime(U->pos)) { - --U->count; - ++U->idx; - U->result = U->pos; + g->result += !(g->result & 1); + for (g->pos = g->result; g->count > 0; g->pos += 2) { + if (is_prime(g->pos)) { + --g->count; + ++g->idx; + g->result = g->pos; cco_yield(false); } } @@ -48,20 +48,20 @@ struct fibonacci { int cco_state; }; -bool fibonacci(struct fibonacci* F) { - assert(F->count < 94); +bool fibonacci(struct fibonacci* g) { + assert(g->count < 94); - cco_begin(F); - F->idx = 0; - F->result = 0; - F->b = 1; + cco_begin(g); + g->idx = 0; + g->result = 0; + g->b = 1; for (;;) { - if (F->count-- == 0) + if (g->count-- == 0) cco_return; - if (++F->idx > 1) { - int64_t sum = F->result + F->b; // NB! locals only lasts until next cco_yield! - F->result = F->b; - F->b = sum; + if (++g->idx > 1) { + int64_t sum = g->result + g->b; // NB! locals only lasts until next cco_yield! + g->result = g->b; + g->b = sum; } cco_yield(false); } diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index 1809f2ec..db9c2716 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -19,7 +19,7 @@ static bool schedule(Scheduler* sched) struct Task task = *Scheduler_front(sched); Scheduler_pop_front(sched); - if (cco_alive(&task)) + if (!cco_done(&task)) task.resume(&task); return !Scheduler_empty(sched); -- cgit v1.2.3 From 028b113df1e09cb56ac56b4ad60f633b8fabaded Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 2 May 2023 14:01:38 +0200 Subject: Add cco_await_void(). --- docs/ccommon_api.md | 7 ++++--- include/stc/algo/coroutine.h | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 407ddac4..f4a2c349 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -362,14 +362,15 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_yield(retval)` | Suspend execution and return retval | | | `cco_yield()` | Suspend execution (return void) | | | `cco_await(promise)` | Suspend and return false until promise is true | +| | `cco_await_void(promise)` | Suspend until promise is true (return void) | | | `cco_await_while(cond, retval)` | Suspend and return retval while cond is true | -| | From caller side: | | -| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | -| `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | | | Semaphores: | | | | `cco_semaphore` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | | | `cco_signal_sem(sem)` | Signal the semaphore by increasing count| +| | From caller side: | | +| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | +| `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index f6769162..5cadbc6a 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -89,6 +89,7 @@ enum cco_states { } while (0) #define cco_await(promise) cco_await_while(!(promise), false) +#define cco_await_void(promise) cco_await_while(!(promise), ) #define cco_final \ case cco_state_final: \ @@ -120,7 +121,7 @@ typedef struct { * This macro carries out the "wait" operation on the semaphore. The * wait operation causes the "thread" to block while the counter is * zero. When the counter reaches a value larger than zero, the - * protothread will continue. + * "thread" will continue. */ #define cco_await_sem(sem) \ do { \ @@ -136,6 +137,6 @@ typedef struct { * eventually will cause waiting "threads" to continue executing. */ #define cco_signal_sem(sem) ++(sem)->count -#define cco_reset_sem(sem, value) ((sem)->count = value) +#define cco_reset_sem(sem, value) ((sem)->count = (value)) #endif -- cgit v1.2.3 From e4efe2f9cc87e70e981ee75ec5c4d6db4cb60c49 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 2 May 2023 23:11:20 +0200 Subject: Changed cco_with_..() API again, final. --- docs/ccommon_api.md | 16 ++++++++-------- include/stc/algo/coroutine.h | 29 +++++++++++++---------------- misc/examples/cointerleave.c | 13 +++++++------ misc/examples/coroutines.c | 26 ++++++++++++++------------ 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index f4a2c349..7014def8 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -358,18 +358,18 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | `bool` | `cco_done(ctx)` | Is coroutine done? | | | `cco_begin(ctx)` | Begin coroutine block | | | `cco_end(retval)` | End coroutine block and return retval | -| | `cco_end()` | End coroutine block (return void) | +| | `cco_end()` | End coroutine block | | | `cco_yield(retval)` | Suspend execution and return retval | -| | `cco_yield()` | Suspend execution (return void) | -| | `cco_await(promise)` | Suspend and return false until promise is true | -| | `cco_await_void(promise)` | Suspend until promise is true (return void) | -| | `cco_await_while(cond, retval)` | Suspend and return retval while cond is true | +| | `cco_yield()` | Suspend execution | +| | `cco_await(promise)` | Suspend until promise is true | +| | `cco_await_with(promise, retval)` | Suspend with retval until promise is true | | | Semaphores: | | -| | `cco_semaphore` | Semaphore type | -| | `cco_await_sem(sem)` | Await for the semaphore count > 0 | +| | `cco_semaphore` | Semaphore type | +| | `cco_await_sem(sem)` | Await for the semaphore count > 0 | +| | `cco_await_sem_with(sem, retval)` | Await with retval for the semaphore | | | `cco_signal_sem(sem)` | Signal the semaphore by increasing count| | | From caller side: | | -| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | +| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | --- diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 5cadbc6a..ae9e4464 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -82,15 +82,13 @@ enum cco_states { case __LINE__:; \ } while (0) -#define cco_await_while(cond, retval) \ +#define cco_await(promise) cco_await_with(promise, ) +#define cco_await_with(promise, retval) \ do { \ *_state = __LINE__; \ - case __LINE__: if (cond) return retval; \ + case __LINE__: if (!(promise)) return retval; \ } while (0) -#define cco_await(promise) cco_await_while(!(promise), false) -#define cco_await_void(promise) cco_await_while(!(promise), ) - #define cco_final \ case cco_state_final: \ _cco_final_ @@ -118,22 +116,21 @@ typedef struct { /** * Wait for a semaphore * - * This macro carries out the "wait" operation on the semaphore. The - * wait operation causes the "thread" to block while the counter is - * zero. When the counter reaches a value larger than zero, the - * "thread" will continue. + * This macro carries out the "wait" operation on the semaphore, + * and causes the "thread" to block while the counter is zero. */ -#define cco_await_sem(sem) \ - do { \ - cco_await((sem)->count > 0); \ - --(sem)->count; \ - } while (0) +#define cco_await_sem(sem) cco_await_sem_with(sem, ) +#define cco_await_sem_with(sem, retval) \ + do { \ + cco_await_with((sem)->count > 0, retval); \ + --(sem)->count; \ + } while (0) /** * Signal a semaphore * - * This macro carries out the "signal" operation on the semaphore. The - * signal operation increments the counter inside the semaphore, which + * This macro carries out the "signal" operation on the semaphore, + * and increments the counter inside the semaphore, which * eventually will cause waiting "threads" to continue executing. */ #define cco_signal_sem(sem) ++(sem)->count diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 9ef7d561..5bdbd257 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -26,19 +26,19 @@ struct Generator { int value; }; -bool interleaved(struct Generator* g) +void interleaved(struct Generator* g) { cco_begin(g); while (!cco_done(&g->x) || !cco_done(&g->y)) { g->value = next_value(&g->x); - if (!cco_done(&g->x)) cco_yield(false); + if (!cco_done(&g->x)) cco_yield(); g->value = next_value(&g->y); - if (!cco_done(&g->y)) cco_yield(false); + if (!cco_done(&g->y)) cco_yield(); } cco_final: - cco_end(true); + cco_end(); } void Use(void) @@ -48,9 +48,10 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - while (!interleaved(&g)) - printf("%d\n", g.value); + while (interleaved(&g), !cco_done(&g)) + printf("%d ", g.value); + puts(""); c_drop(IVec, &a, &b); } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index bbe85874..00cedd84 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -4,16 +4,17 @@ // Demonstrate to call another coroutine from a coroutine: // First create prime generator, then call fibonacci sequence: +typedef long long llong; bool is_prime(int64_t i) { - for (int64_t j=2; j*j <= i; ++j) + for (llong j=2; j*j <= i; ++j) if (i % j == 0) return false; return true; } struct prime { int count, idx; - int64_t result, pos; + llong result, pos; int cco_state; }; @@ -44,7 +45,7 @@ bool prime(struct prime* g) { struct fibonacci { int count, idx; - int64_t result, b; + llong result, b; int cco_state; }; @@ -59,7 +60,7 @@ bool fibonacci(struct fibonacci* g) { if (g->count-- == 0) cco_return; if (++g->idx > 1) { - int64_t sum = g->result + g->b; // NB! locals only lasts until next cco_yield! + llong sum = g->result + g->b; // NB! locals lasts only until next cco_yield/cco_await! g->result = g->b; g->b = sum; } @@ -81,13 +82,13 @@ struct combined { bool combined(struct combined* C) { cco_begin(C); - cco_await(prime(&C->prm)); - cco_await(fibonacci(&C->fib)); + cco_await_with(prime(&C->prm), false); + cco_await_with(fibonacci(&C->fib), false); // Reuse the C->prm context and extend the count: - C->prm.count = 8; C->prm.result += 2; + C->prm.count = 8, C->prm.result += 2; cco_reset(&C->prm); - cco_await(prime(&C->prm)); + cco_await_with(prime(&C->prm), false); cco_final: puts("final comb"); cco_end(true); @@ -95,10 +96,11 @@ bool combined(struct combined* C) { int main(void) { - struct combined comb = {.prm={.count=8}, .fib={14}}; + struct combined c = {.prm={.count=8}, .fib={14}}; - while (!combined(&comb)) + while (!combined(&c)) { printf("Prime(%d)=%lld, Fib(%d)=%lld\n", - comb.prm.idx, (long long)comb.prm.result, - comb.fib.idx, (long long)comb.fib.result); + c.prm.idx, c.prm.result, + c.fib.idx, c.fib.result); + } } -- cgit v1.2.3 From 6b23e35287f26dad63abd755c5f365b443e025a3 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 3 May 2023 16:45:37 +0200 Subject: Reverted from cco_await_with(promise, ret) to cco_await(promise, ret). --- include/stc/algo/coroutine.h | 15 +++++++++------ misc/examples/coread.c | 14 +++++++------- misc/examples/coroutines.c | 26 ++++++++++++++------------ 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index ae9e4464..89dd27f0 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -57,11 +57,12 @@ int main(void) { */ #include -enum cco_states { +enum { cco_state_final = -1, cco_state_done = -2, }; +#define cco_initial(ctx) ((ctx)->cco_state == 0) #define cco_suspended(ctx) ((ctx)->cco_state > 0) #define cco_done(ctx) ((ctx)->cco_state == cco_state_done) @@ -82,8 +83,9 @@ enum cco_states { case __LINE__:; \ } while (0) -#define cco_await(promise) cco_await_with(promise, ) -#define cco_await_with(promise, retval) \ +#define cco_await(...) c_MACRO_OVERLOAD(cco_await, __VA_ARGS__) +#define cco_await_1(promise) cco_await_2(promise, ) +#define cco_await_2(promise, retval) \ do { \ *_state = __LINE__; \ case __LINE__: if (!(promise)) return retval; \ @@ -119,10 +121,11 @@ typedef struct { * This macro carries out the "wait" operation on the semaphore, * and causes the "thread" to block while the counter is zero. */ -#define cco_await_sem(sem) cco_await_sem_with(sem, ) -#define cco_await_sem_with(sem, retval) \ +#define cco_await_sem(...) c_MACRO_OVERLOAD(cco_await_sem, __VA_ARGS__) +#define cco_await_sem_1(sem) cco_await_sem_2(sem, ) +#define cco_await_sem_2(sem, retval) \ do { \ - cco_await_with((sem)->count > 0, retval); \ + cco_await_2((sem)->count > 0, retval); \ --(sem)->count; \ } while (0) diff --git a/misc/examples/coread.c b/misc/examples/coread.c index d5385a87..38447c44 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -11,19 +11,19 @@ struct file_read { cstr line; }; -bool file_read(struct file_read* U) +bool file_read(struct file_read* g) { - cco_begin(U) - U->fp = fopen(U->filename, "r"); - U->line = cstr_init(); + cco_begin(g) + g->fp = fopen(g->filename, "r"); + g->line = cstr_init(); - while (cstr_getline(&U->line, U->fp)) + while (cstr_getline(&g->line, g->fp)) cco_yield(false); cco_final: // this label is required. printf("finish\n"); - cstr_drop(&U->line); - fclose(U->fp); + cstr_drop(&g->line); + fclose(g->fp); cco_end(true); } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 00cedd84..a5db3291 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -36,7 +36,7 @@ bool prime(struct prime* g) { } } cco_final: - printf("final prm\n"); + printf("final prm\n"); cco_end(true); } @@ -60,14 +60,15 @@ bool fibonacci(struct fibonacci* g) { if (g->count-- == 0) cco_return; if (++g->idx > 1) { - llong sum = g->result + g->b; // NB! locals lasts only until next cco_yield/cco_await! + // NB! locals lasts only until next cco_yield/cco_await! + llong sum = g->result + g->b; g->result = g->b; g->b = sum; } cco_yield(false); } cco_final: - printf("final fib\n"); + printf("final fib\n"); cco_end(true); } @@ -80,17 +81,18 @@ struct combined { }; -bool combined(struct combined* C) { - cco_begin(C); - cco_await_with(prime(&C->prm), false); - cco_await_with(fibonacci(&C->fib), false); +bool combined(struct combined* g) { + cco_begin(g); + cco_await(prime(&g->prm), false); + cco_await(fibonacci(&g->fib), false); - // Reuse the C->prm context and extend the count: - C->prm.count = 8, C->prm.result += 2; - cco_reset(&C->prm); - cco_await_with(prime(&C->prm), false); + // Reuse the g->prm context and extend the count: + g->prm.count = 8, g->prm.result += 2; + cco_reset(&g->prm); + cco_await(prime(&g->prm), false); - cco_final: puts("final comb"); + cco_final: + puts("final combined"); cco_end(true); } -- cgit v1.2.3 From b03148caa1d6fc660e6e7c5986dd6fd38779bedc Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 4 May 2023 11:51:56 +0200 Subject: Updates in coroutines.h: No longer *required* with cco_final:, but only when no cleanup is needed. --- docs/ccommon_api.md | 8 ++++---- include/stc/algo/coroutine.h | 14 ++++++-------- misc/examples/cointerleave.c | 8 ++++---- misc/examples/coread.c | 8 ++++---- misc/examples/coroutines.c | 6 +++--- misc/examples/generator.c | 32 +++++++++++++++--------------- misc/examples/scheduler.c | 2 -- misc/examples/triples.c | 46 +++++++++++++++++++++++--------------------- 8 files changed, 61 insertions(+), 63 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 7014def8..2319109b 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -314,7 +314,7 @@ bool triples(struct triples* i) { // coroutine } } } - cco_final: // required label + cco_final: // required for cleanup puts("done"); cco_end(true); } @@ -352,15 +352,15 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| -| | `cco_final:` | Obligatory label in coroutine | +| | `cco_final:` | Label for cleanup in coroutine | | | `cco_return` | Early return from the coroutine (no arg) | | `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? | | `bool` | `cco_done(ctx)` | Is coroutine done? | | | `cco_begin(ctx)` | Begin coroutine block | -| | `cco_end(retval)` | End coroutine block and return retval | | | `cco_end()` | End coroutine block | -| | `cco_yield(retval)` | Suspend execution and return retval | +| | `cco_end(retval)` | End coroutine block and return retval | | | `cco_yield()` | Suspend execution | +| | `cco_yield(retval)` | Suspend execution and return retval | | | `cco_await(promise)` | Suspend until promise is true | | | `cco_await_with(promise, retval)` | Suspend with retval until promise is true | | | Semaphores: | | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 89dd27f0..c9cb8fc0 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -38,7 +38,7 @@ bool coroutine(struct coroutine* I) { for (I->y = 0; I->y < I->max_y; I->y++) cco_yield(false); - cco_final: + cco_final: // required if there is cleanup code puts("final"); cco_end(true); } @@ -68,13 +68,12 @@ enum { #define cco_begin(ctx) \ int *_state = &(ctx)->cco_state; \ - switch (*_state) { \ + goto _begin; _begin: switch (*_state) { \ case 0: #define cco_end(retval) \ - *_state = cco_state_done; break; \ - case -99: goto _cco_final_; \ } \ + *_state = cco_state_done; \ return retval #define cco_yield(retval) \ @@ -92,11 +91,10 @@ enum { } while (0) #define cco_final \ - case cco_state_final: \ - _cco_final_ + case cco_state_final #define cco_return \ - goto _cco_final_ + do { *_state = cco_state_final; goto _begin; } while (0) #define cco_stop(ctx) \ do { \ @@ -112,7 +110,7 @@ enum { typedef struct { - int count; + intptr_t count; } cco_semaphore; /** diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 5bdbd257..4fe89316 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -16,7 +16,6 @@ static int next_value(struct GenValue* g) cco_begin(g); for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) cco_yield(*g->it.ref); - cco_final: cco_end(0); } @@ -37,7 +36,6 @@ void interleaved(struct Generator* g) g->value = next_value(&g->y); if (!cco_done(&g->y)) cco_yield(); } - cco_final: cco_end(); } @@ -48,9 +46,11 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - while (interleaved(&g), !cco_done(&g)) + while (1) { + interleaved(&g); + if (cco_done(&g)) break; printf("%d ", g.value); - + } puts(""); c_drop(IVec, &a, &b); } diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 38447c44..0073191b 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -20,10 +20,10 @@ bool file_read(struct file_read* g) while (cstr_getline(&g->line, g->fp)) cco_yield(false); - cco_final: // this label is required. - printf("finish\n"); - cstr_drop(&g->line); - fclose(g->fp); + cco_final: + printf("finish\n"); + cstr_drop(&g->line); + fclose(g->fp); cco_end(true); } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index a5db3291..9071fee0 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -35,7 +35,7 @@ bool prime(struct prime* g) { cco_yield(false); } } - cco_final: + cco_final: printf("final prm\n"); cco_end(true); } @@ -67,7 +67,7 @@ bool fibonacci(struct fibonacci* g) { } cco_yield(false); } - cco_final: + cco_final: printf("final fib\n"); cco_end(true); } @@ -91,7 +91,7 @@ bool combined(struct combined* g) { cco_reset(&g->prm); cco_await(prime(&g->prm), false); - cco_final: + cco_final: puts("final combined"); cco_end(true); } diff --git a/misc/examples/generator.c b/misc/examples/generator.c index 2bccc489..41dffafb 100644 --- a/misc/examples/generator.c +++ b/misc/examples/generator.c @@ -4,37 +4,38 @@ #include typedef struct { - int n; + int size; int a, b, c; -} Triple_value, Triple; +} Triple, Triple_value; typedef struct { Triple_value* ref; + int count; int cco_state; } Triple_iter; -bool Triple_next(Triple_iter* it) { +void Triple_next(Triple_iter* it) { Triple_value* t = it->ref; cco_begin(it); - for (t->c = 1;; ++t->c) { + for (t->c = 5; t->size; ++t->c) { for (t->a = 1; t->a < t->c; ++t->a) { for (t->b = t->a; t->b < t->c; ++t->b) { if (t->a*t->a + t->b*t->b == t->c*t->c) { - if (t->n-- == 0) cco_return; - cco_yield(true); + if (it->count++ == t->size) + cco_return; + cco_yield(); } } } } - cco_final: - it->ref = NULL; - cco_end(false); + cco_final: + it->ref = NULL; + cco_end(); } Triple_iter Triple_begin(Triple* t) { - Triple_iter it = {t}; - if (t->n > 0) Triple_next(&it); - else it.ref = NULL; + Triple_iter it = {.ref=t}; + Triple_next(&it); return it; } @@ -42,11 +43,10 @@ Triple_iter Triple_begin(Triple* t) { int main() { puts("Pythagorean triples with c < 100:"); - Triple t = {INT32_MAX}; - c_foreach (i, Triple, t) - { + Triple triple = {.size=30}; // max number of triples + c_foreach (i, Triple, triple) { if (i.ref->c < 100) - printf("%u: (%d, %d, %d)\n", INT32_MAX - i.ref->n + 1, i.ref->a, i.ref->b, i.ref->c); + printf("%u: (%d, %d, %d)\n", i.count, i.ref->a, i.ref->b, i.ref->c); else cco_stop(&i); } diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index db9c2716..04107d5e 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -42,7 +42,6 @@ static bool taskA(struct Task* task) puts("A is back doing more work"); cco_yield(resume_task(task)); puts("A is back doing even more work"); - cco_final: cco_end(true); } @@ -54,7 +53,6 @@ static bool taskB(struct Task* task) puts("B is back doing work"); cco_yield(resume_task(task)); puts("B is back doing more work"); - cco_final: cco_end(true); } diff --git a/misc/examples/triples.c b/misc/examples/triples.c index 2e0211c3..183b7389 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -3,12 +3,21 @@ #include #include +int gcd(int a, int b) { + while (b) { + int t = a % b; + a = b; + b = t; + } + return a; +} + void triples_vanilla(int n) { - for (int c = 5; n; ++c) { + for (int c = 5, i = 0; n; ++c) { for (int a = 1; a < c; ++a) { for (int b = a + 1; b < c; ++b) { - if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) { - printf("{%d, %d, %d}\n", a, b, c); + if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c && gcd(a, b) == 1) { + printf("%d: {%d, %d, %d}\n", ++i, a, b, c); if (--n == 0) goto done; } } @@ -18,41 +27,34 @@ void triples_vanilla(int n) { } struct triples { - int n; + int size, count; int a, b, c; int cco_state; }; -bool triples_coro(struct triples* I) { - cco_begin(I); - for (I->c = 5; I->n; ++I->c) { - for (I->a = 1; I->a < I->c; ++I->a) { - for (I->b = I->a + 1; I->b < I->c; ++I->b) { - if ((int64_t)I->a*I->a + (int64_t)I->b*I->b == (int64_t)I->c*I->c) { +bool triples_coro(struct triples* t) { + cco_begin(t); + t->count = 0; + for (t->c = 5; t->size; ++t->c) { + for (t->a = 1; t->a < t->c; ++t->a) { + for (t->b = t->a + 1; t->b < t->c; ++t->b) { + if ((int64_t)t->a*t->a + (int64_t)t->b*t->b == (int64_t)t->c*t->c) { + if (t->count++ == t->size) + cco_return; cco_yield(false); - if (--I->n == 0) cco_return; } } } } - cco_final: + cco_final: puts("done"); cco_end(true); } -int gcd(int a, int b) { - while (b) { - int t = a % b; - a = b; - b = t; - } - return a; -} - int main() { puts("Vanilla triples:"); - triples_vanilla(6); + triples_vanilla(5); puts("\nCoroutine triples:"); struct triples t = {INT32_MAX}; -- cgit v1.2.3 From bca31bb8d85d6781f0c3d074eb1a25fa6de48e07 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 8 May 2023 07:40:41 +0200 Subject: Updated API for timer and semaphores in coroutine.h (ctimer, csem) --- docs/ccommon_api.md | 17 ++++++++--- include/stc/algo/coroutine.h | 68 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 2319109b..c20043f8 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -362,12 +362,21 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_yield()` | Suspend execution | | | `cco_yield(retval)` | Suspend execution and return retval | | | `cco_await(promise)` | Suspend until promise is true | -| | `cco_await_with(promise, retval)` | Suspend with retval until promise is true | +| | `cco_await(promise, retval)` | Suspend with retval until promise is true | | | Semaphores: | | -| | `cco_semaphore` | Semaphore type | +| | `csem` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | -| | `cco_await_sem_with(sem, retval)` | Await with retval for the semaphore | -| | `cco_signal_sem(sem)` | Signal the semaphore by increasing count| +| | `cco_await_sem(sem, retval)` | Await with retval for the semaphore | +| | `csem_set(sem, long value)` | Set semaphore | +| | `csem_signal(sem)` | Signal the semaphore | +| | Timers: | | +| | `ctimer` | Timer type | +| | `cco_await_timer(tm)` | Await for timer to expire | +| | `cco_await_timer(tm, retval)` | Await with retval for timer to expire | +| | `ctimer_start(tm, long msecs)` | Start timer for milliseconds | +| | `ctimer_restart(tm)` | Restart timer with same duration | +| `bool` | `ctimer_expired(tm)` | Return true if timer is expired | +| `long` | `ctimer_remaining(tm)` | Return milliseconds remaining | | | From caller side: | | | `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index c9cb8fc0..80b96bbd 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -108,17 +108,14 @@ enum { if (*_state == cco_state_done) *_state = 0; \ } while (0) +/* + * Semaphore + */ typedef struct { intptr_t count; -} cco_semaphore; +} csem; -/** - * Wait for a semaphore - * - * This macro carries out the "wait" operation on the semaphore, - * and causes the "thread" to block while the counter is zero. - */ #define cco_await_sem(...) c_MACRO_OVERLOAD(cco_await_sem, __VA_ARGS__) #define cco_await_sem_1(sem) cco_await_sem_2(sem, ) #define cco_await_sem_2(sem, retval) \ @@ -127,14 +124,55 @@ typedef struct { --(sem)->count; \ } while (0) -/** - * Signal a semaphore - * - * This macro carries out the "signal" operation on the semaphore, - * and increments the counter inside the semaphore, which - * eventually will cause waiting "threads" to continue executing. +#define csem_signal(sem) ++(sem)->count +#define csem_set(sem, value) ((sem)->count = (value)) + +/* + * Timer */ -#define cco_signal_sem(sem) ++(sem)->count -#define cco_reset_sem(sem, value) ((sem)->count = (value)) + +#include + +#ifdef _WIN32 + static inline void csleep_ms(long msecs) { + extern void Sleep(unsigned long); + Sleep((unsigned long)msecs); + } +#elif _POSIX_C_SOURCE >= 199309L + static inline void csleep_ms(long msecs) { + struct timespec ts = {msecs/1000, 1000000*(msecs % 1000)}; + nanosleep(&ts, NULL); + } +#endif + +typedef struct { + clock_t start; + clock_t interval; +} ctimer; + +#define cco_await_timer(...) c_MACRO_OVERLOAD(cco_await_timer, __VA_ARGS__) +#define cco_await_timer_2(t, msecs) cco_await_timer_3(t, msecs, ) +#define cco_await_timer_3(t, msecs, ret) \ + do { \ + ctimer_start(t, msecs); \ + cco_await_2(ctimer_expired(t), ret); \ + } while (0) + +static inline void ctimer_start(ctimer* t, long msecs) { + t->interval = msecs*(CLOCKS_PER_SEC/1000); + t->start = clock(); +} + +static inline void ctimer_restart(ctimer* t) { + t->start = clock(); +} + +static inline bool ctimer_expired(ctimer* t) { + return clock() - t->start >= t->interval; +} + +static inline long ctimer_remaining(ctimer* t) { + return (long)((double)(t->start + t->interval - clock())*(1000.0/CLOCKS_PER_SEC)); +} #endif -- cgit v1.2.3 From b909bee0e400fa12908bc3d9bca447ea2a71864b Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 8 May 2023 11:14:03 +0200 Subject: More coroutine updates. --- docs/ccommon_api.md | 7 ++++-- include/stc/algo/coroutine.h | 53 ++++++++++++++++++++++++++------------------ misc/examples/coroutines.c | 12 +++++----- 3 files changed, 42 insertions(+), 30 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index c20043f8..daf21e56 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -314,7 +314,7 @@ bool triples(struct triples* i) { // coroutine } } } - cco_final: // required for cleanup + cco_final: // tear down puts("done"); cco_end(true); } @@ -363,6 +363,8 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_yield(retval)` | Suspend execution and return retval | | | `cco_await(promise)` | Suspend until promise is true | | | `cco_await(promise, retval)` | Suspend with retval until promise is true | +| | `cco_call(ctx, corocall)` | Call coro async, suspend while not done | +| | `cco_call(ctx, corocall, retval)` | Call coro async, return retval on suspend | | | Semaphores: | | | | `csem` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | @@ -373,13 +375,14 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `ctimer` | Timer type | | | `cco_await_timer(tm)` | Await for timer to expire | | | `cco_await_timer(tm, retval)` | Await with retval for timer to expire | -| | `ctimer_start(tm, long msecs)` | Start timer for milliseconds | +| | `ctimer_start(tm, long msecs)` | Start timer msecs milliseconds | | | `ctimer_restart(tm)` | Restart timer with same duration | | `bool` | `ctimer_expired(tm)` | Return true if timer is expired | | `long` | `ctimer_remaining(tm)` | Return milliseconds remaining | | | From caller side: | | | `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | +| `void` | `cco_run_blocked(ctx, corocall) { }` | Call coro blocked until done | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 80b96bbd..942abc5a 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -62,12 +62,12 @@ enum { cco_state_done = -2, }; -#define cco_initial(ctx) ((ctx)->cco_state == 0) -#define cco_suspended(ctx) ((ctx)->cco_state > 0) -#define cco_done(ctx) ((ctx)->cco_state == cco_state_done) +#define cco_initial(co) ((co)->cco_state == 0) +#define cco_suspended(co) ((co)->cco_state > 0) +#define cco_done(co) ((co)->cco_state == cco_state_done) -#define cco_begin(ctx) \ - int *_state = &(ctx)->cco_state; \ +#define cco_begin(co) \ + int *_state = &(co)->cco_state; \ goto _begin; _begin: switch (*_state) { \ case 0: @@ -90,21 +90,30 @@ enum { case __LINE__: if (!(promise)) return retval; \ } while (0) +#define cco_call(...) c_MACRO_OVERLOAD(cco_call, __VA_ARGS__) +#define cco_call_2(co, call) cco_call_3(co, call, ) +#define cco_call_3(co, call, retval) cco_await_2((call, cco_done(co)), retval) + +#define cco_run_blocked(co, call) while (call, !cco_done(co)) + #define cco_final \ case cco_state_final #define cco_return \ do { *_state = cco_state_final; goto _begin; } while (0) -#define cco_stop(ctx) \ +#define cco_return_v(value) \ + return (*_state = cco_state_final, value) + +#define cco_stop(co) \ do { \ - int* _state = &(ctx)->cco_state; \ + int* _state = &(co)->cco_state; \ if (*_state > 0) *_state = cco_state_final; \ } while (0) -#define cco_reset(ctx) \ +#define cco_reset(co) \ do { \ - int* _state = &(ctx)->cco_state; \ + int* _state = &(co)->cco_state; \ if (*_state == cco_state_done) *_state = 0; \ } while (0) @@ -151,28 +160,28 @@ typedef struct { } ctimer; #define cco_await_timer(...) c_MACRO_OVERLOAD(cco_await_timer, __VA_ARGS__) -#define cco_await_timer_2(t, msecs) cco_await_timer_3(t, msecs, ) -#define cco_await_timer_3(t, msecs, ret) \ +#define cco_await_timer_2(tm, msecs) cco_await_timer_3(tm, msecs, ) +#define cco_await_timer_3(tm, msecs, ret) \ do { \ - ctimer_start(t, msecs); \ - cco_await_2(ctimer_expired(t), ret); \ + ctimer_start(tm, msecs); \ + cco_await_2(ctimer_expired(tm), ret); \ } while (0) -static inline void ctimer_start(ctimer* t, long msecs) { - t->interval = msecs*(CLOCKS_PER_SEC/1000); - t->start = clock(); +static inline void ctimer_start(ctimer* tm, long msecs) { + tm->interval = msecs*(CLOCKS_PER_SEC/1000); + tm->start = clock(); } -static inline void ctimer_restart(ctimer* t) { - t->start = clock(); +static inline void ctimer_restart(ctimer* tm) { + tm->start = clock(); } -static inline bool ctimer_expired(ctimer* t) { - return clock() - t->start >= t->interval; +static inline bool ctimer_expired(ctimer* tm) { + return clock() - tm->start >= tm->interval; } -static inline long ctimer_remaining(ctimer* t) { - return (long)((double)(t->start + t->interval - clock())*(1000.0/CLOCKS_PER_SEC)); +static inline long ctimer_remaining(ctimer* tm) { + return (long)((double)(tm->start + tm->interval - clock())*(1000.0/CLOCKS_PER_SEC)); } #endif diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 9071fee0..7f255dda 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -81,26 +81,26 @@ struct combined { }; -bool combined(struct combined* g) { +void combined(struct combined* g) { cco_begin(g); - cco_await(prime(&g->prm), false); - cco_await(fibonacci(&g->fib), false); + cco_await(prime(&g->prm)); + cco_await(fibonacci(&g->fib)); // Reuse the g->prm context and extend the count: g->prm.count = 8, g->prm.result += 2; cco_reset(&g->prm); - cco_await(prime(&g->prm), false); + cco_await(prime(&g->prm)); cco_final: puts("final combined"); - cco_end(true); + cco_end(); } int main(void) { struct combined c = {.prm={.count=8}, .fib={14}}; - while (!combined(&c)) { + cco_run_blocked(&c, combined(&c)) { printf("Prime(%d)=%lld, Fib(%d)=%lld\n", c.prm.idx, c.prm.result, c.fib.idx, c.fib.result); -- cgit v1.2.3 From f8f544d8f5b805b9749f1e06fd7c1875b6115d48 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 8 May 2023 13:23:05 +0200 Subject: Final coroutine API updates. --- docs/ccommon_api.md | 34 ++++++++++++++++++---------------- include/stc/algo/coroutine.h | 27 ++++++++++++++++----------- misc/examples/cointerleave.c | 13 ++++--------- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index daf21e56..fb29d642 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -354,35 +354,37 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c |:----------|:-------------------------------------|:----------------------------------------| | | `cco_final:` | Label for cleanup in coroutine | | | `cco_return` | Early return from the coroutine (no arg) | -| `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? | -| `bool` | `cco_done(ctx)` | Is coroutine done? | -| | `cco_begin(ctx)` | Begin coroutine block | +| `bool` | `cco_suspended(co)` | Is coroutine in suspended state? | +| `bool` | `cco_done(co)` | Is coroutine done? | +| | `cco_begin(co)` | Begin coroutine block | | | `cco_end()` | End coroutine block | -| | `cco_end(retval)` | End coroutine block and return retval | -| | `cco_yield()` | Suspend execution | -| | `cco_yield(retval)` | Suspend execution and return retval | -| | `cco_await(promise)` | Suspend until promise is true | -| | `cco_await(promise, retval)` | Suspend with retval until promise is true | -| | `cco_call(ctx, corocall)` | Call coro async, suspend while not done | -| | `cco_call(ctx, corocall, retval)` | Call coro async, return retval on suspend | +| | `cco_end(ret)` | End coroutine block and return ret | +| | `cco_yield()` | Yield/suspend execution | +| | `cco_yield(ret)` | Yield/suspend execution and return ret | +| | `cco_yield_sub(subco, call)` | Yield if subco not done after call | +| | `cco_yield_sub(subco, call, ret)` | Yield with ret if subco alive after call | +| | `cco_await(promise)` | Wait/suspend until promise is true | +| | `cco_await(promise, ret)` | Wait/suspend with ret value | +| | `cco_await_sub(subco, call)` | Wait/suspend until subco call is done | +| | `cco_await_sub(subco, call, ret)` | Wait/suspend with ret on subco call done | | | Semaphores: | | | | `csem` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | -| | `cco_await_sem(sem, retval)` | Await with retval for the semaphore | -| | `csem_set(sem, long value)` | Set semaphore | +| | `cco_await_sem(sem, ret)` | Await with ret on the semaphore | +| | `csem_set(sem, long value)` | Set semaphore value | | | `csem_signal(sem)` | Signal the semaphore | | | Timers: | | | | `ctimer` | Timer type | | | `cco_await_timer(tm)` | Await for timer to expire | -| | `cco_await_timer(tm, retval)` | Await with retval for timer to expire | +| | `cco_await_timer(tm, ret)` | Await with ret for timer to expire | | | `ctimer_start(tm, long msecs)` | Start timer msecs milliseconds | | | `ctimer_restart(tm)` | Restart timer with same duration | | `bool` | `ctimer_expired(tm)` | Return true if timer is expired | | `long` | `ctimer_remaining(tm)` | Return milliseconds remaining | | | From caller side: | | -| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | -| `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | -| `void` | `cco_run_blocked(ctx, corocall) { }` | Call coro blocked until done | +| `void` | `cco_stop(co)` | Next call of coroutine returns `cco_end()` | +| `void` | `cco_reset(co)` | Reset state to initial (for reuse) | +| `void` | `cco_run_blocked(co, corocall) { }` | Call coro blocked until done | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 942abc5a..83814605 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -71,28 +71,33 @@ enum { goto _begin; _begin: switch (*_state) { \ case 0: -#define cco_end(retval) \ +#define cco_end(ret) \ } \ *_state = cco_state_done; \ - return retval + return ret -#define cco_yield(retval) \ +#define cco_yield(ret) \ do { \ - *_state = __LINE__; return retval; \ + *_state = __LINE__; return ret; \ case __LINE__:; \ } while (0) +#define cco_yield_sub(...) c_MACRO_OVERLOAD(cco_yield_sub, __VA_ARGS__) +#define cco_yield_sub_2(co, call) cco_yield_sub_3(co, call, ) +#define cco_yield_sub_3(co, call, ret) \ + do { call; if (!cco_done(co)) cco_yield(ret); } while (0) + #define cco_await(...) c_MACRO_OVERLOAD(cco_await, __VA_ARGS__) #define cco_await_1(promise) cco_await_2(promise, ) -#define cco_await_2(promise, retval) \ +#define cco_await_2(promise, ret) \ do { \ *_state = __LINE__; \ - case __LINE__: if (!(promise)) return retval; \ + case __LINE__: if (!(promise)) return ret; \ } while (0) -#define cco_call(...) c_MACRO_OVERLOAD(cco_call, __VA_ARGS__) -#define cco_call_2(co, call) cco_call_3(co, call, ) -#define cco_call_3(co, call, retval) cco_await_2((call, cco_done(co)), retval) +#define cco_await_sub(...) c_MACRO_OVERLOAD(cco_await_sub, __VA_ARGS__) +#define cco_await_sub_2(co, call) cco_await_sub_3(co, call, ) +#define cco_await_sub_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) #define cco_run_blocked(co, call) while (call, !cco_done(co)) @@ -127,9 +132,9 @@ typedef struct { #define cco_await_sem(...) c_MACRO_OVERLOAD(cco_await_sem, __VA_ARGS__) #define cco_await_sem_1(sem) cco_await_sem_2(sem, ) -#define cco_await_sem_2(sem, retval) \ +#define cco_await_sem_2(sem, ret) \ do { \ - cco_await_2((sem)->count > 0, retval); \ + cco_await_2((sem)->count > 0, ret); \ --(sem)->count; \ } while (0) diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 4fe89316..0ccf9ad7 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -11,7 +11,7 @@ struct GenValue { int cco_state; }; -static int next_value(struct GenValue* g) +static int get_value(struct GenValue* g) { cco_begin(g); for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) @@ -30,11 +30,8 @@ void interleaved(struct Generator* g) cco_begin(g); while (!cco_done(&g->x) || !cco_done(&g->y)) { - g->value = next_value(&g->x); - if (!cco_done(&g->x)) cco_yield(); - - g->value = next_value(&g->y); - if (!cco_done(&g->y)) cco_yield(); + cco_yield_sub(&g->x, g->value = get_value(&g->x)); + cco_yield_sub(&g->y, g->value = get_value(&g->y)); } cco_end(); } @@ -46,9 +43,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - while (1) { - interleaved(&g); - if (cco_done(&g)) break; + cco_run_blocked(&g, interleaved(&g)) { printf("%d ", g.value); } puts(""); -- cgit v1.2.3 From 2f11c7cf36690a1493344189b6a011c26ee58a9b Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 8 May 2023 18:45:24 +0200 Subject: coroutine cco_await_* and cco_yield_* changes. --- docs/ccommon_api.md | 12 ++++++------ include/stc/algo/coroutine.h | 12 ++++++------ misc/examples/cointerleave.c | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index fb29d642..512aeb80 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -361,12 +361,12 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_end(ret)` | End coroutine block and return ret | | | `cco_yield()` | Yield/suspend execution | | | `cco_yield(ret)` | Yield/suspend execution and return ret | -| | `cco_yield_sub(subco, call)` | Yield if subco not done after call | -| | `cco_yield_sub(subco, call, ret)` | Yield with ret if subco alive after call | -| | `cco_await(promise)` | Wait/suspend until promise is true | -| | `cco_await(promise, ret)` | Wait/suspend with ret value | -| | `cco_await_sub(subco, call)` | Wait/suspend until subco call is done | -| | `cco_await_sub(subco, call, ret)` | Wait/suspend with ret on subco call done | +| | `cco_yield_at(co, call)` | Yield next in co call, if not done | +| | `cco_yield_at(co, call, ret)` | Yield next in co call with ret | +| | `cco_await(promise)` | Await/suspend until promise is true | +| | `cco_await(promise, ret)` | Await/suspend with ret value | +| | `cco_await_done(co, call)` | Await for co call to finish | +| | `cco_await_done(co, call, ret)` | Await for co call to finish with ret | | | Semaphores: | | | | `csem` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 83814605..979e05bb 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -82,9 +82,9 @@ enum { case __LINE__:; \ } while (0) -#define cco_yield_sub(...) c_MACRO_OVERLOAD(cco_yield_sub, __VA_ARGS__) -#define cco_yield_sub_2(co, call) cco_yield_sub_3(co, call, ) -#define cco_yield_sub_3(co, call, ret) \ +#define cco_yield_at(...) c_MACRO_OVERLOAD(cco_yield_at, __VA_ARGS__) +#define cco_yield_at_2(co, call) cco_yield_at_3(co, call, ) +#define cco_yield_at_3(co, call, ret) \ do { call; if (!cco_done(co)) cco_yield(ret); } while (0) #define cco_await(...) c_MACRO_OVERLOAD(cco_await, __VA_ARGS__) @@ -95,9 +95,9 @@ enum { case __LINE__: if (!(promise)) return ret; \ } while (0) -#define cco_await_sub(...) c_MACRO_OVERLOAD(cco_await_sub, __VA_ARGS__) -#define cco_await_sub_2(co, call) cco_await_sub_3(co, call, ) -#define cco_await_sub_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) +#define cco_await_done(...) c_MACRO_OVERLOAD(cco_await_done, __VA_ARGS__) +#define cco_await_done_2(co, call) cco_await_done_3(co, call, ) +#define cco_await_done_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) #define cco_run_blocked(co, call) while (call, !cco_done(co)) diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 0ccf9ad7..0854a741 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -28,10 +28,10 @@ struct Generator { void interleaved(struct Generator* g) { cco_begin(g); - while (!cco_done(&g->x) || !cco_done(&g->y)) + while (!(cco_done(&g->x) & cco_done(&g->y))) { - cco_yield_sub(&g->x, g->value = get_value(&g->x)); - cco_yield_sub(&g->y, g->value = get_value(&g->y)); + cco_yield_at(&g->x, g->value = get_value(&g->x)); + cco_yield_at(&g->y, g->value = get_value(&g->y)); } cco_end(); } -- cgit v1.2.3 From 99d94309f31f082b505180d2cb7c1c6c2215e9f0 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Tue, 9 May 2023 04:40:24 +0200 Subject: reverted cco_await_done => cco_await_at. --- docs/ccommon_api.md | 10 +++++----- include/stc/algo/coroutine.h | 8 ++++---- include/stc/cpque.h | 5 +++-- misc/examples/cointerleave.c | 2 +- misc/examples/coread.c | 11 +++++------ misc/examples/coroutines.c | 2 +- misc/examples/scheduler.c | 12 ++++++------ 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 512aeb80..93ad2bb7 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -361,12 +361,12 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_end(ret)` | End coroutine block and return ret | | | `cco_yield()` | Yield/suspend execution | | | `cco_yield(ret)` | Yield/suspend execution and return ret | -| | `cco_yield_at(co, call)` | Yield next in co call, if not done | -| | `cco_yield_at(co, call, ret)` | Yield next in co call with ret | +| | `cco_yield_at(co, call)` | Yield at co call if it is suspended | +| | `cco_yield_at(co, call, ret)` | Yield at co call with ret if suspended | | | `cco_await(promise)` | Await/suspend until promise is true | | | `cco_await(promise, ret)` | Await/suspend with ret value | -| | `cco_await_done(co, call)` | Await for co call to finish | -| | `cco_await_done(co, call, ret)` | Await for co call to finish with ret | +| | `cco_await_at(co, call)` | Await for co call to finish | +| | `cco_await_at(co, call, ret)` | Await for co call to finish with ret | | | Semaphores: | | | | `csem` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | @@ -384,7 +384,7 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_run_blocked(co, corocall) { }` | Call coro blocked until done | +| `void` | `cco_run(co, corocall) { }` | Run blocking until coro is done | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 979e05bb..2ea7122b 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -95,11 +95,11 @@ enum { case __LINE__: if (!(promise)) return ret; \ } while (0) -#define cco_await_done(...) c_MACRO_OVERLOAD(cco_await_done, __VA_ARGS__) -#define cco_await_done_2(co, call) cco_await_done_3(co, call, ) -#define cco_await_done_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) +#define cco_await_at(...) c_MACRO_OVERLOAD(cco_await_at, __VA_ARGS__) +#define cco_await_at_2(co, call) cco_await_at_3(co, call, ) +#define cco_await_at_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) -#define cco_run_blocked(co, call) while (call, !cco_done(co)) +#define cco_run(co, call) while (call, !cco_done(co)) #define cco_final \ case cco_state_final diff --git a/include/stc/cpque.h b/include/stc/cpque.h index c76621cd..85002c67 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -36,7 +36,7 @@ typedef i_keyraw _cx_raw; STC_API void _cx_memb(_make_heap)(_cx_self* self); STC_API void _cx_memb(_erase_at)(_cx_self* self, intptr_t idx); -STC_API void _cx_memb(_push)(_cx_self* self, _cx_value value); +STC_API _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value value); STC_INLINE _cx_self _cx_memb(_init)(void) { return c_LITERAL(_cx_self){NULL}; } @@ -144,7 +144,7 @@ _cx_memb(_erase_at)(_cx_self* self, const intptr_t idx) { _cx_memb(_sift_down_)(self, idx + 1, n); } -STC_DEF void +STC_DEF _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value value) { if (self->_len == self->_cap) _cx_memb(_reserve)(self, self->_len*3/2 + 4); @@ -153,6 +153,7 @@ _cx_memb(_push)(_cx_self* self, _cx_value value) { for (; c > 1 && (i_less((&arr[c/2]), (&value))); c /= 2) arr[c] = arr[c/2]; arr[c] = value; + return arr + c; } #endif diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 0854a741..d725989f 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -43,7 +43,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - cco_run_blocked(&g, interleaved(&g)) { + cco_run(&g, interleaved(&g)) { printf("%d ", g.value); } puts(""); diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 0073191b..e60fb31c 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -11,29 +11,28 @@ struct file_read { cstr line; }; -bool file_read(struct file_read* g) +void file_read(struct file_read* g) { cco_begin(g) g->fp = fopen(g->filename, "r"); g->line = cstr_init(); - while (cstr_getline(&g->line, g->fp)) - cco_yield(false); + cco_await(!cstr_getline(&g->line, g->fp)); cco_final: printf("finish\n"); cstr_drop(&g->line); fclose(g->fp); - cco_end(true); + cco_end(); } int main(void) { struct file_read g = {__FILE__}; int n = 0; - while (!file_read(&g)) + cco_run(&g, file_read(&g)) { printf("%3d %s\n", ++n, cstr_str(&g.line)); - //if (n == 10) cco_stop(&it); + //if (n == 10) cco_stop(&g); } } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 7f255dda..a7136993 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -100,7 +100,7 @@ int main(void) { struct combined c = {.prm={.count=8}, .fib={14}}; - cco_run_blocked(&c, combined(&c)) { + cco_run(&c, combined(&c)) { printf("Prime(%d)=%lld, Fib(%d)=%lld\n", c.prm.idx, c.prm.result, c.fib.idx, c.fib.result); diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index 04107d5e..bad5201b 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -25,7 +25,7 @@ static bool schedule(Scheduler* sched) return !Scheduler_empty(sched); } -static bool resume_task(const struct Task* task) +static bool push_task(const struct Task* task) { Scheduler_push_back(task->sched, *task); return false; @@ -36,11 +36,11 @@ static bool taskA(struct Task* task) { cco_begin(task); puts("Hello, from task A"); - cco_yield(resume_task(task)); + cco_yield(push_task(task)); puts("A is back doing work"); - cco_yield(resume_task(task)); + cco_yield(push_task(task)); puts("A is back doing more work"); - cco_yield(resume_task(task)); + cco_yield(push_task(task)); puts("A is back doing even more work"); cco_end(true); } @@ -49,9 +49,9 @@ static bool taskB(struct Task* task) { cco_begin(task); puts("Hello, from task B"); - cco_yield(resume_task(task)); + cco_yield(push_task(task)); puts("B is back doing work"); - cco_yield(resume_task(task)); + cco_yield(push_task(task)); puts("B is back doing more work"); cco_end(true); } -- cgit v1.2.3 From 992950d20096848f606525dffc96c74bda52c543 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Tue, 9 May 2023 16:30:08 +0200 Subject: Renaming. --- docs/ccommon_api.md | 8 ++++---- include/stc/algo/coroutine.h | 14 +++++++------- misc/examples/cointerleave.c | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 93ad2bb7..e4c881dd 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -361,12 +361,12 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_end(ret)` | End coroutine block and return ret | | | `cco_yield()` | Yield/suspend execution | | | `cco_yield(ret)` | Yield/suspend execution and return ret | -| | `cco_yield_at(co, call)` | Yield at co call if it is suspended | -| | `cco_yield_at(co, call, ret)` | Yield at co call with ret if suspended | +| | `cco_yield_coro(co, call)` | Yield at co call if it is suspended | +| | `cco_yield_coro(co, call, ret)` | Yield at co call with ret if suspended | | | `cco_await(promise)` | Await/suspend until promise is true | | | `cco_await(promise, ret)` | Await/suspend with ret value | -| | `cco_await_at(co, call)` | Await for co call to finish | -| | `cco_await_at(co, call, ret)` | Await for co call to finish with ret | +| | `cco_await_coro(co, call)` | Await for co call to finish | +| | `cco_await_coro(co, call, ret)` | Await for co call to finish with ret | | | Semaphores: | | | | `csem` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 2ea7122b..8d3b79b5 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -82,12 +82,12 @@ enum { case __LINE__:; \ } while (0) -#define cco_yield_at(...) c_MACRO_OVERLOAD(cco_yield_at, __VA_ARGS__) -#define cco_yield_at_2(co, call) cco_yield_at_3(co, call, ) -#define cco_yield_at_3(co, call, ret) \ +#define cco_yield_coro(...) c_MACRO_OVERLOAD(cco_yield_coro, __VA_ARGS__) +#define cco_yield_coro_2(co, call) cco_yield_coro_3(co, call, ) +#define cco_yield_coro_3(co, call, ret) \ do { call; if (!cco_done(co)) cco_yield(ret); } while (0) -#define cco_await(...) c_MACRO_OVERLOAD(cco_await, __VA_ARGS__) +#define cco_await(...) c_MACRO_OVERLOAD(cco_awaitcoro, __VA_ARGS__) #define cco_await_1(promise) cco_await_2(promise, ) #define cco_await_2(promise, ret) \ do { \ @@ -95,9 +95,9 @@ enum { case __LINE__: if (!(promise)) return ret; \ } while (0) -#define cco_await_at(...) c_MACRO_OVERLOAD(cco_await_at, __VA_ARGS__) -#define cco_await_at_2(co, call) cco_await_at_3(co, call, ) -#define cco_await_at_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) +#define cco_await_coro(...) c_MACRO_OVERLOAD(cco_await_coro, __VA_ARGS__) +#define cco_await_coro_2(co, call) cco_await_2((call, cco_done(co)), ) +#define cco_await_coro_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) #define cco_run(co, call) while (call, !cco_done(co)) diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index d725989f..aa57808e 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -30,9 +30,9 @@ void interleaved(struct Generator* g) cco_begin(g); while (!(cco_done(&g->x) & cco_done(&g->y))) { - cco_yield_at(&g->x, g->value = get_value(&g->x)); - cco_yield_at(&g->y, g->value = get_value(&g->y)); - } + cco_yield_coro(&g->x, g->value = get_value(&g->x)); + cco_yield_coro(&g->y, g->value = get_value(&g->y)); + } cco_end(); } -- cgit v1.2.3 From 98d131bfc1bcc8b82cb27b30ad6da176d1fed117 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Tue, 9 May 2023 16:36:46 +0200 Subject: fixed typo. --- include/stc/algo/coroutine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 8d3b79b5..c3f36ac2 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -87,7 +87,7 @@ enum { #define cco_yield_coro_3(co, call, ret) \ do { call; if (!cco_done(co)) cco_yield(ret); } while (0) -#define cco_await(...) c_MACRO_OVERLOAD(cco_awaitcoro, __VA_ARGS__) +#define cco_await(...) c_MACRO_OVERLOAD(cco_await, __VA_ARGS__) #define cco_await_1(promise) cco_await_2(promise, ) #define cco_await_2(promise, ret) \ do { \ -- cgit v1.2.3 From be7d9913d4a284bdeb7f0431482b5731b5ef31df Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sat, 13 May 2023 11:04:11 +0200 Subject: File priv/raii.h no longer included by stc/ccommon.h, instead moved to stc/algo/raii.h and included by stc/calgo.h --- include/stc/algo/raii.h | 54 ++++++++++++++++++++++++++++++++++++++++++ include/stc/calgo.h | 1 + include/stc/ccommon.h | 3 +-- include/stc/priv/raii.h | 27 --------------------- misc/examples/arc_containers.c | 1 + misc/examples/astar.c | 1 + misc/examples/bits.c | 1 + misc/examples/box2.c | 1 + misc/examples/convert.c | 1 + misc/examples/person_arc.c | 1 + misc/examples/read.c | 1 + misc/examples/regex_replace.c | 1 + misc/examples/sorted_map.c | 3 ++- misc/examples/unordered_set.c | 1 + misc/tests/cregex_test.c | 1 + misc/tests/cspan_test.c | 1 + 16 files changed, 69 insertions(+), 30 deletions(-) create mode 100644 include/stc/algo/raii.h delete mode 100644 include/stc/priv/raii.h diff --git a/include/stc/algo/raii.h b/include/stc/algo/raii.h new file mode 100644 index 00000000..7b1b445b --- /dev/null +++ b/include/stc/algo/raii.h @@ -0,0 +1,54 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ +#ifndef STC_RAII_INCLUDED +#define STC_RAII_INCLUDED + +#define c_defer(...) \ + for (int _i = 1; _i; _i = 0, __VA_ARGS__) + +#define c_with(...) c_MACRO_OVERLOAD(c_with, __VA_ARGS__) +#define c_with_2(declvar, drop) \ + for (declvar, *_i, **_ip = &_i; _ip; _ip = 0, drop) +#define c_with_3(declvar, pred, drop) \ + for (declvar, *_i, **_ip = &_i; _ip && (pred); _ip = 0, drop) + +#define c_scope(...) c_MACRO_OVERLOAD(c_scope, __VA_ARGS__) +#define c_scope_2(init, drop) \ + for (int _i = (init, 1); _i; _i = 0, drop) +#define c_scope_3(init, pred, drop) \ + for (int _i = (init, 1); _i && (pred); _i = 0, drop) + +#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__) +#define c_auto_2(C, a) \ + c_with_2(C a = C##_init(), C##_drop(&a)) +#define c_auto_3(C, a, b) \ + c_with_2(c_EXPAND(C a = C##_init(), b = C##_init()), \ + (C##_drop(&b), C##_drop(&a))) +#define c_auto_4(C, a, b, c) \ + c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init()), \ + (C##_drop(&c), C##_drop(&b), C##_drop(&a))) +#define c_auto_5(C, a, b, c, d) \ + c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \ + (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a))) + +#endif \ No newline at end of file diff --git a/include/stc/calgo.h b/include/stc/calgo.h index 21e73faf..63ef97b9 100644 --- a/include/stc/calgo.h +++ b/include/stc/calgo.h @@ -1,6 +1,7 @@ #ifndef STC_CALGO_INCLUDED #define STC_CALGO_INCLUDED +#include "algo/raii.h" #include "algo/crange.h" #include "algo/filter.h" #include "algo/coroutine.h" diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 1882646c..fd673696 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -29,7 +29,6 @@ #include #include #include -#include "priv/raii.h" #define c_NPOS INTPTR_MAX #define c_ZI PRIiPTR @@ -62,7 +61,7 @@ #define _c_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ _14, _15, _16, N, ...) N -#ifdef __cplusplus +#ifdef __cplusplus #include #define _i_alloc(T) static_cast(i_malloc(c_sizeof(T))) #define _i_new(T, ...) new (_i_alloc(T)) T(__VA_ARGS__) diff --git a/include/stc/priv/raii.h b/include/stc/priv/raii.h deleted file mode 100644 index bb41e0d1..00000000 --- a/include/stc/priv/raii.h +++ /dev/null @@ -1,27 +0,0 @@ -#define c_defer(...) \ - for (int _i = 1; _i; _i = 0, __VA_ARGS__) - -#define c_with(...) c_MACRO_OVERLOAD(c_with, __VA_ARGS__) -#define c_with_2(declvar, drop) \ - for (declvar, *_i, **_ip = &_i; _ip; _ip = 0, drop) -#define c_with_3(declvar, pred, drop) \ - for (declvar, *_i, **_ip = &_i; _ip && (pred); _ip = 0, drop) - -#define c_scope(...) c_MACRO_OVERLOAD(c_scope, __VA_ARGS__) -#define c_scope_2(init, drop) \ - for (int _i = (init, 1); _i; _i = 0, drop) -#define c_scope_3(init, pred, drop) \ - for (int _i = (init, 1); _i && (pred); _i = 0, drop) - -#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__) -#define c_auto_2(C, a) \ - c_with_2(C a = C##_init(), C##_drop(&a)) -#define c_auto_3(C, a, b) \ - c_with_2(c_EXPAND(C a = C##_init(), b = C##_init()), \ - (C##_drop(&b), C##_drop(&a))) -#define c_auto_4(C, a, b, c) \ - c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init()), \ - (C##_drop(&c), C##_drop(&b), C##_drop(&a))) -#define c_auto_5(C, a, b, c, d) \ - c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \ - (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a))) diff --git a/misc/examples/arc_containers.c b/misc/examples/arc_containers.c index 84ba8dda..d6a0afa8 100644 --- a/misc/examples/arc_containers.c +++ b/misc/examples/arc_containers.c @@ -2,6 +2,7 @@ // and demonstrate sharing and cloning of maps. #define i_static #include +#include #define i_type Map #define i_key_str // strings #define i_val int diff --git a/misc/examples/astar.c b/misc/examples/astar.c index 7dd12d50..dae6d609 100644 --- a/misc/examples/astar.c +++ b/misc/examples/astar.c @@ -5,6 +5,7 @@ // https://github.com/glouw/ctl/blob/master/examples/astar.c // https://www.redblobgames.com/pathfinding/a-star/introduction.html #include +#include #include typedef struct diff --git a/misc/examples/bits.c b/misc/examples/bits.c index 1323d4e7..95452300 100644 --- a/misc/examples/bits.c +++ b/misc/examples/bits.c @@ -1,5 +1,6 @@ #include #include +#include int main(void) { diff --git a/misc/examples/box2.c b/misc/examples/box2.c index cba255d2..33212ef4 100644 --- a/misc/examples/box2.c +++ b/misc/examples/box2.c @@ -1,5 +1,6 @@ // example: https://doc.rust-lang.org/rust-by-example/std/box.html #include +#include typedef struct { double x; diff --git a/misc/examples/convert.c b/misc/examples/convert.c index 0f09e830..138035e9 100644 --- a/misc/examples/convert.c +++ b/misc/examples/convert.c @@ -1,4 +1,5 @@ #include +#include #define i_key_str #define i_val_str diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c index 620d311f..c931089d 100644 --- a/misc/examples/person_arc.c +++ b/misc/examples/person_arc.c @@ -1,5 +1,6 @@ /* cbox: heap allocated boxed type */ #include +#include typedef struct { cstr name, last; } Person; diff --git a/misc/examples/read.c b/misc/examples/read.c index 4efdcfeb..edc89f0e 100644 --- a/misc/examples/read.c +++ b/misc/examples/read.c @@ -1,4 +1,5 @@ #include +#include #define i_val_str #include #include diff --git a/misc/examples/regex_replace.c b/misc/examples/regex_replace.c index d3952f50..cad195d5 100644 --- a/misc/examples/regex_replace.c +++ b/misc/examples/regex_replace.c @@ -1,6 +1,7 @@ #define i_extern #include #include +#include bool add_10_years(int i, csview match, cstr* out) { if (i == 1) { // group 1 matches year diff --git a/misc/examples/sorted_map.c b/misc/examples/sorted_map.c index ae9b45a4..2199846c 100644 --- a/misc/examples/sorted_map.c +++ b/misc/examples/sorted_map.c @@ -1,9 +1,10 @@ // https://iq.opengenus.org/containers-cpp-stl/ +#include +#include #define i_key int #define i_val int #include -#include int main() { diff --git a/misc/examples/unordered_set.c b/misc/examples/unordered_set.c index 61f9cc1f..90c78521 100644 --- a/misc/examples/unordered_set.c +++ b/misc/examples/unordered_set.c @@ -1,6 +1,7 @@ // https://iq.opengenus.org/containers-cpp-stl/ // C program to demonstrate various function of stc cset #include +#include #define i_key_str #include diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index aa4b2a65..07e5c3cb 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -1,6 +1,7 @@ #define i_extern #include #include +#include #include "ctest.h" #define M_START(m) ((m).str - inp) diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index 5d46f579..9afa63f5 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -1,5 +1,6 @@ #include #include +#include #include "ctest.h" using_cspan3(intspan, int); -- cgit v1.2.3 From 6973d104999f47e0baad4b23d36642f86775be90 Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Thu, 18 May 2023 14:18:10 +0800 Subject: add `cco` macro, block style coroutine definition, to replace cco_begin(co) && cco_end() --- include/stc/algo/coroutine.h | 6 +++++- misc/examples/coread.c | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index c3f36ac2..78dc80c6 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -76,9 +76,13 @@ enum { *_state = cco_state_done; \ return ret +#define cco(co) \ + for (int *_state = &(co)->cco_state, _once=1; _once; *_state = cco_state_done, _once=0) \ + _begin: switch (*_state) case 0: + #define cco_yield(ret) \ do { \ - *_state = __LINE__; return ret; \ + *_state = __LINE__; return ret; goto _begin; \ case __LINE__:; \ } while (0) diff --git a/misc/examples/coread.c b/misc/examples/coread.c index e60fb31c..1976231f 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -13,7 +13,7 @@ struct file_read { void file_read(struct file_read* g) { - cco_begin(g) + cco(g) { g->fp = fopen(g->filename, "r"); g->line = cstr_init(); @@ -23,7 +23,8 @@ void file_read(struct file_read* g) printf("finish\n"); cstr_drop(&g->line); fclose(g->fp); - cco_end(); + } + return; } int main(void) -- cgit v1.2.3 From 50a16934dde8e65bbcf628d6342c1649f7e09365 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Thu, 18 May 2023 11:49:31 +0200 Subject: Huge update: cqueue and cdeq completely rewritten. cvec and cdeq API harmonized. Docs update/improved. --- README.md | 2 +- docs/ccommon_api.md | 2 +- docs/cdeq_api.md | 45 ++-- docs/clist_api.md | 10 +- docs/cqueue_api.md | 9 +- docs/csmap_api.md | 3 +- docs/cstack_api.md | 3 +- docs/cvec_api.md | 20 +- include/stc/algo/csort.h | 89 ------- include/stc/algo/sort.h | 100 ++++++++ include/stc/ccommon.h | 10 + include/stc/cdeq.h | 453 ++++++++-------------------------- include/stc/clist.h | 9 +- include/stc/cmap.h | 9 +- include/stc/cqueue.h | 226 ++++++++++++++--- include/stc/cvec.h | 121 ++++----- include/stc/forward.h | 13 +- include/stc/priv/template.h | 8 +- include/stc/priv/template2.h | 5 + misc/benchmarks/various/csort_bench.c | 44 ++-- misc/benchmarks/various/cspan_bench.c | 2 +- misc/examples/printspan.c | 6 - src/cregex.c | 2 +- 23 files changed, 550 insertions(+), 641 deletions(-) delete mode 100644 include/stc/algo/csort.h create mode 100644 include/stc/algo/sort.h diff --git a/README.md b/README.md index 74c2238f..3b9cf90f 100644 --- a/README.md +++ b/README.md @@ -642,7 +642,7 @@ Major changes: - Algorithms: - [crange](docs/ccommon_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - [c_forfilter](docs/ccommon_api.md#c_forfilter) - ranges-like view filtering. - - [csort](include/stc/algo/csort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. + - [csort](include/stc/algo/sort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. - Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. - Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. - Some API changes in **cregex** and **cstr**. diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index e4c881dd..e37a1463 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -212,7 +212,7 @@ You may customize `i_tag` and the comparison function `i_cmp` or `i_less`. There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c). ```c #define i_val int -#include +#include int main() { int array[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}; diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index fc11fe66..91022a5c 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -1,7 +1,9 @@ # STC [cdeq](../include/stc/cdeq.h): Double Ended Queue ![Deque](pics/deque.jpg) -A **cdeq** is an indexed sequence container that allows fast insertion and deletion at both its beginning and its end. Note that this container is implemented similar to a vector, but has the same performance profile for both *push_back()* and *push_front()* as *cdeq_X_push_back()*. Iterators may be invalidated after push-operations. +A **cdeq** is an indexed sequence container that allows fast insertion and deletion at both +its beginning and its end, but has also fast random access to elements. The container is +implemented as a circular dynamic buffer. Iterators may be invalidated after push-operations. See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque) for a functional description. @@ -32,20 +34,20 @@ cdeq_X cdeq_X_clone(cdeq_X deq); void cdeq_X_clear(cdeq_X* self); void cdeq_X_copy(cdeq_X* self, const cdeq_X* other); -cdeq_X_iter cdeq_X_copy_range(cdeq_X* self, i_val* pos, const i_val* p1, const i_val* p2); bool cdeq_X_reserve(cdeq_X* self, intptr_t cap); void cdeq_X_shrink_to_fit(cdeq_X* self); -void cdeq_X_drop(cdeq_X* self); // destructor +void cdeq_X_drop(cdeq_X* self); // destructor bool cdeq_X_empty(const cdeq_X* self); intptr_t cdeq_X_size(const cdeq_X* self); intptr_t cdeq_X_capacity(const cdeq_X* self); const cdeq_X_value* cdeq_X_at(const cdeq_X* self, intptr_t idx); -const cdeq_X_value* cdeq_X_get(const cdeq_X* self, i_valraw raw); // return NULL if not found -cdeq_X_value* cdeq_X_get_mut(cdeq_X* self, i_valraw raw); // mutable get +cdeq_X_value* cdeq_X_at_mut(cdeq_X* self, intptr_t idx); +const cdeq_X_value* cdeq_X_get(const cdeq_X* self, i_valraw raw); // return NULL if not found +cdeq_X_value* cdeq_X_get_mut(cdeq_X* self, i_valraw raw); // mutable get cdeq_X_iter cdeq_X_find(const cdeq_X* self, i_valraw raw); -cdeq_X_iter cdeq_X_find_in(cdeq_X_iter i1, cdeq_X_iter i2, i_valraw raw); // return cvec_X_end() if not found +cdeq_X_iter cdeq_X_find_in(cdeq_X_iter i1, cdeq_X_iter i2, i_valraw raw); // return cvec_X_end() if not found cdeq_X_value* cdeq_X_front(const cdeq_X* self); cdeq_X_value* cdeq_X_back(const cdeq_X* self); @@ -55,38 +57,31 @@ cdeq_X_value* cdeq_X_emplace_front(cdeq_X* self, i_valraw raw); void cdeq_X_pop_front(cdeq_X* self); cdeq_X_value* cdeq_X_push_back(cdeq_X* self, i_val value); -cdeq_X_value* cdeq_X_push(cdeq_X* self, i_val value); // alias for push_back() +cdeq_X_value* cdeq_X_push(cdeq_X* self, i_val value); // alias for push_back() cdeq_X_value* cdeq_X_emplace_back(cdeq_X* self, i_valraw raw); -cdeq_X_value* cdeq_X_emplace(cdeq_X* self, i_valraw raw); // alias for emplace_back() +cdeq_X_value* cdeq_X_emplace(cdeq_X* self, i_valraw raw); // alias for emplace_back() void cdeq_X_pop_back(cdeq_X* self); -cdeq_X_iter cdeq_X_insert(cdeq_X* self, intptr_t idx, i_val value); // move value -cdeq_X_iter cdeq_X_insert_n(cdeq_X* self, intptr_t idx, const i_val[] arr, intptr_t n); // move arr values -cdeq_X_iter cdeq_X_insert_at(cdeq_X* self, cdeq_X_iter it, i_val value); // move value -cdeq_X_iter cdeq_X_insert_range(cdeq_X* self, i_val* pos, - const i_val* p1, const i_val* p2); - -cdeq_X_iter cdeq_X_emplace_n(cdeq_X* self, intptr_t idx, const i_valraw[] arr, intptr_t n); // clone values +cdeq_X_iter cdeq_X_insert_n(cdeq_X* self, intptr_t idx, const i_val[] arr, intptr_t n); // move values +cdeq_X_iter cdeq_X_insert(cdeq_X* self, intptr_t idx, i_val value); // move value +cdeq_X_iter cdeq_X_insert_at(cdeq_X* self, cdeq_X_iter it, i_val value); // move value +cdeq_X_iter cdeq_X_insert_uninit(cdeq_X* self, intptr_t idx, intptr_t n); // uninitialized data + // copy values: +cdeq_X_iter cdeq_X_emplace_n(cdeq_X* self, intptr_t idx, const i_valraw[] arr, intptr_t n); cdeq_X_iter cdeq_X_emplace_at(cdeq_X* self, cdeq_X_iter it, i_valraw raw); -cdeq_X_iter cdeq_X_emplace_range(cdeq_X* self, i_val* pos, - const i_valraw* p1, const i_valraw* p2); -cdeq_X_iter cdeq_X_erase_n(cdeq_X* self, intptr_t idx, intptr_t n); +void cdeq_X_erase_n(cdeq_X* self, intptr_t idx, intptr_t n); cdeq_X_iter cdeq_X_erase_at(cdeq_X* self, cdeq_X_iter it); cdeq_X_iter cdeq_X_erase_range(cdeq_X* self, cdeq_X_iter it1, cdeq_X_iter it2); -cdeq_X_iter cdeq_X_erase_range_p(cdeq_X* self, i_val* p1, i_val* p2); - -void cdeq_X_sort(cdeq_X* self); -void cdeq_X_sort_range(cdeq_X_iter i1, cdeq_X_iter i2, - int(*cmp)(const i_val*, const i_val*)); cdeq_X_iter cdeq_X_begin(const cdeq_X* self); cdeq_X_iter cdeq_X_end(const cdeq_X* self); void cdeq_X_next(cdeq_X_iter* it); -cdeq_X_iter cdeq_X_advance(cdeq_X_iter it, size_t n); +cdeq_X_iter cdeq_X_advance(cdeq_X_iter it, intptr_t n); -cdeq_X_raw cdeq_X_value_toraw(cdeq_X_value* pval); cdeq_X_value cdeq_X_value_clone(cdeq_X_value val); +cdeq_X_raw cdeq_X_value_toraw(const cdeq_X_value* pval); +void cdeq_X_value_drop(cdeq_X_value* pval); ``` ## Types diff --git a/docs/clist_api.md b/docs/clist_api.md index a1dbe105..44c3bb7c 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -84,19 +84,21 @@ void clist_X_sort(clist_X* self); void clist_X_sort_with(clist_X* self, int(*cmp)(const clist_X_value*, const clist_X_value*)); // Node API -clist_X_node* clist_X_get_node(clist_X_value* val); // get the enclosing node +clist_X_node* clist_X_get_node(clist_X_value* val); // get enclosing node clist_X_value* clist_X_push_back_node(clist_X* self, clist_X_node* node); clist_X_value* clist_X_insert_after_node(clist_X* self, clist_X_node* ref, clist_X_node* node); -clist_X_node* clist_X_unlink_after_node(clist_X* self, clist_X_node* ref); // return the unlinked node +clist_X_node* clist_X_unlink_after_node(clist_X* self, clist_X_node* ref); // return unlinked node +clist_X_node* clist_X_unlink_front_node(clist_X* self); // return unlinked node void clist_X_erase_after_node(clist_X* self, clist_X_node* node); clist_X_iter clist_X_begin(const clist_X* self); clist_X_iter clist_X_end(const clist_X* self); void clist_X_next(clist_X_iter* it); -clist_X_iter clist_X_advance(clist_X_iter it, size_t n); // return n elements ahead. +clist_X_iter clist_X_advance(clist_X_iter it, size_t n); // return n elements ahead. -clist_X_raw clist_X_value_toraw(clist_X_value* pval); clist_X_value clist_X_value_clone(clist_X_value val); +clist_X_raw clist_X_value_toraw(const clist_X_value* pval); +void clist_X_value_drop(clist_X_value* pval); ``` ## Types diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md index 9ea4b148..7d8d4e5c 100644 --- a/docs/cqueue_api.md +++ b/docs/cqueue_api.md @@ -26,27 +26,34 @@ See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue ```c cqueue_X cqueue_X_init(void); +cqueue_X cqueue_X_with_capacity(intptr_t size); cqueue_X cqueue_X_clone(cqueue_X q); void cqueue_X_clear(cqueue_X* self); void cqueue_X_copy(cqueue_X* self, const cqueue_X* other); +bool cqueue_X_reserve(cqueue_X* self, intptr_t cap); +void cqueue_X_shrink_to_fit(cqueue_X* self); void cqueue_X_drop(cqueue_X* self); // destructor intptr_t cqueue_X_size(const cqueue_X* self); +intptr_t cqueue_X_capacity(const cqueue_X* self); bool cqueue_X_empty(const cqueue_X* self); + cqueue_X_value* cqueue_X_front(const cqueue_X* self); cqueue_X_value* cqueue_X_back(const cqueue_X* self); cqueue_X_value* cqueue_X_push(cqueue_X* self, i_val value); cqueue_X_value* cqueue_X_emplace(cqueue_X* self, i_valraw raw); - void cqueue_X_pop(cqueue_X* self); cqueue_X_iter cqueue_X_begin(const cqueue_X* self); cqueue_X_iter cqueue_X_end(const cqueue_X* self); void cqueue_X_next(cqueue_X_iter* it); +cqueue_X_iter cqueue_X_advance(cqueue_X_iter it, intptr_t n); i_val cqueue_X_value_clone(i_val value); +cqueue_X_raw cqueue_X_value_toraw(const cqueue_X_value* pval); +void cqueue_X_value_drop(cqueue_X_value* pval); ``` ## Types diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 3e643cee..8c2048c0 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -83,7 +83,8 @@ void csmap_X_next(csmap_X_iter* iter); csmap_X_iter csmap_X_advance(csmap_X_iter it, intptr_t n); csmap_X_value csmap_X_value_clone(csmap_X_value val); -csmap_X_raw csmap_X_value_toraw(csmap_X_value* pval); +csmap_X_raw csmap_X_value_toraw(const csmap_X_value* pval); +void csmap_X_value_drop(csmap_X_value* pval); ``` ## Types diff --git a/docs/cstack_api.md b/docs/cstack_api.md index b1371f4e..c20de7d1 100644 --- a/docs/cstack_api.md +++ b/docs/cstack_api.md @@ -54,8 +54,9 @@ cstack_X_iter cstack_X_begin(const cstack_X* self); cstack_X_iter cstack_X_end(const cstack_X* self); void cstack_X_next(cstack_X_iter* it); -i_valraw cstack_X_value_toraw(cvec_X_value* pval); i_val cstack_X_value_clone(i_val value); +i_valraw cstack_X_value_toraw(const cvec_X_value* pval); +void cstack_X_value_drop(cvec_X_value* pval); ``` ## Types diff --git a/docs/cvec_api.md b/docs/cvec_api.md index 5879bc1f..194d48e1 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -37,10 +37,9 @@ cvec_X cvec_X_clone(cvec_X vec); void cvec_X_clear(cvec_X* self); void cvec_X_copy(cvec_X* self, const cvec_X* other); -cvec_X_iter cvec_X_copy_range(cvec_X* self, i_val* pos, const i_val* p1, const i_val* p2); +cvec_X_iter cvec_X_copy_n(cvec_X* self, intptr_t idx, const i_val* arr, intptr_t n); bool cvec_X_reserve(cvec_X* self, intptr_t cap); bool cvec_X_resize(cvec_X* self, intptr_t size, i_val null); -cvec_X_iter cvec_X_insert_uninit(cvec_X* self, i_val* pos, intptr_t n); // return pos iter void cvec_X_shrink_to_fit(cvec_X* self); void cvec_X_drop(cvec_X* self); // destructor @@ -50,8 +49,8 @@ intptr_t cvec_X_capacity(const cvec_X* self); const cvec_X_value* cvec_X_at(const cvec_X* self, intptr_t idx); const cvec_X_value* cvec_X_get(const cvec_X* self, i_valraw raw); // return NULL if not found -cvec_X_value* cvec_X_at_mut(cvec_X* self, intptr_t idx); -cvec_X_value* cvec_X_get_mut(cvec_X* self, i_valraw raw); // find mutable value, return value ptr +cvec_X_value* cvec_X_at_mut(cvec_X* self, intptr_t idx); // return mutable at idx +cvec_X_value* cvec_X_get_mut(cvec_X* self, i_valraw raw); // find mutable value cvec_X_iter cvec_X_find(const cvec_X* self, i_valraw raw); cvec_X_iter cvec_X_find_in(cvec_X_iter i1, cvec_X_iter i2, i_valraw raw); // return cvec_X_end() if not found // On sorted vectors: @@ -72,20 +71,16 @@ void cvec_X_pop(cvec_X* self); void cvec_X_pop_back(cvec_X* self); // alias for pop cvec_X_iter cvec_X_insert(cvec_X* self, intptr_t idx, i_val value); // move value -cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_val[] arr, intptr_t n); // move n values +cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_val arr[], intptr_t n); // move values cvec_X_iter cvec_X_insert_at(cvec_X* self, cvec_X_iter it, i_val value); // move value -cvec_X_iter cvec_X_insert_range(cvec_X* self, i_val* pos, - const i_val* p1, const i_val* p2); +cvec_X_iter cvec_X_insert_uninit(cvec_X* self, intptr_t idx, intptr_t n); // return iter at idx -cvec_X_iter cvec_X_emplace_n(cvec_X* self, intptr_t idx, const i_valraw[] arr, intptr_t n); // clone values +cvec_X_iter cvec_X_emplace_n(cvec_X* self, intptr_t idx, const i_valraw raw[], intptr_t n); cvec_X_iter cvec_X_emplace_at(cvec_X* self, cvec_X_iter it, i_valraw raw); -cvec_X_iter cvec_X_emplace_range(cvec_X* self, i_val* pos, - const i_valraw* p1, const i_valraw* p2); cvec_X_iter cvec_X_erase_n(cvec_X* self, intptr_t idx, intptr_t n); cvec_X_iter cvec_X_erase_at(cvec_X* self, cvec_X_iter it); cvec_X_iter cvec_X_erase_range(cvec_X* self, cvec_X_iter it1, cvec_X_iter it2); -cvec_X_iter cvec_X_erase_range_p(cvec_X* self, i_val* p1, i_val* p2); void cvec_X_sort(cvec_X* self); void cvec_X_sort_range(cvec_X_iter i1, cvec_X_iter i2, @@ -96,8 +91,9 @@ cvec_X_iter cvec_X_end(const cvec_X* self); void cvec_X_next(cvec_X_iter* iter); cvec_X_iter cvec_X_advance(cvec_X_iter it, size_t n); -cvec_X_raw cvec_X_value_toraw(cvec_X_value* pval); cvec_X_value cvec_X_value_clone(cvec_X_value val); +cvec_X_raw cvec_X_value_toraw(const cvec_X_value* pval); +cvec_X_raw cvec_X_value_drop(cvec_X_value* pval); ``` ## Types diff --git a/include/stc/algo/csort.h b/include/stc/algo/csort.h deleted file mode 100644 index e01a2893..00000000 --- a/include/stc/algo/csort.h +++ /dev/null @@ -1,89 +0,0 @@ -/* MIT License - * - * Copyright (c) 2023 Tyge Løvset - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -/* Generic Quicksort in C, performs as fast as c++ std::sort(). -template params: -#define i_val - value type [required] -#define i_less - less function. default: *x < *y -#define i_tag NAME - define csort_NAME(). default {i_val} - -// test: -#include -#define i_val int -#include - -int main() { - int arr[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21}; - - csort_int(arr, c_arraylen(arr)); - - for (int i = 0; i < c_arraylen(arr); i++) - printf(" %d", arr[i]); - puts(""); -} -*/ -#include "../ccommon.h" -#define _i_prefix csort_ -#include "../priv/template.h" - -typedef i_val _cx_value; - -static inline void _cx_memb(_insertion)(i_val arr[], intptr_t lo, intptr_t hi) { - for (intptr_t j = lo, i = lo + 1; i <= hi; j = i, ++i) { - i_val key = arr[i]; - while (j >= 0 && (i_less((&key), (&arr[j])))) { - arr[j + 1] = arr[j]; - --j; - } - arr[j + 1] = key; - } -} - -static inline void _cx_memb(_quicksort)(i_val arr[], intptr_t lo, intptr_t hi) { - intptr_t i = lo, j; - while (lo < hi) { - i_val pivot = arr[lo + (hi - lo)*7/16]; - j = hi; - - while (i <= j) { - while (i_less((&arr[i]), (&pivot))) ++i; - while (i_less((&pivot), (&arr[j]))) --j; - if (i <= j) { - c_swap(i_val, arr+i, arr+j); - ++i; --j; - } - } - if (j - lo > hi - i) { - c_swap(intptr_t, &lo, &i); - c_swap(intptr_t, &hi, &j); - } - - if (j - lo > 64) _cx_memb(_quicksort)(arr, lo, j); - else if (j > lo) _cx_memb(_insertion)(arr, lo, j); - lo = i; - } -} - -static inline void _cx_self(i_val arr[], intptr_t n) - { _cx_memb(_quicksort)(arr, 0, n - 1); } - -#include "../priv/template2.h" diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h new file mode 100644 index 00000000..20b7e1b3 --- /dev/null +++ b/include/stc/algo/sort.h @@ -0,0 +1,100 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* Generic Quicksort in C, performs as fast as c++ std::sort(). +template params: +#define i_val - value type [required] +#define i_less - less function. default: *x < *y +#define i_tag name - define namearray_qsort(). i_tag defaults {i_val} + +// test: +#include +#define i_val int +#include + +int main() { + int arr[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21}; + + intarray_qsort(arr, c_arraylen(arr)); + + for (int i = 0; i < c_arraylen(arr); i++) + printf(" %d", arr[i]); + puts(""); +} +*/ +#include "../ccommon.h" +#ifndef i_type + #define i_at(arr, idx) (&arr[idx]) + #ifndef i_tag + #define i_tag i_val + #endif + #define i_type c_PASTE(i_tag, array) + typedef i_val i_type; +#endif +#ifndef i_at + #define i_at(arr, idx) _cx_memb(_at_mut)(arr, idx) +#endif +#include "../priv/template.h" + + +static inline void _cx_memb(_insertsort_ij)(_cx_self* arr, intptr_t lo, intptr_t hi) { + for (intptr_t j = lo, i = lo + 1; i <= hi; j = i, ++i) { + i_val key = *i_at(arr, i); + while (j >= 0 && (i_less((&key), i_at(arr, j)))) { + *i_at(arr, j + 1) = *i_at(arr, j); + --j; + } + *i_at(arr, j + 1) = key; + } +} + +static inline void _cx_memb(_sort_ij)(_cx_self* arr, intptr_t lo, intptr_t hi) { + intptr_t i = lo, j; + while (lo < hi) { + i_val pivot = *i_at(arr, lo + (hi - lo)*7/16); + j = hi; + + while (i <= j) { + while (i_less(i_at(arr, i), (&pivot))) ++i; + while (i_less((&pivot), i_at(arr, j))) --j; + if (i <= j) { + c_swap(i_val, i_at(arr, i), i_at(arr, j)); + ++i; --j; + } + } + if (j - lo > hi - i) { + c_swap(intptr_t, &lo, &i); + c_swap(intptr_t, &hi, &j); + } + + if (j - lo > 64) _cx_memb(_sort_ij)(arr, lo, j); + else if (j > lo) _cx_memb(_insertsort_ij)(arr, lo, j); + lo = i; + } +} + +static inline void _cx_memb(_sort_n)(_cx_self* arr, intptr_t len) { + _cx_memb(_sort_ij)(arr, 0, len - 1); +} + +#include "../priv/template2.h" +#undef i_at diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index fd673696..07c72e2f 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -171,6 +171,16 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle, return NULL; } +STC_INLINE intptr_t cnextpow2(intptr_t n) { + n--; + n |= n >> 1, n |= n >> 2; + n |= n >> 4, n |= n >> 8; + n |= n >> 16; + #if INTPTR_SIZE == INT64_SIZE + n |= n >> 32; + #endif + return n + 1; +} /* Control block macros */ #define c_foreach(...) c_MACRO_OVERLOAD(c_foreach, __VA_ARGS__) diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index ff6e744f..80dd1dbe 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -20,166 +20,82 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "ccommon.h" - -#ifndef CDEQ_H_INCLUDED -#include "forward.h" -#include -#include - -#define _it2_ptr(it1, it2) (it1.ref && !it2.ref ? it2.end : it2.ref) -#define _it_ptr(it) (it.ref ? it.ref : it.end) -#endif // CDEQ_H_INCLUDED - -#ifndef _i_prefix #define _i_prefix cdeq_ +#define _pop _pop_front +#ifdef i_more + #include "cqueue.h" + #define i_more +#else + #define i_more + #include "cqueue.h" #endif -#include "priv/template.h" - -#ifndef i_is_forward -_cx_deftypes(_c_cdeq_types, _cx_self, i_key); -#endif -typedef i_keyraw _cx_raw; - -STC_API _cx_self _cx_memb(_init)(void); -STC_API _cx_self _cx_memb(_with_capacity)(const intptr_t n); -STC_API bool _cx_memb(_reserve)(_cx_self* self, const intptr_t n); -STC_API void _cx_memb(_clear)(_cx_self* self); -STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value); -STC_API void _cx_memb(_shrink_to_fit)(_cx_self *self); -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } -STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); } -#if !defined _i_queue -#if !defined i_no_emplace -STC_API _cx_iter _cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos, - const _cx_raw* p1, const _cx_raw* p2); -#endif // i_no_emplace - -#if !defined i_no_cmp || defined _i_has_eq -STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw); -#endif -#ifndef i_no_cmp -STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y); -#endif -STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value); -STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2); -STC_API _cx_iter _cx_memb(_insert_range)(_cx_self* self, _cx_value* pos, - const _cx_value* p1, const _cx_value* p2); -#endif // !_i_queue +#undef _pop -#if !defined i_no_emplace -STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push)(self, i_keyfrom(raw)); } -#endif +STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value); +STC_API _cx_iter _cx_memb(_insert_n)(_cx_self* self, intptr_t idx, const _cx_value* arr, intptr_t n); +STC_API _cx_iter _cx_memb(_emplace_n)(_cx_self* self, intptr_t idx, const _cx_raw* raw, intptr_t n); +STC_API _cx_iter _cx_memb(_insert_uninit)(_cx_self* self, intptr_t idx, intptr_t n); +STC_API void _cx_memb(_erase_n)(_cx_self* self, intptr_t idx, intptr_t n); -#if !defined i_no_clone -#if !defined _i_queue -STC_API _cx_iter _cx_memb(_copy_range)(_cx_self* self, _cx_value* pos, - const _cx_value* p1, const _cx_value* p2); +STC_INLINE const _cx_value* +_cx_memb(_at)(const _cx_self* self, intptr_t idx) + { return self->data + _cdeq_topos(self, idx); } -STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) { - if (self->data == other->data) return; - _cx_memb(_clear)(self); - _cx_memb(_copy_range)(self, self->data, - other->data, other->data + other->_len); - } -#endif // !_i_queue -STC_API _cx_self _cx_memb(_clone)(_cx_self cx); -STC_INLINE i_key _cx_memb(_value_clone)(i_key val) - { return i_keyclone(val); } -#endif // !i_no_clone -STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) { return self->_len; } -STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) { return self->_cap; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return !self->_len; } -STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* pval) { return i_keyto(pval); } -STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; } -STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) - { return self->data + self->_len - 1; } -STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) // == _pop() when _i_queue - { i_keydrop(self->data); ++self->data; --self->_len; } +STC_INLINE _cx_value* +_cx_memb(_at_mut)(_cx_self* self, intptr_t idx) + { return self->data + _cdeq_topos(self, idx); } -STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { - intptr_t n = self->_len; - return c_LITERAL(_cx_iter){n ? self->data : NULL, self->data + n}; +STC_INLINE _cx_value* +_cx_memb(_push_back)(_cx_self* self, _cx_value val) { + return _cx_memb(_push)(self, val); } -STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) - { return c_LITERAL(_cx_iter){NULL, self->data + self->_len}; } - -STC_INLINE void _cx_memb(_next)(_cx_iter* it) - { if (++it->ref == it->end) it->ref = NULL; } - -STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) - { if ((it.ref += n) >= it.end) it.ref = NULL; return it; } - -#if !defined _i_queue - -STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it) - { return (it.ref - self->data); } -STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) - { _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } - -STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, const intptr_t idx) { - assert(idx < self->_len); return self->data + idx; -} -STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, const intptr_t idx) { - assert(idx < self->_len); return self->data + idx; +STC_INLINE void +_cx_memb(_pop_back)(_cx_self* self) { + assert(!_cx_memb(_empty)(self)); + self->end = (self->end - 1) & self->capmask; + i_keydrop((self->data + self->end)); } -STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) { - return _cx_memb(_push)(self, value); -} -STC_INLINE _cx_iter -_cx_memb(_insert)(_cx_self* self, const intptr_t idx, i_key value) { - return _cx_memb(_insert_range)(self, self->data + idx, &value, &value + 1); -} -STC_INLINE _cx_iter -_cx_memb(_insert_n)(_cx_self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) { - return _cx_memb(_insert_range)(self, self->data + idx, arr, arr + n); -} STC_INLINE _cx_iter -_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) { - return _cx_memb(_insert_range)(self, _it_ptr(it), &value, &value + 1); +_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, const _cx_value val) { + intptr_t idx = _cdeq_toidx(self, it.pos); + return _cx_memb(_insert_n)(self, idx, &val, 1); } -STC_INLINE _cx_iter -_cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t n) { - return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n); -} STC_INLINE _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { - return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1); + _cx_memb(_erase_n)(self, _cdeq_toidx(self, it.pos), 1); + if (it.pos == self->end) it.ref = NULL; + return it; } + STC_INLINE _cx_iter -_cx_memb(_erase_range)(_cx_self* self, _cx_iter i1, _cx_iter i2) { - return _cx_memb(_erase_range_p)(self, i1.ref, _it2_ptr(i1, i2)); +_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { + intptr_t idx1 = _cdeq_toidx(self, it1.pos); + intptr_t idx2 = _cdeq_toidx(self, it2.pos); + _cx_memb(_erase_n)(self, idx1, idx2 - idx1); + if (it1.pos == self->end) it1.ref = NULL; + return it1; } #if !defined i_no_emplace STC_INLINE _cx_value* -_cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw) { - return _cx_memb(_push_front)(self, i_keyfrom(raw)); -} +_cx_memb(_emplace_front)(_cx_self* self, const _cx_raw raw) + { return _cx_memb(_push_front)(self, i_keyfrom(raw)); } -STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) { - return _cx_memb(_push)(self, i_keyfrom(raw)); -} +STC_INLINE _cx_value* +_cx_memb(_emplace_back)(_cx_self* self, const _cx_raw raw) + { return _cx_memb(_push)(self, i_keyfrom(raw)); } STC_INLINE _cx_iter -_cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw arr[], const intptr_t n) { - return _cx_memb(_emplace_range)(self, self->data + idx, arr, arr + n); -} -STC_INLINE _cx_iter -_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) { - return _cx_memb(_emplace_range)(self, _it_ptr(it), &raw, &raw + 1); -} -#endif // !i_no_emplace +_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, const _cx_raw raw) + { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); } +#endif -#if !defined i_no_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp +STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw); +STC_API bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other); STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_raw raw) { @@ -194,253 +110,88 @@ _cx_memb(_get)(const _cx_self* self, _cx_raw raw) { STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, _cx_raw raw) { return (_cx_value *) _cx_memb(_get)(self, raw); } - -STC_INLINE bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - if (self->_len != other->_len) return false; - for (intptr_t i = 0; i < self->_len; ++i) { - const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i); - if (!(i_eq((&_rx), (&_ry)))) return false; - } - return true; -} #endif -#ifndef i_no_cmp - -STC_INLINE void -_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) { - qsort(i1.ref, (size_t)(_it2_ptr(i1, i2) - i1.ref), sizeof *i1.ref, - (int(*)(const void*, const void*)) cmp); -} - -STC_INLINE void -_cx_memb(_sort)(_cx_self* self) { - _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp)); -} -#endif // !c_no_cmp -#endif // _i_queue /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) -#define _cdeq_nfront(self) ((self)->data - (self)->_base) - -STC_DEF _cx_self -_cx_memb(_init)(void) { - _cx_self cx = {NULL}; - return cx; -} - -STC_DEF void -_cx_memb(_clear)(_cx_self* self) { - if (self->_cap) { - for (_cx_value *p = self->data, *q = p + self->_len; p != q; ) - { --q; i_keydrop(q); } - self->_len = 0; - self->data = self->_base; - } -} - -STC_DEF void -_cx_memb(_shrink_to_fit)(_cx_self *self) { - if (self->_len != self->_cap) { - c_memmove(self->_base, self->data, self->_len*c_sizeof(i_key)); - _cx_value* d = (_cx_value*)i_realloc(self->_base, self->_len*c_sizeof(i_key)); - if (d) { - self->_base = d; - self->_cap = self->_len; - } - self->data = self->_base; - } -} - -STC_DEF void -_cx_memb(_drop)(_cx_self* self) { - if (self->_base) { - _cx_memb(_clear)(self); - i_free(self->_base); - } -} - -static intptr_t -_cx_memb(_realloc_)(_cx_self* self, const intptr_t n) { - const intptr_t cap = (intptr_t)((float)self->_len*1.7f) + n + 7; - const intptr_t nfront = _cdeq_nfront(self); - _cx_value* d = (_cx_value*)i_realloc(self->_base, cap*c_sizeof(i_key)); - if (!d) - return 0; - self->_cap = cap; - self->_base = d; - self->data = d + nfront; - return cap; -} - -static bool -_cx_memb(_expand_right_half_)(_cx_self* self, const intptr_t idx, const intptr_t n) { - const intptr_t sz = self->_len, cap = self->_cap; - const intptr_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront; - if (nback >= n || (intptr_t)((float)sz*1.3f) + n > cap) { - if (!_cx_memb(_realloc_)(self, n)) - return false; - c_memmove(self->data + idx + n, self->data + idx, (sz - idx)*c_sizeof(i_key)); - } else { -#if !defined _i_queue - const intptr_t unused = cap - (sz + n); - const intptr_t pos = (nfront*2 < unused) ? nfront : unused/2; -#else - const intptr_t pos = 0; -#endif - c_memmove(self->_base + pos, self->data, idx*c_sizeof(i_key)); - c_memmove(self->data + pos + idx + n, self->data + idx, (sz - idx)*c_sizeof(i_key)); - self->data = self->_base + pos; - } - return true; -} - -STC_DEF _cx_self -_cx_memb(_with_capacity)(const intptr_t n) { - _cx_self cx = _cx_memb(_init)(); - _cx_memb(_expand_right_half_)(&cx, 0, n); - return cx; -} - -STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const intptr_t n) { - const intptr_t sz = self->_len; - return n <= sz || _cx_memb(_expand_right_half_)(self, sz, n - sz); -} STC_DEF _cx_value* -_cx_memb(_push)(_cx_self* self, i_key value) { - if (_cdeq_nfront(self) + self->_len == self->_cap) - _cx_memb(_expand_right_half_)(self, self->_len, 1); - _cx_value *v = self->data + self->_len++; +_cx_memb(_push_front)(_cx_self* self, i_key value) { + intptr_t start = (self->start - 1) & self->capmask; + if (start == self->end) { // full + _cx_memb(_reserve)(self, self->capmask + 3); // => 2x expand + start = (self->start - 1) & self->capmask; + } + _cx_value *v = self->data + start; + self->start = start; *v = value; return v; } -#if !defined i_no_clone -STC_DEF _cx_self -_cx_memb(_clone)(_cx_self cx) { - _cx_self out = _cx_memb(_with_capacity)(cx._len); - if (out._base) - for (intptr_t i = 0; i < cx._len; ++i) - out.data[i] = i_keyclone(cx.data[i]); - return out; -} -#endif - -#if !defined _i_queue - -static void -_cx_memb(_expand_left_half_)(_cx_self* self, const intptr_t idx, const intptr_t n) { - intptr_t cap = self->_cap; - const intptr_t sz = self->_len; - const intptr_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront; - if (nfront >= n) { - self->data = (_cx_value *)c_memmove(self->data - n, self->data, idx*c_sizeof(i_key)); - } else { - if ((intptr_t)((float)sz*1.3f) + n > cap) - cap = _cx_memb(_realloc_)(self, n); - const intptr_t unused = cap - (sz + n); - const intptr_t pos = (nback*2 < unused) ? unused - nback : unused/2; - c_memmove(self->_base + pos + idx + n, self->data + idx, (sz - idx)*c_sizeof(i_key)); - self->data = (_cx_value *)c_memmove(self->_base + pos, self->data, idx*c_sizeof(i_key)); - } -} - -static _cx_iter -_cx_memb(_insert_uninit)(_cx_self* self, _cx_value* pos, const intptr_t n) { - if (n) { - if (!pos) pos = self->data + self->_len; - const intptr_t idx = (pos - self->data); - if (idx*2 < self->_len) - _cx_memb(_expand_left_half_)(self, idx, n); - else - _cx_memb(_expand_right_half_)(self, idx, n); - self->_len += n; - pos = self->data + idx; - } - return c_LITERAL(_cx_iter){pos, self->data + self->_len}; -} - -STC_DEF _cx_value* -_cx_memb(_push_front)(_cx_self* self, i_key value) { - if (self->data == self->_base) - _cx_memb(_expand_left_half_)(self, 0, 1); - else - --self->data; - ++self->_len; - *self->data = value; - return self->data; +STC_DEF void +_cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t n) { + const intptr_t len = _cx_memb(_size)(self); + for (intptr_t i = idx + n - 1; i >= idx; --i) + i_keydrop(_cx_memb(_at_mut)(self, i)); + for (intptr_t i = idx, j = i + n; j < len; ++i, ++j) + *_cx_memb(_at_mut)(self, i) = *_cx_memb(_at)(self, j); + self->end = (self->end - n) & self->capmask; } STC_DEF _cx_iter -_cx_memb(_insert_range)(_cx_self* self, _cx_value* pos, - const _cx_value* p1, const _cx_value* p2) { - _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1)); - if (it.ref) - c_memcpy(it.ref, p1, (p2 - p1)*c_sizeof *p1); +_cx_memb(_insert_uninit)(_cx_self* self, const intptr_t idx, const intptr_t n) { + const intptr_t len = _cx_memb(_size)(self); + _cx_iter it = {._s=self}; + if (len + n > self->capmask) + if (!_cx_memb(_reserve)(self, len + n)) + return it; + for (intptr_t j = len - 1, i = j + n; j >= idx; --j, --i) + *_cx_memb(_at_mut)(self, i) = *_cx_memb(_at)(self, j); + self->end = (self->end + n) & self->capmask; + it.pos = _cdeq_topos(self, idx); + it.ref = self->data + it.pos; return it; } STC_DEF _cx_iter -_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) { - assert(p1 && p2); - intptr_t len = p2 - p1; - _cx_value* p = p1, *end = self->data + self->_len; - for (; p != p2; ++p) - { i_keydrop(p); } - c_memmove(p1, p2, (end - p2)*c_sizeof *p1); - self->_len -= len; - return c_LITERAL(_cx_iter){p2 == end ? NULL : p1, end - len}; -} - -#if !defined i_no_clone -STC_DEF _cx_iter -_cx_memb(_copy_range)(_cx_self* self, _cx_value* pos, - const _cx_value* p1, const _cx_value* p2) { - _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1)); - if (it.ref) - for (_cx_value* p = it.ref; p1 != p2; ++p1) - *p++ = i_keyclone((*p1)); +_cx_memb(_insert_n)(_cx_self* self, const intptr_t idx, const _cx_value* arr, const intptr_t n) { + _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); + for (intptr_t i = idx, j = 0; j < n; ++i, ++j) + *_cx_memb(_at_mut)(self, i) = arr[j]; return it; } -#endif // !i_no_clone -#if !defined i_no_emplace STC_DEF _cx_iter -_cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos, - const _cx_raw* p1, const _cx_raw* p2) { - _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1)); - if (it.ref) - for (_cx_value* p = it.ref; p1 != p2; ++p1) - *p++ = i_keyfrom((*p1)); +_cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw* raw, const intptr_t n) { + _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); + for (intptr_t i = idx, j = 0; j < n; ++i, ++j) + *_cx_memb(_at_mut)(self, i) = i_keyfrom(raw[j]); return it; } -#endif // !i_no_emplace -#if !defined i_no_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp STC_DEF _cx_iter _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { - const _cx_value* p2 = _it2_ptr(i1, i2); - for (; i1.ref != p2; ++i1.ref) { + for (; i1.ref; _cx_memb(_next)(&i1)) { const _cx_raw r = i_keyto(i1.ref); if (i_eq((&raw), (&r))) - return i1; + break; } - i2.ref = NULL; - return i2; + return i1; } -#endif -#ifndef i_no_cmp -STC_DEF int -_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { - const _cx_raw rx = i_keyto(x); - const _cx_raw ry = i_keyto(y); - return i_cmp((&rx), (&ry)); + +STC_DEF bool +_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { + if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; + for (_cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other); + i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) + { + const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); + if (!(i_eq((&_rx), (&_ry)))) return false; + } + return true; } -#endif // !c_no_cmp -#endif // !_i_queue +#endif #endif // IMPLEMENTATION #define CDEQ_H_INCLUDED #include "priv/template2.h" diff --git a/include/stc/clist.h b/include/stc/clist.h index 65a1ac87..128e848d 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -109,8 +109,9 @@ STC_API _cx_value* _cx_memb(_push_back_node)(_cx_self* self, _cx_node* node STC_API _cx_value* _cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node); STC_API _cx_node* _cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref); STC_API void _cx_memb(_erase_after_node)(_cx_self* self, _cx_node* ref); -STC_INLINE _cx_node* _cx_memb(_get_node)(_cx_value* vp) { return _clist_tonode(vp); } - +STC_INLINE _cx_node* _cx_memb(_get_node)(_cx_value* pval) { return _clist_tonode(pval); } +STC_INLINE _cx_node* _cx_memb(_unlink_front_node)(_cx_self* self) + { return _cx_memb(_unlink_after_node)(self, self->last); } #if !defined i_no_clone STC_API _cx_self _cx_memb(_clone)(_cx_self cx); STC_INLINE i_key _cx_memb(_value_clone)(i_key val) { return i_keyclone(val); } @@ -144,10 +145,10 @@ STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, i_key value) { return _cx_memb(_push_back)(self, value); } STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) { assert(!_cx_memb(_empty)(self)); _cx_memb(_erase_after_node)(self, self->last); } -STC_INLINE _cx_node* _cx_memb(_unlink_node_front)(_cx_self* self) - { return _cx_memb(_unlink_after_node)(self, self->last); } STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return &self->last->next->value; } STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) { return &self->last->value; } +STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* pval) { return i_keyto(pval); } +STC_INLINE void _cx_memb(_value_drop)(_cx_value* pval) { i_keydrop(pval); } STC_INLINE intptr_t _cx_memb(_count)(const _cx_self* self) { diff --git a/include/stc/cmap.h b/include/stc/cmap.h index ec3238f6..4ba6156b 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -276,13 +276,6 @@ STC_INLINE intptr_t fastrange_1(uint64_t x, uint64_t n) STC_INLINE intptr_t fastrange_2(uint64_t x, uint64_t n) { return (intptr_t)(x & (n - 1)); } // n power of 2. -STC_INLINE uint64_t next_power_of_2(uint64_t n) { - n--; - n |= n >> 1, n |= n >> 2; - n |= n >> 4, n |= n >> 8; - n |= n >> 16, n |= n >> 32; - return n + 1; -} #endif // CMAP_H_INCLUDED STC_DEF _cx_iter _cx_memb(_begin)(const _cx_self* self) { @@ -422,7 +415,7 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { return true; intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) | 1; #if i_expandby == 2 - _newbucks = (intptr_t)next_power_of_2((uint64_t)_newbucks); + _newbucks = cnextpow2(_newbucks); #endif _cx_self m = { (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 254bc834..09a747e5 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -20,44 +20,198 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -// STC queue -/* -#include -#include - -#define i_key int -#include - -int main() { - int n = 10000000; - crand_t rng = crand_init(1234); - crand_unif_t dist = crand_unif_init(0, n); - - c_auto (cqueue_int, Q) - { - // Push ten million random numbers onto the queue. - for (int i=0; i0; --i) { - int r = crand_unif(&rng, &dist); - if (r & 1) - ++n, cqueue_int_push(&Q, r); - else - --n, cqueue_int_pop(&Q); - } - printf("after: size, capacity: %d, %d\n", n, cqueue_int_size(&Q), cqueue_int_capacity(&Q)); +#include "ccommon.h" + +#ifndef CQUEUE_H_INCLUDED +#include "forward.h" +#include +#include +#endif // CQUEUE_H_INCLUDED + +#ifndef _i_prefix +#define _i_prefix cqueue_ +#endif +#include "priv/template.h" + +#ifndef i_is_forward +_cx_deftypes(_c_cdeq_types, _cx_self, i_key); +#endif +typedef i_keyraw _cx_raw; + +STC_API _cx_self _cx_memb(_with_capacity)(const intptr_t n); +STC_API bool _cx_memb(_reserve)(_cx_self* self, const intptr_t n); +STC_API void _cx_memb(_clear)(_cx_self* self); +STC_API void _cx_memb(_drop)(_cx_self* self); +STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value); // push_back +STC_API void _cx_memb(_shrink_to_fit)(_cx_self *self); +STC_API _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t n); + +#define _cdeq_toidx(self, pos) (((pos) - (self)->start) & (self)->capmask) +#define _cdeq_topos(self, idx) (((self)->start + (idx)) & (self)->capmask) + +STC_INLINE _cx_self _cx_memb(_init)(void) + { _cx_self cx = {0}; return cx; } +STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } +STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } +STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); } + +#if !defined i_no_emplace +STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) + { return _cx_memb(_push)(self, i_keyfrom(raw)); } +#endif + +#if !defined i_no_clone +STC_API _cx_self _cx_memb(_clone)(_cx_self cx); +STC_INLINE i_key _cx_memb(_value_clone)(i_key val) + { return i_keyclone(val); } +#endif // !i_no_clone +STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) + { return _cdeq_toidx(self, self->end); } +STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) + { return self->capmask; } +STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) + { return self->start == self->end; } +STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* pval) + { return i_keyto(pval); } + +STC_INLINE _cx_value* +_cx_memb(_front)(const _cx_self* self) + { return self->data + self->start; } + +STC_INLINE _cx_value* +_cx_memb(_back)(const _cx_self* self) + { return self->data + ((self->end - 1) & self->capmask); } + +STC_INLINE void +_cx_memb(_pop)(_cx_self* self) { // pop_front + c_ASSERT(!_cx_memb(_empty)(self)); + i_keydrop((self->data + self->start)); + self->start = (self->start + 1) & self->capmask; +} + +STC_INLINE void _cx_memb(_copy)(_cx_self* self, const _cx_self* other) { + if (self->data == other->data) return; + _cx_memb(_drop)(self); + *self = _cx_memb(_clone)(*other); +} + +STC_INLINE _cx_iter +_cx_memb(_begin)(const _cx_self* self) { + return c_LITERAL(_cx_iter){ + _cx_memb(_empty)(self) ? NULL : self->data + self->start, + self->start, self + }; +} + +STC_INLINE _cx_iter +_cx_memb(_end)(const _cx_self* self) + { return c_LITERAL(_cx_iter){NULL, self->end, self}; } + +STC_INLINE void +_cx_memb(_next)(_cx_iter* it) { + if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; } + else { it->ref -= it->pos; it->pos = 0; } + if (it->pos == it->_s->end) it->ref = NULL; +} + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +STC_DEF _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t n) { + intptr_t len = _cx_memb(_size)(it._s); + intptr_t pos = it.pos, idx = _cdeq_toidx(it._s, pos); + it.pos = (pos + n) & it._s->capmask; + it.ref += it.pos - pos; + if (!c_LTu(idx + n, len)) it.ref = NULL; + return it; +} + +STC_DEF void +_cx_memb(_clear)(_cx_self* self) { + c_foreach (i, _cx_self, *self) + { i_keydrop(i.ref); } + self->start = 0, self->end = 0; +} + +STC_DEF void +_cx_memb(_drop)(_cx_self* self) { + _cx_memb(_clear)(self); + i_free(self->data); +} + +STC_DEF _cx_self +_cx_memb(_with_capacity)(const intptr_t n) { + _cx_self cx = {0}; + _cx_memb(_reserve)(&cx, n); + return cx; +} + +STC_DEF bool +_cx_memb(_reserve)(_cx_self* self, const intptr_t n) { + if (n <= self->capmask) + return true; + intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1); + _cx_value* data = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data); + if (!data) + return false; + intptr_t head = oldcap - self->start; + if (self->start < self->end || self->start == 0) + ; + else if (head < self->end) { + self->start = newcap - head; + c_memmove(data + self->start, data + oldcap - head, head*c_sizeof *data); + } else { + c_memmove(data + oldcap, data, self->end*c_sizeof *data); + self->end += oldcap; } + self->capmask = newcap - 1; + self->data = data; + return true; } -*/ -#define _i_prefix cqueue_ -#define _i_queue -#define _pop_front _pop +STC_DEF _cx_value* +_cx_memb(_push)(_cx_self* self, i_key value) { // push_back + intptr_t end = (self->end + 1) & self->capmask; + if (end == self->start) { // full + _cx_memb(_reserve)(self, self->capmask + 3); // => 2x expand + end = (self->end + 1) & self->capmask; + } + _cx_value *v = self->data + self->end; + self->end = end; + *v = value; + return v; +} + +STC_DEF void +_cx_memb(_shrink_to_fit)(_cx_self *self) { + intptr_t sz = _cx_memb(_size)(self), j = 0; + if (sz > self->capmask/2) + return; + _cx_self out = _cx_memb(_with_capacity)(sz); + if (!out.data) + return; + c_foreach (i, _cx_self, *self) + out.data[j++] = *i.ref; + out.end = sz; + i_free(self->data); + *self = out; +} -#include "cdeq.h" +#if !defined i_no_clone +STC_DEF _cx_self +_cx_memb(_clone)(_cx_self cx) { + intptr_t sz = _cx_memb(_size)(&cx), j = 0; + _cx_self out = _cx_memb(_with_capacity)(sz); + if (out.data) + c_foreach (i, _cx_self, cx) + out.data[j++] = i_keyclone((*i.ref)); + out.end = sz; + return out; +} -#undef _pop_front -#undef _i_queue +#endif // i_no_clone +#endif // IMPLEMENTATION +#include "priv/template2.h" +#define CQUEUE_H_INCLUDED diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 3cbd90b7..a7eb1a05 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -81,10 +81,8 @@ STC_API void _cx_memb(_clear)(_cx_self* self); STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t cap); STC_API bool _cx_memb(_resize)(_cx_self* self, intptr_t size, i_key null); STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value); -STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2); -STC_API _cx_iter _cx_memb(_insert_range)(_cx_self* self, _cx_value* pos, - const _cx_value* p1, const _cx_value* p2); -STC_API _cx_iter _cx_memb(_insert_uninit)(_cx_self* self, _cx_value* pos, const intptr_t n); +STC_API _cx_iter _cx_memb(_erase_n)(_cx_self* self, intptr_t idx, intptr_t n); +STC_API _cx_iter _cx_memb(_insert_uninit)(_cx_self* self, intptr_t idx, intptr_t n); #if !defined i_no_cmp || defined _i_has_eq STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw); #endif @@ -95,26 +93,23 @@ STC_API _cx_iter _cx_memb(_binary_search_in)(_cx_iter it1, _cx_iter it2, STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); } #if !defined i_no_emplace -STC_API _cx_iter _cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos, - const _cx_raw* p1, const _cx_raw* p2); -STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push)(self, i_keyfrom(raw)); } -STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push)(self, i_keyfrom(raw)); } -STC_INLINE _cx_iter -_cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw arr[], const intptr_t n) { - return _cx_memb(_emplace_range)(self, self->data + idx, arr, arr + n); +STC_API _cx_iter +_cx_memb(_emplace_n)(_cx_self* self, intptr_t idx, const _cx_raw raw[], intptr_t n); + +STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) { + return _cx_memb(_push)(self, i_keyfrom(raw)); } -STC_INLINE _cx_iter -_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) { - return _cx_memb(_emplace_range)(self, _it_ptr(it), &raw, &raw + 1); +STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) { + return _cx_memb(_push)(self, i_keyfrom(raw)); +} +STC_INLINE _cx_iter _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) { + return _cx_memb(_emplace_n)(self, _it_ptr(it) - self->data, &raw, 1); } #endif // !i_no_emplace #if !defined i_no_clone STC_API _cx_self _cx_memb(_clone)(_cx_self cx); -STC_API _cx_iter _cx_memb(_copy_range)(_cx_self* self, _cx_value* pos, - const _cx_value* p1, const _cx_value* p2); +STC_API _cx_iter _cx_memb(_copy_n)(_cx_self* self, intptr_t idx, const _cx_value arr[], intptr_t n); STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) @@ -124,8 +119,7 @@ STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val) STC_INLINE void _cx_memb(_copy)(_cx_self* self, const _cx_self* other) { if (self->data == other->data) return; _cx_memb(_clear)(self); - _cx_memb(_copy_range)(self, self->data, other->data, - other->data + other->_len); + _cx_memb(_copy_n)(self, 0, other->data, other->_len); } #endif // !i_no_clone @@ -161,31 +155,29 @@ _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, _cx_memb(_size)(self)); } - -STC_INLINE _cx_iter -_cx_memb(_insert)(_cx_self* self, const intptr_t idx, i_key value) { - return _cx_memb(_insert_range)(self, self->data + idx, &value, &value + 1); -} STC_INLINE _cx_iter _cx_memb(_insert_n)(_cx_self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) { - return _cx_memb(_insert_range)(self, self->data + idx, arr, arr + n); + _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); + if (it.ref) + c_memcpy(it.ref, arr, n*c_sizeof *arr); + return it; } STC_INLINE _cx_iter -_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) { - return _cx_memb(_insert_range)(self, _it_ptr(it), &value, &value + 1); +_cx_memb(_insert)(_cx_self* self, const intptr_t idx, const i_key value) { + return _cx_memb(_insert_n)(self, idx, &value, 1); } - STC_INLINE _cx_iter -_cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t n) { - return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n); +_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, const i_key value) { + return _cx_memb(_insert_n)(self, _it_ptr(it) - self->data, &value, 1); } + STC_INLINE _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { - return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1); + return _cx_memb(_erase_n)(self, it.ref - self->data, 1); } STC_INLINE _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter i1, _cx_iter i2) { - return _cx_memb(_erase_range_p)(self, i1.ref, _it2_ptr(i1, i2)); + return _cx_memb(_erase_n)(self, i1.ref - self->data, _it2_ptr(i1, i2) - i1.ref); } STC_INLINE const _cx_value* @@ -329,73 +321,58 @@ _cx_memb(_push)(_cx_self* self, i_key value) { } STC_DEF _cx_iter -_cx_memb(_insert_uninit)(_cx_self* self, _cx_value* pos, const intptr_t n) { - if (n) { - if (!pos) pos = self->data + self->_len; - const intptr_t idx = (pos - self->data); - if (self->_len + n > self->_cap) { - if (!_cx_memb(_reserve)(self, self->_len*3/2 + n)) - return _cx_memb(_end)(self); - pos = self->data + idx; - } - c_memmove(pos + n, pos, (self->_len - idx)*c_sizeof *pos); - self->_len += n; - } +_cx_memb(_insert_uninit)(_cx_self* self, const intptr_t idx, const intptr_t n) { + if (self->_len + n > self->_cap) + if (!_cx_memb(_reserve)(self, self->_len*3/2 + n)) + return _cx_memb(_end)(self); + + _cx_value* pos = self->data + idx; + c_memmove(pos + n, pos, (self->_len - idx)*c_sizeof *pos); + self->_len += n; return c_LITERAL(_cx_iter){pos, self->data + self->_len}; } STC_DEF _cx_iter -_cx_memb(_insert_range)(_cx_self* self, _cx_value* pos, - const _cx_value* p1, const _cx_value* p2) { - _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1)); - if (it.ref) - c_memcpy(it.ref, p1, (p2 - p1)*c_sizeof *p1); - return it; -} - -STC_DEF _cx_iter -_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) { - intptr_t len = (p2 - p1); - _cx_value* p = p1, *end = self->data + self->_len; - for (; p != p2; ++p) +_cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t len) { + _cx_value* d = self->data + idx, *p = d, *end = self->data + self->_len; + for (intptr_t i = 0; i < len; ++i, ++p) { i_keydrop(p); } - c_memmove(p1, p2, (end - p2)*c_sizeof *p1); + c_memmove(d, p, (end - p)*c_sizeof *d); self->_len -= len; - return c_LITERAL(_cx_iter){p2 == end ? NULL : p1, end - len}; + return c_LITERAL(_cx_iter){p == end ? NULL : d, end - len}; } #if !defined i_no_clone STC_DEF _cx_self _cx_memb(_clone)(_cx_self cx) { _cx_self out = _cx_memb(_init)(); - _cx_memb(_copy_range)(&out, out.data, cx.data, cx.data + cx._len); + _cx_memb(_copy_n)(&out, 0, cx.data, cx._len); return out; } STC_DEF _cx_iter -_cx_memb(_copy_range)(_cx_self* self, _cx_value* pos, - const _cx_value* p1, const _cx_value* p2) { - _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1)); +_cx_memb(_copy_n)(_cx_self* self, const intptr_t idx, + const _cx_value arr[], const intptr_t n) { + _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); if (it.ref) - for (_cx_value* p = it.ref; p1 != p2; ++p1) - *p++ = i_keyclone((*p1)); + for (_cx_value* p = it.ref, *q = p + n; p != q; ++arr) + *p++ = i_keyclone((*arr)); return it; } #endif // !i_no_clone #if !defined i_no_emplace STC_DEF _cx_iter -_cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos, - const _cx_raw* p1, const _cx_raw* p2) { - _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1)); +_cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw raw[], intptr_t n) { + _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); if (it.ref) - for (_cx_value* p = it.ref; p1 != p2; ++p1) - *p++ = i_keyfrom((*p1)); + for (_cx_value* p = it.ref; n--; ++raw, ++p) + *p = i_keyfrom((*raw)); return it; } #endif // !i_no_emplace - #if !defined i_no_cmp || defined _i_has_eq + STC_DEF _cx_iter _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { const _cx_value* p2 = _it2_ptr(i1, i2); diff --git a/include/stc/forward.h b/include/stc/forward.h index b534e48b..9eafb857 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -81,12 +81,17 @@ typedef union { #define _c_cdeq_types(SELF, VAL) \ typedef VAL SELF##_value; \ - typedef struct { SELF##_value *ref, *end; } SELF##_iter; \ \ typedef struct SELF { \ - SELF##_value *_base, *data; \ - intptr_t _len, _cap; \ - } SELF + SELF##_value *data; \ + intptr_t start, end, capmask; \ + } SELF; \ +\ + typedef struct { \ + SELF##_value *ref; \ + intptr_t pos; \ + const SELF* _s; \ + } SELF##_iter #define _c_clist_types(SELF, VAL) \ typedef VAL SELF##_value; \ diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 2605a434..f70281c7 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -20,9 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifdef _i_template - #error template.h already included -#endif +#ifndef _i_template #define _i_template #ifndef STC_TEMPLATE_H_INCLUDED @@ -107,6 +105,9 @@ #ifdef i_eq #define _i_has_eq #endif +#if defined i_cmp || defined i_less + #define _i_has_cmp +#endif #if defined i_key_str #define i_keyclass cstr @@ -288,3 +289,4 @@ #ifndef _i_has_from #define i_no_emplace #endif +#endif diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 2e8a6c8d..66ed7739 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -20,6 +20,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifdef i_more +#undef i_more +#else #undef i_type #undef i_tag #undef i_imp @@ -74,4 +77,6 @@ #undef _i_expandby #undef _i_has_from #undef _i_has_eq +#undef _i_has_cmp #undef _i_template +#endif \ No newline at end of file diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c index d5d7fa7c..4d1149fc 100644 --- a/misc/benchmarks/various/csort_bench.c +++ b/misc/benchmarks/various/csort_bench.c @@ -5,8 +5,12 @@ #ifdef __cplusplus #include #endif +#define NDEBUG +#define i_type Ints #define i_val int -#include +#define i_more +#include +#include #define ROTL(d,bits) ((d<<(bits)) | (d>>(8*sizeof(d)-(bits)))) uint64_t romutrio(uint64_t s[3]) { @@ -21,14 +25,14 @@ static int cmp_int(const void* a, const void* b) { return c_default_cmp((const int*)a, (const int*)b); } -void testsort(int *a, int size, const char *desc) { +void testsort(Ints *a, int size, const char *desc) { clock_t t = clock(); #ifdef __cplusplus - printf("std::sort: "); std::sort(a, a + size); + printf("std::sort: "); std::sort(a->data, a->data + size); #elif defined QSORT - printf("qsort: "); qsort(a, size, sizeof *a, cmp_int); + printf("qsort: "); qsort(a->data, size, sizeof *a->data, cmp_int); #else - printf("stc_sort: "); csort_int(a, size); + printf("stc_qsort: "); Ints_sort_n(a, size); #endif t = clock() - t; @@ -41,27 +45,27 @@ int main(int argc, char *argv[]) { size_t i, size = argc > 1 ? strtoull(argv[1], NULL, 0) : 10000000; uint64_t s[3] = {123456789, 3456789123, 789123456}; - int32_t *a = (int32_t*)malloc(sizeof(*a) * size); - if (!a) return -1; + Ints a = Ints_with_capacity(size); for (i = 0; i < size; i++) - a[i] = romutrio(s) & (1U << 30) - 1; - testsort(a, size, "random"); + *Ints_push(&a, romutrio(s) & (1U << 30) - 1); + testsort(&a, size, "random"); for (i = 0; i < 20; i++) - printf(" %d", (int)a[i]); + printf(" %d", (int)*Ints_at(&a, i)); puts(""); for (i = 0; i < size; i++) - a[i] = i; - testsort(a, size, "sorted"); + *Ints_at_mut(&a, i) = i; + testsort(&a, size, "sorted"); for (i = 0; i < size; i++) - a[i] = size - i; - testsort(a, size, "reverse sorted"); + *Ints_at_mut(&a, i) = size - i; + testsort(&a, size, "reverse sorted"); for (i = 0; i < size; i++) - a[i] = 126735; - testsort(a, size, "constant"); + *Ints_at_mut(&a, i) = 126735; + testsort(&a, size, "constant"); for (i = 0; i < size; i++) - a[i] = i + 1; - a[size - 1] = 0; - testsort(a, size, "rotated"); - free(a); + *Ints_at_mut(&a, i) = i + 1; + *Ints_at_mut(&a, size - 1) = 0; + testsort(&a, size, "rotated"); + + Ints_drop(&a); } diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c index 589df13a..02ae3237 100644 --- a/misc/benchmarks/various/cspan_bench.c +++ b/misc/benchmarks/various/cspan_bench.c @@ -1,4 +1,4 @@ -#define STC_NDEBUG +#define NDEBUG #include #include #include diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c index 7459ac77..60a2d934 100644 --- a/misc/examples/printspan.c +++ b/misc/examples/printspan.c @@ -6,8 +6,6 @@ #include #define i_val int #include -#define i_val int -#include #define i_val_str #include #include @@ -40,9 +38,6 @@ int main() cstack_int stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7}); printMe( (intspan)cspan_from(&stk) ); - cdeq_int deq = c_make(cdeq_int, {1, 2, 3, 4, 5, 6, 7, 8}); - printMe( (intspan)cspan_from(&deq) ); - csset_str set = c_make(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); printf("%d:", (int)csset_str_size(&set)); c_foreach (e, csset_str, set) @@ -52,6 +47,5 @@ int main() // cleanup cvec_int_drop(&vec); cstack_int_drop(&stk); - cdeq_int_drop(&deq); csset_str_drop(&set); } diff --git a/src/cregex.c b/src/cregex.c index a1d43944..981a256a 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -1220,7 +1220,7 @@ _build_subst(const char* replace, int nmatch, const csview match[], if (g < (int)nmatch) { csview m = mfun && mfun(g, match[g], &mstr) ? cstr_sv(&mstr) : match[g]; if (len + m.size > cap) - dst = cstr_reserve(subst, cap = cap*3/2 + m.size); + dst = cstr_reserve(subst, cap += cap*3/2 + m.size); for (int i = 0; i < (int)m.size; ++i) dst[len++] = m.str[i]; } -- cgit v1.2.3 From c54da07eb171455ad182d61a1fb5c4e4520aebbb Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 18 May 2023 15:39:48 +0200 Subject: Fixing find_in() in cdeq, and add support c_eraseremove_if() for cqueue and cdeq. --- include/stc/algo/filter.h | 2 +- include/stc/cdeq.h | 10 ++++------ include/stc/cqueue.h | 32 ++++++++++++++++---------------- include/stc/cstack.h | 7 +++++++ include/stc/cvec.h | 3 +++ 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index db076ae4..fe733c64 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -106,7 +106,7 @@ int main() for (_i = it; it.ref; C##_next(&it)) \ if (pred) C##_value_drop(it.ref), ++_n; \ else *_i.ref = *it.ref, C##_next(&_i); \ - _cnt->_len -= _n; \ + C##_adjust_end_(_cnt, -_n); \ } while (0) // ------------------------ private ------------------------- diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 80dd1dbe..100a6b19 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -46,9 +46,8 @@ _cx_memb(_at_mut)(_cx_self* self, intptr_t idx) { return self->data + _cdeq_topos(self, idx); } STC_INLINE _cx_value* -_cx_memb(_push_back)(_cx_self* self, _cx_value val) { - return _cx_memb(_push)(self, val); -} +_cx_memb(_push_back)(_cx_self* self, _cx_value val) + { return _cx_memb(_push)(self, val); } STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) { @@ -141,14 +140,13 @@ _cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t n) { STC_DEF _cx_iter _cx_memb(_insert_uninit)(_cx_self* self, const intptr_t idx, const intptr_t n) { const intptr_t len = _cx_memb(_size)(self); - _cx_iter it = {._s=self}; + _cx_iter it = {.pos=_cdeq_topos(self, idx), ._s=self}; if (len + n > self->capmask) if (!_cx_memb(_reserve)(self, len + n)) return it; for (intptr_t j = len - 1, i = j + n; j >= idx; --j, --i) *_cx_memb(_at_mut)(self, i) = *_cx_memb(_at)(self, j); self->end = (self->end + n) & self->capmask; - it.pos = _cdeq_topos(self, idx); it.ref = self->data + it.pos; return it; } @@ -172,7 +170,7 @@ _cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw* raw, con #if defined _i_has_eq || defined _i_has_cmp STC_DEF _cx_iter _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { - for (; i1.ref; _cx_memb(_next)(&i1)) { + for (; i1.pos != i2.pos; _cx_memb(_next)(&i1)) { const _cx_raw r = i_keyto(i1.ref); if (i_eq((&raw), (&r))) break; diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 09a747e5..d880d1fd 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -76,17 +76,14 @@ STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* pval) { return i_keyto(pval); } -STC_INLINE _cx_value* -_cx_memb(_front)(const _cx_self* self) - { return self->data + self->start; } +STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) + { return self->data + self->start; } -STC_INLINE _cx_value* -_cx_memb(_back)(const _cx_self* self) - { return self->data + ((self->end - 1) & self->capmask); } +STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) + { return self->data + ((self->end - 1) & self->capmask); } -STC_INLINE void -_cx_memb(_pop)(_cx_self* self) { // pop_front - c_ASSERT(!_cx_memb(_empty)(self)); +STC_INLINE void _cx_memb(_pop)(_cx_self* self) { // pop_front + assert(!_cx_memb(_empty)(self)); i_keydrop((self->data + self->start)); self->start = (self->start + 1) & self->capmask; } @@ -97,25 +94,28 @@ STC_INLINE void _cx_memb(_copy)(_cx_self* self, const _cx_self* other) { *self = _cx_memb(_clone)(*other); } -STC_INLINE _cx_iter -_cx_memb(_begin)(const _cx_self* self) { +STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { return c_LITERAL(_cx_iter){ _cx_memb(_empty)(self) ? NULL : self->data + self->start, self->start, self }; } -STC_INLINE _cx_iter -_cx_memb(_end)(const _cx_self* self) - { return c_LITERAL(_cx_iter){NULL, self->end, self}; } +STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) + { return c_LITERAL(_cx_iter){.pos=self->end, ._s=self}; } -STC_INLINE void -_cx_memb(_next)(_cx_iter* it) { +STC_INLINE void _cx_memb(_next)(_cx_iter* it) { if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; } else { it->ref -= it->pos; it->pos = 0; } if (it->pos == it->_s->end) it->ref = NULL; } +STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it) + { return _cdeq_toidx(self, it.pos); } + +STC_INLINE void _cx_memb(_adjust_end_)(_cx_self* self, intptr_t n) + { self->end = (self->end + n) & self->capmask; } + /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) diff --git a/include/stc/cstack.h b/include/stc/cstack.h index 87ef9405..84bdb41b 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -80,6 +80,7 @@ STC_INLINE void _cx_memb(_drop)(_cx_self* self) { i_free(self->data); #endif } + STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) { return self->_len; } @@ -187,4 +188,10 @@ STC_INLINE void _cx_memb(_next)(_cx_iter* it) STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) { if ((it.ref += n) >= it.end) it.ref = NULL ; return it; } +STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it) + { return (it.ref - self->data); } + +STC_INLINE void _cx_memb(_adjust_end_)(_cx_self* self, intptr_t n) + { self->_len += n; } + #include "priv/template2.h" diff --git a/include/stc/cvec.h b/include/stc/cvec.h index a7eb1a05..1a0fb118 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -207,6 +207,9 @@ STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it) { return (it.ref - self->data); } +STC_INLINE void _cx_memb(_adjust_end_)(_cx_self* self, intptr_t n) + { self->_len += n; } + #if !defined i_no_cmp || defined _i_has_eq STC_INLINE _cx_iter -- cgit v1.2.3 From c94e7b91d552a05d49e1cc3859f80e9f20406b48 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 18 May 2023 23:00:42 +0200 Subject: Renamed template param i_con => i_base in stc/extend.h. Also the macro c_getcon(self) => c_extend(self). --- README.md | 8 ++++---- include/stc/extend.h | 10 +++++----- misc/examples/functor.c | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3b9cf90f..2ef371b5 100644 --- a/README.md +++ b/README.md @@ -564,8 +564,8 @@ It adds a MemoryContext to each container by defining the `i_extend` template pa the by inclusion of ``. ```c // stcpgs.h -#define pgs_malloc(sz) MemoryContextAlloc(c_getcon(self)->memctx, sz) -#define pgs_calloc(n, sz) MemoryContextAllocZero(c_getcon(self)->memctx, (n)*(sz)) +#define pgs_malloc(sz) MemoryContextAlloc(c_extend(self)->memctx, sz) +#define pgs_calloc(n, sz) MemoryContextAllocZero(c_extend(self)->memctx, (n)*(sz)) #define pgs_realloc(p, sz) (p ? repalloc(p, sz) : pgs_malloc(sz)) #define pgs_free(p) (p ? pfree(p) : (void)0) // pfree/repalloc does not accept NULL. @@ -574,12 +574,12 @@ the by inclusion of ``. #define i_extend MemoryContext memctx; #include ``` -To use it, define both `i_type` and `i_con` (the container type) before including the custom header: +To use it, define both `i_type` and `i_base` (the container type) before including the custom header: ```c #define i_type IMap +#define i_base csmap #define i_key int #define i_val int -#define i_con csmap #include "stcpgs.h" // Note the wrapper struct type is IMap_ext. IMap is accessed by .get diff --git a/include/stc/extend.h b/include/stc/extend.h index 66b3ebd1..f697d2b3 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -44,9 +44,9 @@ #endif #ifdef _i_key - c_PASTE(forward_, i_con)(i_type, _i_key, _i_val); + c_PASTE(forward_, i_base)(i_type, _i_key, _i_val); #else - c_PASTE(forward_, i_con)(i_type, _i_val); + c_PASTE(forward_, i_base)(i_type, _i_val); #endif typedef struct { @@ -54,13 +54,13 @@ typedef struct { i_type get; } c_PASTE(i_type, _ext); -#define c_getcon(cptr) c_container_of(cptr, _cx_memb(_ext), get) +#define c_extend(self) c_container_of(self, _cx_memb(_ext), get) #define i_is_forward -#define _i_inc +#define _i_inc #include _i_inc #undef _i_inc #undef _i_key #undef _i_val -#undef i_con +#undef i_base #undef i_extend diff --git a/misc/examples/functor.c b/misc/examples/functor.c index c0a4f8e8..d6adfcb1 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -8,10 +8,10 @@ #include #define i_type IPQue +#define i_base cpque #define i_val int #define i_extend bool (*less)(const int*, const int*); -#define i_less(x, y) c_getcon(self)->less(x, y) -#define i_con cpque +#define i_less(x, y) c_extend(self)->less(x, y) #include void print_queue(const char* name, IPQue_ext q) { -- cgit v1.2.3 From 424e522d6f081bb8649777a3376e1dd5913daac8 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Fri, 19 May 2023 04:00:48 +0200 Subject: Fixed an iter return bug in cdeq_insert_uninit(). --- include/stc/cdeq.h | 14 ++++++++++---- include/stc/cqueue.h | 1 - 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 100a6b19..0dbe7f5d 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -33,7 +33,6 @@ STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value); STC_API _cx_iter _cx_memb(_insert_n)(_cx_self* self, intptr_t idx, const _cx_value* arr, intptr_t n); -STC_API _cx_iter _cx_memb(_emplace_n)(_cx_self* self, intptr_t idx, const _cx_raw* raw, intptr_t n); STC_API _cx_iter _cx_memb(_insert_uninit)(_cx_self* self, intptr_t idx, intptr_t n); STC_API void _cx_memb(_erase_n)(_cx_self* self, intptr_t idx, intptr_t n); @@ -79,6 +78,9 @@ _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { } #if !defined i_no_emplace +STC_API _cx_iter +_cx_memb(_emplace_n)(_cx_self* self, intptr_t idx, const _cx_raw* raw, intptr_t n); + STC_INLINE _cx_value* _cx_memb(_emplace_front)(_cx_self* self, const _cx_raw raw) { return _cx_memb(_push_front)(self, i_keyfrom(raw)); } @@ -140,13 +142,15 @@ _cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t n) { STC_DEF _cx_iter _cx_memb(_insert_uninit)(_cx_self* self, const intptr_t idx, const intptr_t n) { const intptr_t len = _cx_memb(_size)(self); - _cx_iter it = {.pos=_cdeq_topos(self, idx), ._s=self}; + _cx_iter it = {._s=self}; if (len + n > self->capmask) if (!_cx_memb(_reserve)(self, len + n)) return it; - for (intptr_t j = len - 1, i = j + n; j >= idx; --j, --i) - *_cx_memb(_at_mut)(self, i) = *_cx_memb(_at)(self, j); + for (intptr_t i = len - 1, j = i + n; i >= idx; --i, --j) + *_cx_memb(_at_mut)(self, j) = *_cx_memb(_at)(self, i); + self->end = (self->end + n) & self->capmask; + it.pos = _cdeq_topos(self, idx); it.ref = self->data + it.pos; return it; } @@ -159,6 +163,7 @@ _cx_memb(_insert_n)(_cx_self* self, const intptr_t idx, const _cx_value* arr, co return it; } +#if !defined i_no_emplace STC_DEF _cx_iter _cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw* raw, const intptr_t n) { _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); @@ -166,6 +171,7 @@ _cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw* raw, con *_cx_memb(_at_mut)(self, i) = i_keyfrom(raw[j]); return it; } +#endif #if defined _i_has_eq || defined _i_has_cmp STC_DEF _cx_iter diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index d880d1fd..840c4fa6 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -210,7 +210,6 @@ _cx_memb(_clone)(_cx_self cx) { out.end = sz; return out; } - #endif // i_no_clone #endif // IMPLEMENTATION #include "priv/template2.h" -- cgit v1.2.3 From d629139d053fdc1ff24bc0dc1985e1a2d1a0ac47 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Fri, 19 May 2023 19:06:37 +0200 Subject: Added container equality function to docs _eq(c1, c2). --- docs/ccommon_api.md | 28 ++++++++++++++++++++++++---- docs/cdeq_api.md | 1 + docs/clist_api.md | 1 + docs/cqueue_api.md | 1 + docs/cstack_api.md | 1 + docs/cvec_api.md | 1 + include/stc/cdeq.h | 13 ------------- include/stc/cqueue.h | 18 ++++++++++++++++++ include/stc/cstack.h | 11 +++++++++++ misc/benchmarks/various/csort_bench.c | 2 +- 10 files changed, 59 insertions(+), 18 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index e37a1463..eaf01996 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -204,22 +204,40 @@ if (it.ref) cmap_str_erase_at(&map, it); c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello")); ``` -### csort - two times faster qsort +### sort_n_ - two times faster qsort -When very fast array sorting is required, **csort** is about twice as fast as *qsort()*, and often simpler to use. +The **sort_n**, **sort_ij** algorithm is about twice as fast as *qsort()*, and often simpler to use. You may customize `i_tag` and the comparison function `i_cmp` or `i_less`. There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c). ```c #define i_val int #include +#include int main() { - int array[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}; - csort_int(array, c_arraylen(array)); + int nums[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}; + intarray_sort_n(nums, c_arraylen(nums)); + c_forrange (i, c_arraylen(arr)) printf(" %d", arr[i]); } ``` +Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is +possible and very fast. Note that `i_more` must be defined to pick up template parameters from the container: +```c +#define i_type MyDeq +#define i_val int +#define i_more +#include // deque +#include +#include +int main() { + MyDeq deq = c_make(MyDeq, {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}); + MyDeq_sort_n(&deq, MyDeq_size(&deq)); + c_foreach (i, MyDeq, deq) printf(" %d", *i.ref); + MyDeq_drop(&deq); +} +``` ### c_new, c_delete @@ -403,6 +421,8 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are | `continue` | Exit a defer-block without resource leak | ```c +#include // or +... // `c_defer` executes the expression(s) when leaving scope. cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); c_defer (cstr_drop(&s1), cstr_drop(&s2)) diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index 91022a5c..99980c24 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -79,6 +79,7 @@ cdeq_X_iter cdeq_X_end(const cdeq_X* self); void cdeq_X_next(cdeq_X_iter* it); cdeq_X_iter cdeq_X_advance(cdeq_X_iter it, intptr_t n); +bool cdeq_X_eq(const cdeq_X* c1, const cdeq_X* c2); // require i_eq/i_cmp/i_less. cdeq_X_value cdeq_X_value_clone(cdeq_X_value val); cdeq_X_raw cdeq_X_value_toraw(const cdeq_X_value* pval); void cdeq_X_value_drop(cdeq_X_value* pval); diff --git a/docs/clist_api.md b/docs/clist_api.md index 44c3bb7c..eb84fbd4 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -96,6 +96,7 @@ clist_X_iter clist_X_end(const clist_X* self); void clist_X_next(clist_X_iter* it); clist_X_iter clist_X_advance(clist_X_iter it, size_t n); // return n elements ahead. +bool clist_X_eq(const clist_X* c1, const clist_X* c2); // equality test clist_X_value clist_X_value_clone(clist_X_value val); clist_X_raw clist_X_value_toraw(const clist_X_value* pval); void clist_X_value_drop(clist_X_value* pval); diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md index 7d8d4e5c..f5df86d6 100644 --- a/docs/cqueue_api.md +++ b/docs/cqueue_api.md @@ -51,6 +51,7 @@ cqueue_X_iter cqueue_X_end(const cqueue_X* self); void cqueue_X_next(cqueue_X_iter* it); cqueue_X_iter cqueue_X_advance(cqueue_X_iter it, intptr_t n); +bool cqueue_X_eq(const cqueue_X* c1, const cqueue_X* c2); // require i_eq/i_cmp/i_less. i_val cqueue_X_value_clone(i_val value); cqueue_X_raw cqueue_X_value_toraw(const cqueue_X_value* pval); void cqueue_X_value_drop(cqueue_X_value* pval); diff --git a/docs/cstack_api.md b/docs/cstack_api.md index c20de7d1..9cb7b42b 100644 --- a/docs/cstack_api.md +++ b/docs/cstack_api.md @@ -54,6 +54,7 @@ cstack_X_iter cstack_X_begin(const cstack_X* self); cstack_X_iter cstack_X_end(const cstack_X* self); void cstack_X_next(cstack_X_iter* it); +bool cstack_X_eq(const cstack_X* c1, const cstack_X* c2); // require i_eq/i_cmp/i_less. i_val cstack_X_value_clone(i_val value); i_valraw cstack_X_value_toraw(const cvec_X_value* pval); void cstack_X_value_drop(cvec_X_value* pval); diff --git a/docs/cvec_api.md b/docs/cvec_api.md index 194d48e1..841321b2 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -91,6 +91,7 @@ cvec_X_iter cvec_X_end(const cvec_X* self); void cvec_X_next(cvec_X_iter* iter); cvec_X_iter cvec_X_advance(cvec_X_iter it, size_t n); +bool cvec_X_eq(const cvec_X* c1, const cvec_X* c2); // equality comp. cvec_X_value cvec_X_value_clone(cvec_X_value val); cvec_X_raw cvec_X_value_toraw(const cvec_X_value* pval); cvec_X_raw cvec_X_value_drop(cvec_X_value* pval); diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 0dbe7f5d..77fb015f 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -96,7 +96,6 @@ _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, const _cx_raw raw) #if defined _i_has_eq || defined _i_has_cmp STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw); -STC_API bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other); STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_raw raw) { @@ -183,18 +182,6 @@ _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { } return i1; } - -STC_DEF bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; - for (_cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other); - i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) - { - const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); - if (!(i_eq((&_rx), (&_ry)))) return false; - } - return true; -} #endif #endif // IMPLEMENTATION #define CDEQ_H_INCLUDED diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 840c4fa6..1f2c7d0f 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -62,6 +62,10 @@ STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) { return _cx_memb(_push)(self, i_keyfrom(raw)); } #endif +#if defined _i_has_eq || defined _i_has_cmp +STC_API bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other); +#endif + #if !defined i_no_clone STC_API _cx_self _cx_memb(_clone)(_cx_self cx); STC_INLINE i_key _cx_memb(_value_clone)(i_key val) @@ -211,6 +215,20 @@ _cx_memb(_clone)(_cx_self cx) { return out; } #endif // i_no_clone + +#if defined _i_has_eq || defined _i_has_cmp +STC_DEF bool +_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { + if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; + for (_cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other); + i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) + { + const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); + if (!(i_eq((&_rx), (&_ry)))) return false; + } + return true; +} +#endif #endif // IMPLEMENTATION #include "priv/template2.h" #define CQUEUE_H_INCLUDED diff --git a/include/stc/cstack.h b/include/stc/cstack.h index 84bdb41b..bee7d17b 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -194,4 +194,15 @@ STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it) STC_INLINE void _cx_memb(_adjust_end_)(_cx_self* self, intptr_t n) { self->_len += n; } +#if defined _i_has_eq || defined _i_has_cmp +STC_INLINE bool +_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { + if (self->_len != other->_len) return false; + for (intptr_t i = 0; i < self->_len; ++i) { + const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i); + if (!(i_eq((&_rx), (&_ry)))) return false; + } + return true; +} +#endif #include "priv/template2.h" diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c index 4d1149fc..d434693f 100644 --- a/misc/benchmarks/various/csort_bench.c +++ b/misc/benchmarks/various/csort_bench.c @@ -32,7 +32,7 @@ void testsort(Ints *a, int size, const char *desc) { #elif defined QSORT printf("qsort: "); qsort(a->data, size, sizeof *a->data, cmp_int); #else - printf("stc_qsort: "); Ints_sort_n(a, size); + printf("STC sort_n: "); Ints_sort_n(a, size); #endif t = clock() - t; -- cgit v1.2.3 From 26513bb1352ab4e4ffe931aabd80868216afc551 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Fri, 19 May 2023 20:55:57 +0200 Subject: Minor cbits change. --- include/stc/cbits.h | 2 -- include/stc/cdeq.h | 4 ++-- include/stc/cqueue.h | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/include/stc/cbits.h b/include/stc/cbits.h index 855d6eb7..cf13790a 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -128,7 +128,6 @@ STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, cons typedef struct { uint64_t *data64; int64_t _size; } i_type; STC_INLINE cbits cbits_init(void) { return c_LITERAL(cbits){NULL}; } -STC_INLINE void cbits_create(cbits* self) { self->data64 = NULL; self->_size = 0; } STC_INLINE void cbits_drop(cbits* self) { c_free(self->data64); } STC_INLINE int64_t cbits_size(const cbits* self) { return self->_size; } @@ -200,7 +199,6 @@ STC_INLINE cbits cbits_with_pattern(const int64_t size, const uint64_t pattern) typedef struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } i_type; STC_INLINE i_type _i_memb(_init)(void) { return c_LITERAL(i_type){0}; } -STC_INLINE void _i_memb(_create)(i_type* self) {} STC_INLINE void _i_memb(_drop)(i_type* self) {} STC_INLINE int64_t _i_memb(_size)(const i_type* self) { return i_capacity; } STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; } diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 77fb015f..b3714bf8 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -94,7 +94,7 @@ _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, const _cx_raw raw) { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); } #endif -#if defined _i_has_eq || defined _i_has_cmp +#if defined _i_has_cmp || defined _i_has_eq STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw); STC_INLINE _cx_iter @@ -172,7 +172,7 @@ _cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw* raw, con } #endif -#if defined _i_has_eq || defined _i_has_cmp +#if defined _i_has_cmp || defined _i_has_eq STC_DEF _cx_iter _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { for (; i1.pos != i2.pos; _cx_memb(_next)(&i1)) { diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 1f2c7d0f..571c1fe9 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -62,7 +62,7 @@ STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) { return _cx_memb(_push)(self, i_keyfrom(raw)); } #endif -#if defined _i_has_eq || defined _i_has_cmp +#if defined _i_has_cmp || defined _i_has_eq STC_API bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other); #endif @@ -216,7 +216,7 @@ _cx_memb(_clone)(_cx_self cx) { } #endif // i_no_clone -#if defined _i_has_eq || defined _i_has_cmp +#if defined _i_has_cmp || defined _i_has_eq STC_DEF bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; -- cgit v1.2.3 From bb59d9c87f8d99f50c439351480c0ec8d6eea38e Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sat, 20 May 2023 00:40:54 +0200 Subject: Rename c_make() macro to c_init(). c_make still available, but deprecated. --- README.md | 4 ++-- docs/cbox_api.md | 2 +- docs/ccommon_api.md | 10 +++++----- docs/clist_api.md | 8 ++++---- docs/cmap_api.md | 2 +- docs/cset_api.md | 2 +- docs/csmap_api.md | 4 ++-- docs/cspan_api.md | 4 ++-- docs/csset_api.md | 2 +- include/stc/algo/filter.h | 2 +- include/stc/ccommon.h | 5 +++-- include/stc/cspan.h | 2 +- include/stc/cstack.h | 6 +++--- misc/examples/arcvec_erase.c | 2 +- misc/examples/cointerleave.c | 4 ++-- misc/examples/convert.c | 2 +- misc/examples/csmap_erase.c | 2 +- misc/examples/csmap_find.c | 2 +- misc/examples/csmap_insert.c | 2 +- misc/examples/csset_erase.c | 2 +- misc/examples/forfilter.c | 2 +- misc/examples/forloops.c | 4 ++-- misc/examples/inits.c | 6 +++--- misc/examples/list.c | 2 +- misc/examples/list_erase.c | 2 +- misc/examples/list_splice.c | 4 ++-- misc/examples/lower_bound.c | 4 ++-- misc/examples/multidim.c | 2 +- misc/examples/music_arc.c | 2 +- misc/examples/new_list.c | 4 ++-- misc/examples/new_map.c | 6 +++--- misc/examples/new_pque.c | 2 +- misc/examples/new_smap.c | 4 ++-- misc/examples/phonebook.c | 2 +- misc/examples/printspan.c | 8 ++++---- misc/examples/scheduler.c | 2 +- 36 files changed, 63 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 2ef371b5..d699e1d1 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Algorithms ---------- - [***Ranged for-loops*** - c_foreach, c_forpair, c_forlist](docs/ccommon_api.md#ranged-for-loops) - [***Range algorithms*** - c_forrange, crange, c_forfilter](docs/ccommon_api.md#range-algorithms) -- [***Generic algorithms*** - c_make, c_find_if, c_erase_if, csort, etc.](docs/ccommon_api.md#generic-algorithms) +- [***Generic algorithms*** - c_init, c_find_if, c_erase_if, csort, etc.](docs/ccommon_api.md#generic-algorithms) - [***Coroutines*** - Simon Tatham's coroutines done right.](docs/ccommon_api.md#coroutines) - [***Regular expressions*** - Rob Pike's Plan 9 regexp modernized!](docs/cregex_api.md) - [***Random numbers*** - a very fast *PRNG* based on *SFC64*](docs/crandom_api.md) @@ -117,7 +117,7 @@ Benchmark notes: ## Naming conventions - Container names are prefixed by `c`, e.g. `cvec`, `cstr`. -- Public STC macros are prefixed by `c_`, e.g. `c_foreach`, `c_make`. +- Public STC macros are prefixed by `c_`, e.g. `c_foreach`, `c_init`. - Template parameter macros are prefixed by `i_`, e.g. `i_val`, `i_type`. - All containers can be initialized with `{0}`, i.e. no heap allocation used by default init. - Common types for a container type Con: diff --git a/docs/cbox_api.md b/docs/cbox_api.md index ca4d90da..5914a5ad 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -92,7 +92,7 @@ void int_drop(int* x) { int main() { - IVec vec = c_make(Vec, {2021, 2012, 2022, 2015}); + IVec vec = c_init(Vec, {2021, 2012, 2022, 2015}); ISet set = {0}; c_defer( IVec_drop(&vec), diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index eaf01996..56424989 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -18,7 +18,7 @@ #define i_tag ii #include ... -csmap_ii map = c_make(csmap_ii, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} }); +csmap_ii map = c_init(csmap_ii, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} }); c_foreach (i, csmap_ii, map) printf(" %d", i.ref->first); @@ -158,7 +158,7 @@ Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false. --- ## Generic algorithms -### c_make, c_drop +### c_init, c_drop Make any container from an initializer list: ```c @@ -170,11 +170,11 @@ Make any container from an initializer list: #include ... // Initializes with const char*, internally converted to cstr! -cset_str myset = c_make(cset_str, {"This", "is", "the", "story"}); +cset_str myset = c_init(cset_str, {"This", "is", "the", "story"}); cset_str myset2 = c_clone(myset); int x = 7, y = 8; -cmap_int mymap = c_make(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); +cmap_int mymap = c_init(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); ``` Drop multiple containers of the same type: ```c @@ -232,7 +232,7 @@ possible and very fast. Note that `i_more` must be defined to pick up template p #include int main() { - MyDeq deq = c_make(MyDeq, {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}); + MyDeq deq = c_init(MyDeq, {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}); MyDeq_sort_n(&deq, MyDeq_size(&deq)); c_foreach (i, MyDeq, deq) printf(" %d", *i.ref); MyDeq_drop(&deq); diff --git a/docs/clist_api.md b/docs/clist_api.md index eb84fbd4..36935c88 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -124,7 +124,7 @@ Interleave *push_front()* / *push_back()* then *sort()*: #include int main() { - DList list = c_make(DList, {10., 20., 30., 40., 50., 60., 70., 80., 90.}); + DList list = c_init(DList, {10., 20., 30., 40., 50., 60., 70., 80., 90.}); c_forrange (i, 1, 10) { if (i & 1) DList_push_front(&list, (double) i); @@ -162,7 +162,7 @@ Use of *erase_at()* and *erase_range()*: int main () { - clist_i L = c_make(clist_i, {10, 20, 30, 40, 50}); + clist_i L = c_init(clist_i, {10, 20, 30, 40, 50}); // 10 20 30 40 50 clist_i_iter it = clist_i_begin(&L); // ^ clist_i_next(&it); @@ -196,8 +196,8 @@ Splice `[30, 40]` from *L2* into *L1* before `3`: #include int main() { - clist_i L1 = c_make(clist_i, {1, 2, 3, 4, 5}); - clist_i L2 = c_make(clist_i, {10, 20, 30, 40, 50}); + clist_i L1 = c_init(clist_i, {1, 2, 3, 4, 5}); + clist_i L2 = c_init(clist_i, {10, 20, 30, 40, 50}); clist_i_iter i = clist_i_advance(clist_i_begin(&L1), 2); clist_i_iter j1 = clist_i_advance(clist_i_begin(&L2), 2), j2 = clist_i_advance(j1, 2); diff --git a/docs/cmap_api.md b/docs/cmap_api.md index cdb57534..2c9ac8ed 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -123,7 +123,7 @@ bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // ! int main() { // Create an unordered_map of three strings (that map to strings) - cmap_str umap = c_make(cmap_str, { + cmap_str umap = c_init(cmap_str, { {"RED", "#FF0000"}, {"GREEN", "#00FF00"}, {"BLUE", "#0000FF"} diff --git a/docs/cset_api.md b/docs/cset_api.md index b9e8ae99..7243beb3 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -86,7 +86,7 @@ int main () { Strset first, second={0}, third={0}, fourth={0}, fifth; - first = c_make(Strset, {"red", "green", "blue"}); + first = c_init(Strset, {"red", "green", "blue"}); fifth = Strset_clone(second); c_forlist (i, const char*, {"orange", "pink", "yellow"}) diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 8c2048c0..b1bb07c6 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -111,7 +111,7 @@ void csmap_X_value_drop(csmap_X_value* pval); int main() { // Create a sorted map of three strings (maps to string) - csmap_str colors = c_make(csmap_str, { + csmap_str colors = c_init(csmap_str, { {"RED", "#FF0000"}, {"GREEN", "#00FF00"}, {"BLUE", "#0000FF"} @@ -192,7 +192,7 @@ This example uses a csmap with cstr as mapped value. int main() { uint32_t col = 0xcc7744ff; - IDSMap idnames = c_make(IDSMap, { {100, "Red"}, {110, "Blue"} }); + IDSMap idnames = c_init(IDSMap, { {100, "Red"}, {110, "Blue"} }); // Assign/overwrite an existing mapped value with a const char* IDSMap_emplace_or_assign(&idnames, 110, "White"); diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 10565b0f..ec203460 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -143,8 +143,8 @@ using_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3 int main() { - // c_make() can create any STC container/span from an initializer list: - Span span = c_make(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + // c_init() can create any STC container/span from an initializer list: + Span span = c_init(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}); // create a 3d cspan: Span3 span3 = cspan_md(span.data, 2, 4, 3); diff --git a/docs/csset_api.md b/docs/csset_api.md index d095696c..dafe6670 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -86,7 +86,7 @@ int main () { SSet second={0}, third={0}, fourth={0}, fifth={0}; - second = c_make(SSet, {"red", "green", "blue"}); + second = c_init(SSet, {"red", "green", "blue"}); c_forlist (i, const char*, {"orange", "pink", "yellow"}) SSet_emplace(&third, *i.ref); diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index fe733c64..8dc1ad74 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -28,7 +28,7 @@ int main() { - cstack_int stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7, 8, 9}); + cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7, 8, 9}); c_foreach (i, cstack_int, stk) printf(" %d", *i.ref); diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 07c72e2f..e9d97d4b 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -117,8 +117,9 @@ /* Function macros and others */ -#define c_make(C, ...) \ - C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) +#define c_init(C, ...) \ + C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) +#define c_make(C, ...) c_init(C, __VA_ARGS__) // [deprecated] #define c_litstrlen(literal) (c_sizeof("" literal) - 1) #define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a]) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index ac3e9206..b07e75a8 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -115,7 +115,7 @@ typedef struct { int32_t d[6]; } cspan_idx6; #define cspan_md(array, ...) \ {.data=array, .shape={__VA_ARGS__}, .stride={.d={__VA_ARGS__}}} -/* For static initialization, use cspan_make(). c_make() for non-static only. */ +/* For static initialization, use cspan_make(). c_init() for non-static only. */ #define cspan_make(SpanType, ...) \ {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}} diff --git a/include/stc/cstack.h b/include/stc/cstack.h index bee7d17b..eb6ccb58 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -175,12 +175,12 @@ STC_INLINE i_keyraw _cx_memb(_value_toraw)(const _cx_value* val) #endif // !i_no_clone STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { - return c_LITERAL(_cx_iter){self->_len ? (_cx_value*)self->data : NULL, - (_cx_value*)self->data + self->_len}; + return c_LITERAL(_cx_iter){self->_len ? self->data : NULL, + self->data + self->_len}; } STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) - { return c_LITERAL(_cx_iter){NULL, (_cx_value*)self->data + self->_len}; } + { return c_LITERAL(_cx_iter){NULL, self->data + self->_len}; } STC_INLINE void _cx_memb(_next)(_cx_iter* it) { if (++it->ref == it->end) it->ref = NULL; } diff --git a/misc/examples/arcvec_erase.c b/misc/examples/arcvec_erase.c index 3bf41559..28160c1c 100644 --- a/misc/examples/arcvec_erase.c +++ b/misc/examples/arcvec_erase.c @@ -15,7 +15,7 @@ void show_drop(int* x) { printf("drop: %d\n", *x); } int main() { - Vec vec = c_make(Vec, {2012, 1990, 2012, 2019, 2015}); + Vec vec = c_init(Vec, {2012, 1990, 2012, 2019, 2015}); // clone the second 2012 and push it back. // note: cloning make sure that vec.data[2] has ref count 2. diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index aa57808e..e11b2bf3 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -38,8 +38,8 @@ void interleaved(struct Generator* g) void Use(void) { - IVec a = c_make(IVec, {2, 4, 6, 8, 10, 11}); - IVec b = c_make(IVec, {3, 5, 7, 9}); + IVec a = c_init(IVec, {2, 4, 6, 8, 10, 11}); + IVec b = c_init(IVec, {3, 5, 7, 9}); struct Generator g = {{&a}, {&b}}; diff --git a/misc/examples/convert.c b/misc/examples/convert.c index 138035e9..c5649c55 100644 --- a/misc/examples/convert.c +++ b/misc/examples/convert.c @@ -25,7 +25,7 @@ int main() cvec_str_drop(&values), clist_str_drop(&list) ){ - map = c_make(cmap_str, { + map = c_init(cmap_str, { {"green", "#00ff00"}, {"blue", "#0000ff"}, {"yellow", "#ffff00"}, diff --git a/misc/examples/csmap_erase.c b/misc/examples/csmap_erase.c index 697e6c09..568dae29 100644 --- a/misc/examples/csmap_erase.c +++ b/misc/examples/csmap_erase.c @@ -34,7 +34,7 @@ int main() printmap(m1); // Fill in some data to test with - mymap m2 = c_make(mymap, { + mymap m2 = c_init(mymap, { {10, "Bob"}, {11, "Rob"}, {12, "Robert"}, diff --git a/misc/examples/csmap_find.c b/misc/examples/csmap_find.c index c417567a..92dd0031 100644 --- a/misc/examples/csmap_find.c +++ b/misc/examples/csmap_find.c @@ -42,7 +42,7 @@ void findit(csmap_istr c, csmap_istr_key val) int main() { - csmap_istr m1 = c_make(csmap_istr, {{40, "Zr"}, {45, "Rh"}}); + csmap_istr m1 = c_init(csmap_istr, {{40, "Zr"}, {45, "Rh"}}); cvec_istr v = {0}; puts("The starting map m1 is (key, value):"); diff --git a/misc/examples/csmap_insert.c b/misc/examples/csmap_insert.c index 3da245c7..7708fdc9 100644 --- a/misc/examples/csmap_insert.c +++ b/misc/examples/csmap_insert.c @@ -96,7 +96,7 @@ int main() csmap_ii m4 = {0}; // Insert the elements from an initializer_list - m4 = c_make(csmap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}}); + m4 = c_init(csmap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}}); puts("After initializer_list insertion, m4 contains:"); print_ii(m4); puts(""); diff --git a/misc/examples/csset_erase.c b/misc/examples/csset_erase.c index 9fa40682..5fe3fcba 100644 --- a/misc/examples/csset_erase.c +++ b/misc/examples/csset_erase.c @@ -5,7 +5,7 @@ int main() { - csset_int set = c_make(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50}); + csset_int set = c_init(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50}); c_foreach (k, csset_int, set) printf(" %d", *k.ref); diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index fbb7280f..8ea3e6a1 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -17,7 +17,7 @@ void demo1(void) { - IVec vec = c_make(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80, + IVec vec = c_init(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80, 10, 11, 12, 13, 14, 15, 80, 16, 17}); c_forfilter (i, IVec, vec, flt_skipValue(i, 80)) diff --git a/misc/examples/forloops.c b/misc/examples/forloops.c index 1fc00614..337cfaa1 100644 --- a/misc/examples/forloops.c +++ b/misc/examples/forloops.c @@ -34,8 +34,8 @@ int main() printf(" %s", *i.ref); puts(""); - IVec vec = c_make(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199}); - IMap map = c_make(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}}); + IVec vec = c_init(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199}); + IMap map = c_init(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}}); puts("\n\nc_foreach:"); c_foreach (i, IVec, vec) diff --git a/misc/examples/inits.c b/misc/examples/inits.c index e098422e..1f01f88a 100644 --- a/misc/examples/inits.c +++ b/misc/examples/inits.c @@ -66,7 +66,7 @@ int main(void) // CMAP CNT - cmap_cnt countries = c_make(cmap_cnt, { + cmap_cnt countries = c_init(cmap_cnt, { {"Norway", 100}, {"Denmark", 50}, {"Iceland", 10}, @@ -88,7 +88,7 @@ int main(void) // CVEC PAIR - cvec_ip pairs1 = c_make(cvec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); + cvec_ip pairs1 = c_init(cvec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); cvec_ip_sort(&pairs1); c_foreach (i, cvec_ip, pairs1) @@ -98,7 +98,7 @@ int main(void) // CLIST PAIR - clist_ip pairs2 = c_make(clist_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); + clist_ip pairs2 = c_init(clist_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); clist_ip_sort(&pairs2); c_foreach (i, clist_ip, pairs2) diff --git a/misc/examples/list.c b/misc/examples/list.c index 363d7fec..ed27aa50 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -34,7 +34,7 @@ int main() { puts(""); DList_drop(&list); - list = c_make(DList, {10, 20, 30, 40, 30, 50}); + list = c_init(DList, {10, 20, 30, 40, 30, 50}); const double* v = DList_get(&list, 30); printf("found: %f\n", *v); diff --git a/misc/examples/list_erase.c b/misc/examples/list_erase.c index 0201c2d9..17adf11f 100644 --- a/misc/examples/list_erase.c +++ b/misc/examples/list_erase.c @@ -7,7 +7,7 @@ int main () { - IList L = c_make(IList, {10, 20, 30, 40, 50}); + IList L = c_init(IList, {10, 20, 30, 40, 50}); c_foreach (x, IList, L) printf("%d ", *x.ref); diff --git a/misc/examples/list_splice.c b/misc/examples/list_splice.c index baebca29..73015454 100644 --- a/misc/examples/list_splice.c +++ b/misc/examples/list_splice.c @@ -16,8 +16,8 @@ void print_ilist(const char* s, clist_i list) int main () { - clist_i list1 = c_make(clist_i, {1, 2, 3, 4, 5}); - clist_i list2 = c_make(clist_i, {10, 20, 30, 40, 50}); + clist_i list1 = c_init(clist_i, {1, 2, 3, 4, 5}); + clist_i list2 = c_init(clist_i, {10, 20, 30, 40, 50}); print_ilist("list1:", list1); print_ilist("list2:", list2); diff --git a/misc/examples/lower_bound.c b/misc/examples/lower_bound.c index 6ec7544c..d146c4d9 100644 --- a/misc/examples/lower_bound.c +++ b/misc/examples/lower_bound.c @@ -11,7 +11,7 @@ int main() // TEST SORTED VECTOR { int key, *res; - cvec_int vec = c_make(cvec_int, {40, 600, 1, 7000, 2, 500, 30}); + cvec_int vec = c_init(cvec_int, {40, 600, 1, 7000, 2, 500, 30}); cvec_int_sort(&vec); @@ -40,7 +40,7 @@ int main() // TEST SORTED SET { int key, *res; - csset_int set = c_make(csset_int, {40, 600, 1, 7000, 2, 500, 30}); + csset_int set = c_init(csset_int, {40, 600, 1, 7000, 2, 500, 30}); key = 100; res = csset_int_lower_bound(&set, key).ref; diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c index 3980e6d8..2f3ad907 100644 --- a/misc/examples/multidim.c +++ b/misc/examples/multidim.c @@ -8,7 +8,7 @@ using_cspan3(ispan, int); int main() { - cstack_int v = c_make(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}); + cstack_int v = c_init(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}); // View data as contiguous memory representing 24 ints ispan ms1 = cspan_from(&v); diff --git a/misc/examples/music_arc.c b/misc/examples/music_arc.c index 3714e1d5..87a57783 100644 --- a/misc/examples/music_arc.c +++ b/misc/examples/music_arc.c @@ -32,7 +32,7 @@ void Song_drop(Song* s) { void example3() { - SongVec vec1 = c_make(SongVec, { + SongVec vec1 = c_init(SongVec, { Song_make("Bob Dylan", "The Times They Are A Changing"), Song_make("Aretha Franklin", "Bridge Over Troubled Water"), Song_make("Thalia", "Entre El Mar y Una Estrella") diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index 14fabb4a..993f1aac 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -48,7 +48,7 @@ int main() clist_pnt_push_back(&my.pntlst, (Point){123, 456}); MyStruct_drop(&my); - clist_pnt plst = c_make(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); + clist_pnt plst = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); clist_pnt_sort(&plst); c_foreach (i, clist_pnt, plst) @@ -57,7 +57,7 @@ int main() clist_pnt_drop(&plst); - clist_float flst = c_make(clist_float, {123.3f, 321.2f, -32.2f, 78.2f}); + clist_float flst = c_init(clist_float, {123.3f, 321.2f, -32.2f, 78.2f}); clist_float_sort(&flst); c_foreach (i, clist_float, flst) diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c index f01db64f..1f50db83 100644 --- a/misc/examples/new_map.c +++ b/misc/examples/new_map.c @@ -42,18 +42,18 @@ int point_cmp(const Point* a, const Point* b) { int main() { - cmap_pnt pmap = c_make(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}}); + cmap_pnt pmap = c_init(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}}); c_foreach (i, cmap_pnt, pmap) printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second); puts(""); - cmap_str smap = c_make(cmap_str, { + cmap_str smap = c_init(cmap_str, { {"Hello, friend", "long time no see"}, {"So long", "see you around"}, }); - cset_str sset = c_make(cset_str, { + cset_str sset = c_init(cset_str, { "Hello, friend", "Nice to see you again", "So long", diff --git a/misc/examples/new_pque.c b/misc/examples/new_pque.c index 5b26b3de..dc2ecf12 100644 --- a/misc/examples/new_pque.c +++ b/misc/examples/new_pque.c @@ -10,7 +10,7 @@ typedef struct Point { int x, y; } Point; int main() { - PointQ pque = c_make(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}}); + PointQ pque = c_init(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}}); // print for (; !PointQ_empty(&pque); PointQ_pop(&pque)) { diff --git a/misc/examples/new_smap.c b/misc/examples/new_smap.c index f930eba2..2eaae836 100644 --- a/misc/examples/new_smap.c +++ b/misc/examples/new_smap.c @@ -37,12 +37,12 @@ int point_cmp(const Point* a, const Point* b) { int main() { - PMap pmap = c_make(PMap, { + PMap pmap = c_init(PMap, { {{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}, }); - SMap smap = c_make(SMap, { + SMap smap = c_init(SMap, { {"Hello, friend", "this is the mapped value"}, {"The brown fox", "jumped"}, {"This is the time", "for all good things"}, diff --git a/misc/examples/phonebook.c b/misc/examples/phonebook.c index c0007cb7..38a71089 100644 --- a/misc/examples/phonebook.c +++ b/misc/examples/phonebook.c @@ -38,7 +38,7 @@ void print_phone_book(cmap_str phone_book) int main(int argc, char **argv) { - cmap_str phone_book = c_make(cmap_str, { + cmap_str phone_book = c_init(cmap_str, { {"Lilia Friedman", "(892) 670-4739"}, {"Tariq Beltran", "(489) 600-7575"}, {"Laiba Juarez", "(303) 885-5692"}, diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c index 60a2d934..b9ec2476 100644 --- a/misc/examples/printspan.c +++ b/misc/examples/printspan.c @@ -24,21 +24,21 @@ int main() intspan sp1 = cspan_make(intspan, {1, 2}); printMe( sp1 ); - printMe( c_make(intspan, {1, 2, 3}) ); + printMe( c_init(intspan, {1, 2, 3}) ); int arr[] = {1, 2, 3, 4, 5, 6}; intspan sp2 = cspan_from_array(arr); printMe( (intspan)cspan_subspan(&sp2, 1, 4) ); - cvec_int vec = c_make(cvec_int, {1, 2, 3, 4, 5}); + cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5}); printMe( (intspan)cspan_from(&vec) ); printMe( sp2 ); - cstack_int stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7}); + cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7}); printMe( (intspan)cspan_from(&stk) ); - csset_str set = c_make(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); + csset_str set = c_init(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); printf("%d:", (int)csset_str_size(&set)); c_foreach (e, csset_str, set) printf(" %s", cstr_str(e.ref)); diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index bad5201b..14c85f56 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -58,7 +58,7 @@ static bool taskB(struct Task* task) void Use(void) { - Scheduler scheduler = c_make(Scheduler, { + Scheduler scheduler = c_init(Scheduler, { {taskA, &scheduler}, {taskB, &scheduler}, }); -- cgit v1.2.3 From ed9ccf1dcca8d3651e13ff1686148b4b23773721 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sat, 20 May 2023 07:24:22 +0200 Subject: Bug fix (NB!): cregex_captures() now returns num of cap. group *excluding* the full match group (0). --- docs/cregex_api.md | 10 +++++----- include/stc/cregex.h | 2 +- src/cregex.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/cregex_api.md b/docs/cregex_api.md index 9a15a869..e702c47c 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -29,7 +29,7 @@ cregex cregex_from(const char* pattern, int cflags = CREG_DEFAULT); // return CREG_OK, or negative error code on failure int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_DEFAULT); - // num. of capture groups in regex. 0 if RE is invalid. First group is the full match + // num. of capture groups in regex, excluding the 0th group which is the full match int cregex_captures(const cregex* self); // return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR @@ -139,14 +139,14 @@ To iterate multiple matches in an input string, you may use ```c csview match[5] = {0}; while (cregex_find(&re, input, match, CREG_M_NEXT) == CREG_OK) - c_forrange (k, cregex_captures(&re)) - printf("submatch %lld: %.*s\n", k, c_SV(match[k])); + for (int k = 1; i <= cregex_captures(&re); ++k) + printf("submatch %d: %.*s\n", k, c_SV(match[k])); ``` There is also a for-loop macro to simplify it: ```c c_formatch (it, &re, input) - c_forrange (k, cregex_captures(&re)) - printf("submatch %lld: %.*s\n", k, c_SV(it.match[k])); + for (int k = 1; i <= cregex_captures(&re); ++k) + printf("submatch %d: %.*s\n", k, c_SV(it.match[k])); ``` ## Using cregex in a project diff --git a/include/stc/cregex.h b/include/stc/cregex.h index a48b4c49..f90acbf4 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -104,7 +104,7 @@ STC_INLINE cregex cregex_from_2(const char* pattern, int cflags) { return re; } -/* number of capture groups in a regex pattern including full the match capture, 0 if regex is invalid */ +/* number of capture groups in a regex pattern, excluding the full match capture (0) */ int cregex_captures(const cregex* re); /* return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */ diff --git a/src/cregex.c b/src/cregex.c index 981a256a..5ba07550 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -1251,12 +1251,12 @@ cregex_compile_3(cregex *self, const char* pattern, int cflags) { int cregex_captures(const cregex* self) { - return self->prog ? 1 + self->prog->nsubids : 0; + return self->prog ? self->prog->nsubids : 0; } int cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { - int res = _regexec(re->prog, input, cregex_captures(re), match, mflags); + int res = _regexec(re->prog, input, cregex_captures(re) + 1, match, mflags); switch (res) { case 1: return CREG_OK; case 0: return CREG_NOMATCH; @@ -1281,7 +1281,7 @@ cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int cou cstr out = cstr_NULL; cstr subst = cstr_NULL; csview match[CREG_MAX_CAPTURES]; - int nmatch = cregex_captures(re); + int nmatch = cregex_captures(re) + 1; if (!count) count = INT32_MAX; bool copy = !(rflags & CREG_R_STRIP); -- cgit v1.2.3 From 56b0884044610861866a1a27fb64276411604986 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sat, 20 May 2023 08:58:33 +0200 Subject: Fixed two minor things. --- include/stc/cstr.h | 10 ++++------ src/cregex.c | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 694c02d0..244b0a91 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -364,13 +364,11 @@ STC_INLINE void cstr_pop(cstr* self) { STC_INLINE char* cstr_append(cstr* self, const char* str) { return cstr_append_n(self, str, c_strlen(str)); } -STC_INLINE void cstr_append_sv(cstr* self, csview sv) - { cstr_append_n(self, sv.str, sv.size); } +STC_INLINE char* cstr_append_sv(cstr* self, csview sv) + { return cstr_append_n(self, sv.str, sv.size); } -STC_INLINE char* cstr_append_s(cstr* self, cstr s) { - csview sv = cstr_sv(&s); - return cstr_append_n(self, sv.str, sv.size); -} +STC_INLINE char* cstr_append_s(cstr* self, cstr s) + { return cstr_append_sv(self, cstr_sv(&s)); } #define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__) #define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, INT32_MAX) diff --git a/src/cregex.c b/src/cregex.c index 5ba07550..730d35a4 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -1217,11 +1217,11 @@ _build_subst(const char* replace, int nmatch, const csview match[], g = arg - '0'; if (replace[1] >= '0' && replace[1] <= '9' && replace[2] == ';') { g = g*10 + (replace[1] - '0'); replace += 2; } - if (g < (int)nmatch) { + if (g < nmatch) { csview m = mfun && mfun(g, match[g], &mstr) ? cstr_sv(&mstr) : match[g]; if (len + m.size > cap) - dst = cstr_reserve(subst, cap += cap*3/2 + m.size); - for (int i = 0; i < (int)m.size; ++i) + dst = cstr_reserve(subst, cap += cap/2 + m.size); + for (int i = 0; i < m.size; ++i) dst[len++] = m.str[i]; } ++replace; @@ -1230,7 +1230,7 @@ _build_subst(const char* replace, int nmatch, const csview match[], } } if (len == cap) - dst = cstr_reserve(subst, cap = cap*3/2 + 4); + dst = cstr_reserve(subst, cap += cap/2 + 4); dst[len++] = *replace++; } cstr_drop(&mstr); -- cgit v1.2.3 From 0b34cadda2bc4da1cb0904989c8a5f2fe0236358 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sun, 21 May 2023 23:30:25 +0200 Subject: NB! Made cstr.h header-only by default. Now requires #define i_static, i_implement or i_extern (includes utf8code.c) to implement non-inline functions (or link with libstc). --- .github/workflows/workflow.yml | 4 ++-- CMakeLists.txt | 1 + include/stc/ccommon.h | 2 +- include/stc/cregex.h | 6 ++++-- include/stc/cstack.h | 6 +++--- include/stc/cstr.h | 1 + include/stc/csview.h | 1 - misc/examples/make.sh | 2 +- misc/tests/cregex_test.c | 6 +++--- src/libstc.c | 4 ++++ 10 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 src/libstc.c diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 5ceacd43..b1443a0d 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -7,8 +7,8 @@ jobs: build_and_test: runs-on: ubuntu-latest env: - CFLAGS: -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract - CXXFLAGS: -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract + CFLAGS: -DSTC_STATIC -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract + CXXFLAGS: -DSTC_STATIC -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract steps: - name: 'Checkout' uses: actions/checkout@v2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 87662318..3edd39cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ if(BUILD_TESTING) get_filename_component(name "${file}" NAME_WE) add_executable(${name} ${file}) #target_compile_options(${name} PRIVATE "-pthread") + target_compile_options(${name} PRIVATE "-DSTC_STATIC") if(CMAKE_THREAD_LIBS_INIT) target_link_libraries(${name} PRIVATE "${CMAKE_THREAD_LIBS_INIT}") endif() diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index e9d97d4b..eb3a6601 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -253,6 +253,6 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { #if defined(STC_EXTERN) #define i_extern #endif -#if defined(i_static) || defined(STC_IMPLEMENT) +#if defined(i_static) || defined(STC_IMPLEMENT) || defined(i_extern) #define i_implement #endif diff --git a/include/stc/cregex.h b/include/stc/cregex.h index f90acbf4..bf239ff6 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -160,12 +160,14 @@ cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char void cregex_drop(cregex* re); #endif // CREGEX_H_INCLUDED -#if defined(i_extern) +#if defined i_extern || defined i_implement # include "../../src/cregex.c" +#endif +#if defined i_extern # include "../../src/utf8code.c" -# undef i_extern #endif #undef i_opt #undef i_header #undef i_static #undef i_implement +#undef i_extern diff --git a/include/stc/cstack.h b/include/stc/cstack.h index eb6ccb58..ae8b3c40 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -175,12 +175,12 @@ STC_INLINE i_keyraw _cx_memb(_value_toraw)(const _cx_value* val) #endif // !i_no_clone STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { - return c_LITERAL(_cx_iter){self->_len ? self->data : NULL, - self->data + self->_len}; + return c_LITERAL(_cx_iter){self->_len ? (_cx_value*)self->data : NULL, + (_cx_value*)self->data + self->_len}; } STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) - { return c_LITERAL(_cx_iter){NULL, self->data + self->_len}; } + { return c_LITERAL(_cx_iter){NULL, (_cx_value*)self->data + self->_len}; } STC_INLINE void _cx_memb(_next)(_cx_iter* it) { if (++it->ref == it->end) it->ref = NULL; } diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 244b0a91..d496b85e 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -27,6 +27,7 @@ #ifndef CSTR_H_INCLUDED #define CSTR_H_INCLUDED +#define i_header #if defined i_extern || defined STC_EXTERN # define _i_extern #endif diff --git a/include/stc/csview.h b/include/stc/csview.h index bba3aea3..571bb278 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -24,7 +24,6 @@ #define CSVIEW_H_INCLUDED #include "ccommon.h" -#include "forward.h" #include "utf8.h" #define csview_NULL c_sv_1("") diff --git a/misc/examples/make.sh b/misc/examples/make.sh index ee8d2267..25b720b8 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -6,7 +6,7 @@ if [ "$(uname)" = 'Linux' ]; then oflag='-o ' fi -cc=gcc; cflags="-s -O3 -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized -Wno-missing-field-initializers" +cc=gcc; cflags="-DSTC_STATIC -s -O3 -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized -Wno-missing-field-initializers" #cc=gcc; cflags="-g -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" #cc=tcc; cflags="-Wall -std=c99" #cc=clang; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall -Wno-unused-function -Wsign-compare -Wwrite-strings" diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 07e5c3cb..301ecf4f 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -209,7 +209,7 @@ CTEST(cregex, captures_len) { c_auto (cregex, re) { re = cregex_from("(ab(cd))(ef)"); - ASSERT_EQ(cregex_captures(&re), 4); + ASSERT_EQ(cregex_captures(&re), 3); } } @@ -218,7 +218,7 @@ CTEST(cregex, captures_cap) const char* inp; c_auto (cregex, re) { re = cregex_from("(ab)((cd)+)"); - ASSERT_EQ(cregex_captures(&re), 4); + ASSERT_EQ(cregex_captures(&re), 3); csview cap[5]; ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap), CREG_OK); @@ -273,7 +273,7 @@ CTEST(cregex, replace) // Compile RE separately re = cregex_from(pattern); - ASSERT_EQ(cregex_captures(&re), 4); + ASSERT_EQ(cregex_captures(&re), 3); // European date format. cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); diff --git a/src/libstc.c b/src/libstc.c new file mode 100644 index 00000000..bc61e37c --- /dev/null +++ b/src/libstc.c @@ -0,0 +1,4 @@ +#define i_extern +#include "../include/stc/cregex.h" +#define i_implement +#include "../include/stc/csview.h" -- cgit v1.2.3 From f80a78239f545d7d73c8358056dd5d5825ccfe0b Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Tue, 23 May 2023 14:33:24 +0200 Subject: Updated docs to reflect changes in cstr linking shared. --- README.md | 4 ++-- docs/carc_api.md | 1 + docs/ccommon_api.md | 1 + docs/cmap_api.md | 4 ++++ docs/crandom_api.md | 1 + docs/cset_api.md | 1 + docs/csmap_api.md | 4 +++- docs/csset_api.md | 1 + docs/cstr_api.md | 1 + docs/csview_api.md | 26 ++++++++++++++------------ docs/cvec_api.md | 2 ++ include/stc/carc.h | 1 + include/stc/cbox.h | 1 + include/stc/csmap.h | 1 + include/stc/cvec.h | 1 + misc/benchmarks/various/sso_bench.cpp | 1 + 16 files changed, 36 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index d699e1d1..e63a56e4 100644 --- a/README.md +++ b/README.md @@ -352,10 +352,10 @@ It is possible to generate single headers by executing the python script `src/si Conveniently, `src\libstc.c` implements non-templated functions as shared symbols for **cstr**, **csview**, **cbits** and **crand**. When building in shared mode (-DSTC_HEADER), you may include this file in your project, -or define your own as descibed above. +or define your own, e.g.: ```c // stc_libs.c -#define STC_IMPLEMENT +#define STC_IMPLEMENT // implement all the following as shared objects #include #include "Point.h" diff --git a/docs/carc_api.md b/docs/carc_api.md index 48b64ff0..9f3d8cb9 100644 --- a/docs/carc_api.md +++ b/docs/carc_api.md @@ -78,6 +78,7 @@ bool carc_X_value_eq(const i_val* x, const i_val* y); // Create two stacks with carcs to maps. // Demonstrate sharing and cloning of maps. // Show elements dropped. +#define i_implement #include #define i_type Map diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 56424989..cdd4ec87 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -470,6 +470,7 @@ return ok; **Example 2**: Load each line of a text file into a vector of strings: ```c #include +#define i_implement #include #define i_val_str diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 2c9ac8ed..69e547a0 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -114,6 +114,7 @@ bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // ! ## Examples ```c +#define i_implement #include #define i_key_str @@ -157,6 +158,7 @@ The HEX of color BLACK is:[#000000] ### Example 2 This example uses a cmap with cstr as mapped value. ```c +#define i_implement #include #define i_type IDMap #define i_key int @@ -267,6 +269,7 @@ Output: ### Example 5: Advanced Key type is struct. ```c +#define i_implement #include typedef struct { @@ -335,6 +338,7 @@ In example 5 we needed to construct a lookup key which allocated strings, and th In this example we use rawtype feature to make it even simpler to use. Note that we must use the emplace() methods to add "raw" type entries (otherwise compile error): ```c +#define i_implement #include typedef struct Viking { diff --git a/docs/crandom_api.md b/docs/crandom_api.md index 7281b2d7..74e23a6a 100644 --- a/docs/crandom_api.md +++ b/docs/crandom_api.md @@ -67,6 +67,7 @@ double crand_norm(crand_t* rng, crand_norm_t* dist); ```c #include #include +#define i_implement #include // Declare int -> int sorted map. Uses typetag 'i' for ints. diff --git a/docs/cset_api.md b/docs/cset_api.md index 7243beb3..ecf87e5b 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -77,6 +77,7 @@ cset_X_value cset_X_value_clone(cset_X_value val); ## Example ```c +#define i_implement #include #define i_type Strset #define i_key_str diff --git a/docs/csmap_api.md b/docs/csmap_api.md index b1bb07c6..2fd9f6a5 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -102,8 +102,8 @@ void csmap_X_value_drop(csmap_X_value* pval); ## Examples ```c +#define i_implement #include - #define i_key_str // special macro for i_key = cstr, i_tag = str #define i_val_str // ditto #include @@ -150,6 +150,7 @@ Translate a [ [Run this code](https://godbolt.org/z/9d1PP77Pa) ] ```c +#define i_implement #include #define i_type strmap #define i_key_str @@ -182,6 +183,7 @@ int main() ### Example 3 This example uses a csmap with cstr as mapped value. ```c +#define i_implement #include #define i_type IDSMap diff --git a/docs/csset_api.md b/docs/csset_api.md index dafe6670..5695ecf6 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -76,6 +76,7 @@ csset_X_value csset_X_value_clone(csset_X_value val); ## Example ```c +#define i_implement #include #define i_type SSet diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 64ad002c..438dbf27 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -157,6 +157,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt ## Example ```c +#define i_implement #include int main() { diff --git a/docs/csview_api.md b/docs/csview_api.md index ec3bf121..b697b7d6 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -20,8 +20,9 @@ description. All csview definitions and prototypes are available by including a single header file. ```c -#include // optional, include cstr+csview functionality -#include +#define i_implement +#include +#include // after cstr.h: include extra cstr-csview functions ``` ## Methods @@ -116,23 +117,24 @@ uint64_t csview_hash(const csview* x); ## Example ```c +#define i_implement #include #include int main () { cstr str1 = cstr_lit("We think in generalities, but we live in details."); - // (quoting Alfred N. Whitehead) + // (quoting Alfred N. Whitehead) - csview sv1 = cstr_substr(&str1, 3, 5); // "think" - intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 - csview sv2 = cstr_substr(&str1, pos, 4); // get "live" - csview sv3 = cstr_slice(&str1, -8, -1); // get "details" + csview sv1 = cstr_substr_ex(&str1, 3, 5); // "think" + intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 + csview sv2 = cstr_substr_ex(&str1, pos, 4); // get "live" + csview sv3 = cstr_slice_ex(&str1, -8, -1); // get "details" printf("%.*s %.*s %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); cstr s1 = cstr_lit("Apples are red"); - cstr s2 = cstr_from_sv(cstr_substr(&s1, -3, 3)); // "red" - cstr s3 = cstr_from_sv(cstr_substr(&s1, 0, 6)); // "Apples" + cstr s2 = cstr_from_sv(cstr_substr_ex(&s1, -3, 3)); // "red" + cstr s3 = cstr_from_sv(cstr_substr_ex(&s1, 0, 6)); // "Apples" printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); c_drop(cstr, &str1, &s1, &s2, &s3); @@ -146,8 +148,8 @@ red Apples ### Example 2: UTF8 handling ```c -#include -#include +#define i_extern +#include // i_extern: implement cstr + dependencies (utf8) int main() { @@ -181,7 +183,7 @@ void print_split(csview input, const char* sep) printf("[%.*s]\n", c_SV(i.token)); puts(""); } - +#define i_implement #include #define i_val_str #include diff --git a/docs/cvec_api.md b/docs/cvec_api.md index 841321b2..fa7bf8ca 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -148,6 +148,7 @@ sorted: 5 7 8 13 16 25 ``` ### Example 2 ```c +#define i_implement #include #define i_val_str @@ -184,6 +185,7 @@ item: 2 elements so far Container with elements of structs: ```c +#define i_implement #include typedef struct { diff --git a/include/stc/carc.h b/include/stc/carc.h index 74205caf..756b604f 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -22,6 +22,7 @@ */ /* carc: atomic reference counted shared_ptr +#define i_implement #include typedef struct { cstr name, last; } Person; diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 393b904b..699b32ac 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -23,6 +23,7 @@ */ /* cbox: heap allocated boxed type +#define i_implement #include typedef struct { cstr name, email; } Person; diff --git a/include/stc/csmap.h b/include/stc/csmap.h index fbfea8dd..e8138926 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -24,6 +24,7 @@ // Sorted/Ordered set and map - implemented as an AA-tree. /* #include +#define i_implement #include #define i_tag sx // Sorted map diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 1a0fb118..512dbf67 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -22,6 +22,7 @@ */ /* +#define i_implement #include #include diff --git a/misc/benchmarks/various/sso_bench.cpp b/misc/benchmarks/various/sso_bench.cpp index 71d123e8..6d3d107a 100644 --- a/misc/benchmarks/various/sso_bench.cpp +++ b/misc/benchmarks/various/sso_bench.cpp @@ -3,6 +3,7 @@ #include #include +#define i_static #include #define i_type StcVec -- cgit v1.2.3 From b1bbd0564a0d8d43172a654b51ff28bb62e0979a Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 23 May 2023 22:44:33 +0200 Subject: Some house holding cleanup. --- docs/ccommon_api.md | 2 +- include/stc/cbits.h | 4 ++-- include/stc/ccommon.h | 4 ++-- include/stc/cregex.h | 1 - include/stc/cstack.h | 16 +++++----------- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index cdd4ec87..5f6c82ed 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -40,7 +40,7 @@ c_forpair (id, count, csmap_ii, map) ``` ### c_forlist -Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element. +Iterate compound literal array elements. Additional to `i.ref`, you can access `i.size` and `i.index` for the input list/element. ```c // apply multiple push_backs c_forlist (i, int, {1, 2, 3}) diff --git a/include/stc/cbits.h b/include/stc/cbits.h index cf13790a..fe422202 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -198,7 +198,7 @@ STC_INLINE cbits cbits_with_pattern(const int64_t size, const uint64_t pattern) typedef struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } i_type; -STC_INLINE i_type _i_memb(_init)(void) { return c_LITERAL(i_type){0}; } +STC_INLINE void _i_memb(_init)(i_type* self) { memset(self->data64, 0, i_capacity*8); } STC_INLINE void _i_memb(_drop)(i_type* self) {} STC_INLINE int64_t _i_memb(_size)(const i_type* self) { return i_capacity; } STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; } @@ -211,7 +211,7 @@ STC_INLINE i_type _i_memb(_clone)(i_type other) STC_INLINE i_type* _i_memb(_copy)(i_type* self, const i_type* other) { *self = *other; return self; } - + STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value); STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern); diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index eb3a6601..01ead57a 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -217,8 +217,8 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { #else #include #define c_forlist(it, T, ...) \ - for (struct {std::initializer_list _il; std::initializer_list::iterator data, ref; size_t size, index;} \ - it = {._il=__VA_ARGS__, .data=it._il.begin(), .ref=it.data, .size=it._il.size()} \ + for (struct {std::initializer_list _il; std::initializer_list::iterator ref; size_t size, index;} \ + it = {._il=__VA_ARGS__, .ref=it._il.begin(), .size=it._il.size()} \ ; it.index < it.size; ++it.ref, ++it.index) #endif diff --git a/include/stc/cregex.h b/include/stc/cregex.h index bf239ff6..919f5474 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -53,7 +53,6 @@ enum { typedef enum { CREG_OK = 0, - CREG_SUCCESS = 0, /* [deprecated] */ CREG_NOMATCH = -1, CREG_MATCHERROR = -2, CREG_OUTOFMEMORY = -3, diff --git a/include/stc/cstack.h b/include/stc/cstack.h index ae8b3c40..fa0fab2b 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -41,20 +41,14 @@ #endif typedef i_keyraw _cx_raw; -STC_INLINE _cx_self _cx_memb(_init)(void) { - _cx_self cx; cx._len = 0; -#ifndef i_capacity - cx._cap = 0; cx.data = NULL; -#endif - return cx; -} - #ifdef i_capacity -STC_INLINE void _cx_memb(_create)(_cx_self* self) +STC_INLINE void _cx_memb(_init)(_cx_self* self) { self->_len = 0; } #else -STC_INLINE void _cx_memb(_create)(_cx_self* self) - { self->_len = 0; self->_cap = 0; self->data = NULL; } +STC_INLINE _cx_self _cx_memb(_init)(void) { + _cx_self out = {0}; + return out; +} STC_INLINE _cx_self _cx_memb(_with_capacity)(intptr_t cap) { _cx_self out = {(_cx_value *) i_malloc(cap*c_sizeof(i_key)), 0, cap}; -- cgit v1.2.3 From 00150a367c1e50c6b68ab878043beb6c1c8baa02 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 24 May 2023 13:18:27 +0200 Subject: Fixes for clang compiler. --- include/stc/algo/raii.h | 2 +- include/stc/priv/template2.h | 2 +- misc/examples/csset_erase.c | 2 +- misc/examples/make.sh | 16 ++++++++-------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/stc/algo/raii.h b/include/stc/algo/raii.h index 7b1b445b..b0008a96 100644 --- a/include/stc/algo/raii.h +++ b/include/stc/algo/raii.h @@ -51,4 +51,4 @@ c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \ (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a))) -#endif \ No newline at end of file +#endif diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 66ed7739..d7588ca0 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -79,4 +79,4 @@ #undef _i_has_eq #undef _i_has_cmp #undef _i_template -#endif \ No newline at end of file +#endif diff --git a/misc/examples/csset_erase.c b/misc/examples/csset_erase.c index 5fe3fcba..649bb1e3 100644 --- a/misc/examples/csset_erase.c +++ b/misc/examples/csset_erase.c @@ -38,4 +38,4 @@ int main() puts(""); csset_int_drop(&set); -} \ No newline at end of file +} diff --git a/misc/examples/make.sh b/misc/examples/make.sh index 25b720b8..5c81c4d3 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -7,14 +7,14 @@ if [ "$(uname)" = 'Linux' ]; then fi cc=gcc; cflags="-DSTC_STATIC -s -O3 -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized -Wno-missing-field-initializers" -#cc=gcc; cflags="-g -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" -#cc=tcc; cflags="-Wall -std=c99" -#cc=clang; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall -Wno-unused-function -Wsign-compare -Wwrite-strings" -#cc=gcc; cflags="-x c++ -s -O2 -Wall -std=c++20" -#cc=g++; cflags="-x c++ -s -O2 -Wall" -#cc=cl; cflags="-O2 -nologo -W3 -MD" -#cc=cl; cflags="-nologo -TP" -#cc=cl; cflags="-nologo -std:c11" +#cc=gcc; cflags="-DSTC_STATIC -g -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" +#cc=tcc; cflags="-DSTC_STATIC -Wall -std=c99" +#cc=clang; cflags="-DSTC_STATIC -s -O3 -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -Wno-missing-field-initializers" +#cc=gcc; cflags="-DSTC_STATIC -x c++ -s -O2 -Wall -std=c++20" +#cc=g++; cflags="-DSTC_STATIC -x c++ -s -O2 -Wall" +#cc=cl; cflags="-DSTC_STATIC -O2 -nologo -W3 -MD" +#cc=cl; cflags="-DSTC_STATIC -nologo -TP" +#cc=cl; cflags="-DSTC_STATIC -nologo -std:c11" if [ "$cc" = "cl" ]; then oflag='/Fe:' -- cgit v1.2.3 From 276b8110033aa275f58ce60d096f220ca050738c Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 24 May 2023 16:21:22 +0200 Subject: coroutine.h: - Renamed Liigo's coroutine macro cco(x) => cco_routine(x). - Removed cco_begin(x), cco_end() macros. Replaced by cco_routine(x). - Replaced csleep_ms() with csleep_us(), using select() which is portable. - Updated all coroutine examples. --- docs/ccommon_api.md | 11 +++++----- include/stc/algo/coroutine.h | 49 +++++++++++++++----------------------------- misc/examples/cointerleave.c | 11 +++++----- misc/examples/coread.c | 3 ++- misc/examples/coroutines.c | 14 +++++++------ misc/examples/generator.c | 21 ++++++++++--------- misc/examples/scheduler.c | 10 +++++---- misc/examples/triples.c | 5 +++-- 8 files changed, 58 insertions(+), 66 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 5f6c82ed..beaad7e9 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -321,7 +321,7 @@ struct triples { }; bool triples(struct triples* i) { // coroutine - cco_begin(i); + cco_routine(i) { for (i->c = 5; i->n; ++i->c) { for (i->a = 1; i->a < i->c; ++i->a) { for (i->b = i->a + 1; i->b < i->c; ++i->b) { @@ -332,9 +332,10 @@ bool triples(struct triples* i) { // coroutine } } } - cco_final: // tear down + cco_final: puts("done"); - cco_end(true); + } + return true; } int gcd(int a, int b) { // greatest common denominator @@ -374,9 +375,7 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_return` | Early return from the coroutine (no arg) | | `bool` | `cco_suspended(co)` | Is coroutine in suspended state? | | `bool` | `cco_done(co)` | Is coroutine done? | -| | `cco_begin(co)` | Begin coroutine block | -| | `cco_end()` | End coroutine block | -| | `cco_end(ret)` | End coroutine block and return ret | +| | `cco_routine(co) { ... }` | The coroutine closure | | | `cco_yield()` | Yield/suspend execution | | | `cco_yield(ret)` | Yield/suspend execution and return ret | | | `cco_yield_coro(co, call)` | Yield at co call if it is suspended | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 78dc80c6..ebfed613 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -26,31 +26,32 @@ #include #include -struct coroutine { +struct iterpair { int max_x, max_y; int x, y; int cco_state; // required member }; -bool coroutine(struct coroutine* I) { - cco_begin(I); +bool iterpair(struct iterpair* I) { + cco_routine(I) { for (I->x = 0; I->x < I->max_x; I->x++) for (I->y = 0; I->y < I->max_y; I->y++) cco_yield(false); - cco_final: // required if there is cleanup code + cco_final: // required if there is cleanup code puts("final"); - cco_end(true); + } + return true; // finished } int main(void) { - struct coroutine it = {.max_x=3, .max_y=3}; + struct iterpair it = {.max_x=3, .max_y=3}; int n = 0; - while (!coroutine(&it)) + while (!iterpair(&it)) { printf("%d %d\n", it.x, it.y); // example of early stop: - if (++n == 7) cco_stop(&it); // signal to stop at next + if (++n == 7) cco_stop(&it); // signal to stop/finalize in next } return 0; } @@ -66,19 +67,9 @@ enum { #define cco_suspended(co) ((co)->cco_state > 0) #define cco_done(co) ((co)->cco_state == cco_state_done) -#define cco_begin(co) \ - int *_state = &(co)->cco_state; \ - goto _begin; _begin: switch (*_state) { \ - case 0: - -#define cco_end(ret) \ - } \ - *_state = cco_state_done; \ - return ret - -#define cco(co) \ +#define cco_routine(co) \ for (int *_state = &(co)->cco_state, _once=1; _once; *_state = cco_state_done, _once=0) \ - _begin: switch (*_state) case 0: + _begin: switch (*_state) case 0: // thanks, @liigo! #define cco_yield(ret) \ do { \ @@ -96,7 +87,7 @@ enum { #define cco_await_2(promise, ret) \ do { \ *_state = __LINE__; \ - case __LINE__: if (!(promise)) return ret; \ + case __LINE__: if (!(promise)) {return ret; goto _begin;} \ } while (0) #define cco_await_coro(...) c_MACRO_OVERLOAD(cco_await_coro, __VA_ARGS__) @@ -150,18 +141,12 @@ typedef struct { */ #include +#include -#ifdef _WIN32 - static inline void csleep_ms(long msecs) { - extern void Sleep(unsigned long); - Sleep((unsigned long)msecs); - } -#elif _POSIX_C_SOURCE >= 199309L - static inline void csleep_ms(long msecs) { - struct timespec ts = {msecs/1000, 1000000*(msecs % 1000)}; - nanosleep(&ts, NULL); - } -#endif +static inline void csleep_us(int64_t usec) { + struct timeval tv = {.tv_sec=(int)(usec/1000000), .tv_usec=usec % 1000000}; + select(0, NULL, NULL, NULL, &tv); +} typedef struct { clock_t start; diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index e11b2bf3..42bf1d32 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -1,6 +1,6 @@ // https://www.youtube.com/watch?v=8sEe-4tig_A -#include #include +#include #define i_type IVec #define i_val int #include @@ -13,10 +13,11 @@ struct GenValue { static int get_value(struct GenValue* g) { - cco_begin(g); + cco_routine(g) { for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) cco_yield(*g->it.ref); - cco_end(0); + } + return -1; } struct Generator { @@ -27,13 +28,13 @@ struct Generator { void interleaved(struct Generator* g) { - cco_begin(g); + cco_routine(g) { while (!(cco_done(&g->x) & cco_done(&g->y))) { cco_yield_coro(&g->x, g->value = get_value(&g->x)); cco_yield_coro(&g->y, g->value = get_value(&g->y)); } - cco_end(); + } } void Use(void) diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 1976231f..ef6cd6ee 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -1,3 +1,4 @@ +#define i_static #include #include #include @@ -13,7 +14,7 @@ struct file_read { void file_read(struct file_read* g) { - cco(g) { + cco_routine(g) { g->fp = fopen(g->filename, "r"); g->line = cstr_init(); diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index a7136993..040b8472 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -19,7 +19,7 @@ struct prime { }; bool prime(struct prime* g) { - cco_begin(g); + cco_routine(g) { if (g->result < 2) g->result = 2; if (g->result == 2) { if (g->count-- == 0) cco_return; @@ -37,7 +37,8 @@ bool prime(struct prime* g) { } cco_final: printf("final prm\n"); - cco_end(true); + } + return true; } @@ -52,7 +53,7 @@ struct fibonacci { bool fibonacci(struct fibonacci* g) { assert(g->count < 94); - cco_begin(g); + cco_routine(g) { g->idx = 0; g->result = 0; g->b = 1; @@ -69,7 +70,8 @@ bool fibonacci(struct fibonacci* g) { } cco_final: printf("final fib\n"); - cco_end(true); + } + return true; } // Combine @@ -82,7 +84,7 @@ struct combined { void combined(struct combined* g) { - cco_begin(g); + cco_routine(g) { cco_await(prime(&g->prm)); cco_await(fibonacci(&g->fib)); @@ -93,7 +95,7 @@ void combined(struct combined* g) { cco_final: puts("final combined"); - cco_end(); + } } int main(void) diff --git a/misc/examples/generator.c b/misc/examples/generator.c index 41dffafb..6b4b8407 100644 --- a/misc/examples/generator.c +++ b/misc/examples/generator.c @@ -15,13 +15,14 @@ typedef struct { } Triple_iter; void Triple_next(Triple_iter* it) { - Triple_value* t = it->ref; - cco_begin(it); - for (t->c = 5; t->size; ++t->c) { - for (t->a = 1; t->a < t->c; ++t->a) { - for (t->b = t->a; t->b < t->c; ++t->b) { - if (t->a*t->a + t->b*t->b == t->c*t->c) { - if (it->count++ == t->size) + Triple_value* g = it->ref; + cco_routine(it) + { + for (g->c = 5; g->size; ++g->c) { + for (g->a = 1; g->a < g->c; ++g->a) { + for (g->b = g->a; g->b < g->c; ++g->b) { + if (g->a*g->a + g->b*g->b == g->c*g->c) { + if (it->count++ == g->size) cco_return; cco_yield(); } @@ -30,11 +31,11 @@ void Triple_next(Triple_iter* it) { } cco_final: it->ref = NULL; - cco_end(); + } } -Triple_iter Triple_begin(Triple* t) { - Triple_iter it = {.ref=t}; +Triple_iter Triple_begin(Triple* g) { + Triple_iter it = {.ref=g}; Triple_next(&it); return it; } diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index 14c85f56..ea1414c7 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -34,7 +34,7 @@ static bool push_task(const struct Task* task) static bool taskA(struct Task* task) { - cco_begin(task); + cco_routine(task) { puts("Hello, from task A"); cco_yield(push_task(task)); puts("A is back doing work"); @@ -42,18 +42,20 @@ static bool taskA(struct Task* task) puts("A is back doing more work"); cco_yield(push_task(task)); puts("A is back doing even more work"); - cco_end(true); + } + return true; } static bool taskB(struct Task* task) { - cco_begin(task); + cco_routine(task) { puts("Hello, from task B"); cco_yield(push_task(task)); puts("B is back doing work"); cco_yield(push_task(task)); puts("B is back doing more work"); - cco_end(true); + } + return true; } void Use(void) diff --git a/misc/examples/triples.c b/misc/examples/triples.c index 183b7389..06142916 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -33,7 +33,7 @@ struct triples { }; bool triples_coro(struct triples* t) { - cco_begin(t); + cco_routine(t) { t->count = 0; for (t->c = 5; t->size; ++t->c) { for (t->a = 1; t->a < t->c; ++t->a) { @@ -48,7 +48,8 @@ bool triples_coro(struct triples* t) { } cco_final: puts("done"); - cco_end(true); + } + return true; } int main() -- cgit v1.2.3 From c3e01470f45f19215fac339302d87b5d73a323e8 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 24 May 2023 19:47:16 +0200 Subject: More coro adjustments. --- include/stc/algo/coroutine.h | 17 +++++++++++------ include/stc/csview.h | 31 +++++++++++++++---------------- misc/examples/make.sh | 17 ++++++++--------- misc/examples/prime.c | 4 ++-- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index ebfed613..fdce2629 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -141,12 +141,17 @@ typedef struct { */ #include -#include - -static inline void csleep_us(int64_t usec) { - struct timeval tv = {.tv_sec=(int)(usec/1000000), .tv_usec=usec % 1000000}; - select(0, NULL, NULL, NULL, &tv); -} +#if defined _WIN32 && !defined __GNUC__ + static inline void csleep_ms(long msec) { + extern void Sleep(unsigned long); + Sleep((unsigned long)msec); + } +#else + static inline void csleep_ms(long msec) { + struct timespec ts = {msec/1000, 1000000*(msec % 1000)}; + nanosleep(&ts, NULL); + } +#endif typedef struct { clock_t start; diff --git a/include/stc/csview.h b/include/stc/csview.h index 571bb278..e8a3ad9b 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -33,7 +33,12 @@ #define csview_lit(literal) c_sv_1(literal) #define csview_from_n(str, n) c_sv_2(str, n) -STC_API intptr_t csview_find_sv(csview sv, csview search); +STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); +STC_API intptr_t csview_find_sv(csview sv, csview search); +STC_API uint64_t csview_hash(const csview *self); +STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); +STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); +STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); STC_INLINE csview csview_from(const char* str) { return c_LITERAL(csview){str, c_strlen(str)}; } @@ -87,15 +92,6 @@ STC_INLINE void csview_next(csview_iter* it) { it->u8.chr.size = utf8_chr_size(it->ref); if (it->ref == it->u8.end) it->ref = NULL; } -STC_INLINE csview_iter csview_advance(csview_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (it.ref == it.u8.end) it.ref = NULL; - return it; -} - /* utf8 */ STC_INLINE intptr_t csview_u8_size(csview sv) @@ -110,10 +106,6 @@ STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c { return utf8_valid_n(sv.str, sv.size); } -STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); -STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); -STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); - #define c_fortoken_sv(it, inputsv, sep) \ for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \ it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \ @@ -155,11 +147,18 @@ STC_INLINE int csview_icmp(const csview* x, const csview* y) STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } -STC_API uint64_t csview_hash(const csview *self); - /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) +STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (it.ref == it.u8.end) it.ref = NULL; + return it; +} + STC_DEF intptr_t csview_find_sv(csview sv, csview search) { char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); return res ? (res - sv.str) : c_NPOS; diff --git a/misc/examples/make.sh b/misc/examples/make.sh index 5c81c4d3..d58ed0cb 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -6,15 +6,14 @@ if [ "$(uname)" = 'Linux' ]; then oflag='-o ' fi -cc=gcc; cflags="-DSTC_STATIC -s -O3 -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized -Wno-missing-field-initializers" -#cc=gcc; cflags="-DSTC_STATIC -g -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" -#cc=tcc; cflags="-DSTC_STATIC -Wall -std=c99" -#cc=clang; cflags="-DSTC_STATIC -s -O3 -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -Wno-missing-field-initializers" -#cc=gcc; cflags="-DSTC_STATIC -x c++ -s -O2 -Wall -std=c++20" -#cc=g++; cflags="-DSTC_STATIC -x c++ -s -O2 -Wall" -#cc=cl; cflags="-DSTC_STATIC -O2 -nologo -W3 -MD" -#cc=cl; cflags="-DSTC_STATIC -nologo -TP" -#cc=cl; cflags="-DSTC_STATIC -nologo -std:c11" +cc=gcc; cflags="-DSTC_STATIC -std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-implicit-fallthrough -Wno-missing-field-initializers" +#cc=gcc; cflags="-DSTC_STATIC -std=c99 -g -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" +#cc=tcc; cflags="-DSTC_STATIC -std=c99 -Wall" +#cc=clang; cflags="-DSTC_STATIC -std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -Wno-missing-field-initializers" +#cc=gcc; cflags="-DSTC_STATIC -x c++ -std=c++20 -O2 -s -Wall" +#cc=cl; cflags="-DSTC_STATIC -nologo -O2 -MD -W3 -wd4003" +#cc=cl; cflags="-DSTC_STATIC -nologo -TP -wd4003" +#cc=cl; cflags="-DSTC_STATIC -nologo -std:c11 -wd4003" if [ "$cc" = "cl" ]; then oflag='/Fe:' diff --git a/misc/examples/prime.c b/misc/examples/prime.c index 7efa26ff..cb0f8926 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -32,9 +32,8 @@ int main(void) clock_t t = clock(); cbits primes = sieveOfEratosthenes(n + 1); int np = (int)cbits_count(&primes); - t = t - clock(); + t = clock() - t; - printf("Number of primes: %d, time: %f\n\n", np, (double)t/CLOCKS_PER_SEC); puts("Show all the primes in the range [2, 1000):"); printf("2"); c_forrange (i, 3, 1000, 2) @@ -49,6 +48,7 @@ int main(void) printf("%lld ", *i.ref); if (c_flt_getcount(i) % 10 == 0) puts(""); } + printf("Number of primes: %d, time: %.2f\n\n", np, (double)t/CLOCKS_PER_SEC); cbits_drop(&primes); } -- cgit v1.2.3 From 3f840ffe1c9d2df998e1cbcf6c87ea72fe23f97e Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 24 May 2023 22:19:26 +0200 Subject: Fixed portability for csleep_ms() function. --- include/stc/algo/coroutine.h | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index fdce2629..2e992e55 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -56,6 +56,7 @@ int main(void) { return 0; } */ +#include #include enum { @@ -140,34 +141,34 @@ typedef struct { * Timer */ -#include -#if defined _WIN32 && !defined __GNUC__ - static inline void csleep_ms(long msec) { - extern void Sleep(unsigned long); - Sleep((unsigned long)msec); - } -#else - static inline void csleep_ms(long msec) { - struct timespec ts = {msec/1000, 1000000*(msec % 1000)}; - nanosleep(&ts, NULL); - } -#endif - typedef struct { clock_t start; clock_t interval; } ctimer; #define cco_await_timer(...) c_MACRO_OVERLOAD(cco_await_timer, __VA_ARGS__) -#define cco_await_timer_2(tm, msecs) cco_await_timer_3(tm, msecs, ) -#define cco_await_timer_3(tm, msecs, ret) \ +#define cco_await_timer_2(tm, msec) cco_await_timer_3(tm, msec, ) +#define cco_await_timer_3(tm, msec, ret) \ do { \ - ctimer_start(tm, msecs); \ + ctimer_start(tm, msec); \ cco_await_2(ctimer_expired(tm), ret); \ } while (0) -static inline void ctimer_start(ctimer* tm, long msecs) { - tm->interval = msecs*(CLOCKS_PER_SEC/1000); +#if defined _WIN32 + static inline void csleep_ms(long msec) { + extern void Sleep(unsigned long); + Sleep((unsigned long)msec); + } +#else + #include + static inline void csleep_ms(long msec) { + struct timeval tv = {.tv_sec=msec/1000, .tv_usec=1000*(msec % 1000)}; + select(0, NULL, NULL, NULL, &tv); + } +#endif + +static inline void ctimer_start(ctimer* tm, long msec) { + tm->interval = msec*(CLOCKS_PER_SEC/1000); tm->start = clock(); } -- cgit v1.2.3 From 8497b5497ecba2c2f1d368c9161ec52d4f03ae30 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 26 May 2023 19:36:27 +0200 Subject: Minor addition to coroutine API. --- include/stc/algo/coroutine.h | 6 ++++++ misc/examples/coread.c | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 2e992e55..c786eb51 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -65,6 +65,7 @@ enum { }; #define cco_initial(co) ((co)->cco_state == 0) +#define cco_active(co) ((co)->cco_state >= 0) #define cco_suspended(co) ((co)->cco_state > 0) #define cco_done(co) ((co)->cco_state == cco_state_done) @@ -172,6 +173,11 @@ static inline void ctimer_start(ctimer* tm, long msec) { tm->start = clock(); } +static inline ctimer ctimer_with(long msec) { + ctimer tm = {msec*(CLOCKS_PER_SEC/1000), clock()}; + return tm; +} + static inline void ctimer_restart(ctimer* tm) { tm->start = clock(); } diff --git a/misc/examples/coread.c b/misc/examples/coread.c index ef6cd6ee..2585fb81 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -16,6 +16,7 @@ void file_read(struct file_read* g) { cco_routine(g) { g->fp = fopen(g->filename, "r"); + if (!g->fp) cco_return; g->line = cstr_init(); cco_await(!cstr_getline(&g->line, g->fp)); @@ -23,9 +24,8 @@ void file_read(struct file_read* g) cco_final: printf("finish\n"); cstr_drop(&g->line); - fclose(g->fp); + if (g->fp) fclose(g->fp); } - return; } int main(void) -- cgit v1.2.3 From 80df921622c97634aeea31821a61f46885324d9c Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 29 May 2023 20:42:43 +0200 Subject: Update extern benchmark maps. Removed i_expandby in cmap. Always expand by 2 i.e 2^n buckets.. --- include/stc/cmap.h | 22 ++++------------------ misc/benchmarks/external/ankerl/unordered_dense.h | 6 +++--- misc/benchmarks/external/emhash/hash_table7.hpp | 2 +- misc/examples/scheduler.c | 6 +++--- 4 files changed, 11 insertions(+), 25 deletions(-) diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 4ba6156b..837631f8 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -265,18 +265,7 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { #ifndef i_max_load_factor #define i_max_load_factor 0.80f #endif -#ifndef i_expandby - #define i_expandby 2 -#endif - -#ifndef CMAP_H_INCLUDED -STC_INLINE intptr_t fastrange_1(uint64_t x, uint64_t n) - { return (intptr_t)((uint32_t)x*n >> 32); } // n < 2^32 - -STC_INLINE intptr_t fastrange_2(uint64_t x, uint64_t n) - { return (intptr_t)(x & (n - 1)); } // n power of 2. - -#endif // CMAP_H_INCLUDED +#define fastrange_2(x, n) (intptr_t)((x) & (size_t)((n) - 1)) // n power of 2. STC_DEF _cx_iter _cx_memb(_begin)(const _cx_self* self) { _cx_iter it = {self->data, self->data+self->bucket_count, self->slot}; @@ -356,7 +345,7 @@ STC_DEF chash_bucket _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); intptr_t _cap = self->bucket_count; - chash_bucket b = {c_PASTE(fastrange_,i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; + chash_bucket b = {fastrange_2(_hash, _cap), (uint8_t)(_hash | 0x80)}; const chash_slot* s = self->slot; while (s[b.idx].hashx) { if (s[b.idx].hashx == b.hashx) { @@ -413,10 +402,8 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { const intptr_t _oldbucks = self->bucket_count; if (_newcap != self->size && _newcap <= _oldbucks) return true; - intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) | 1; - #if i_expandby == 2 + intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4; _newbucks = cnextpow2(_newbucks); - #endif _cx_self m = { (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), (chash_slot *)i_calloc(_newbucks + 1, sizeof(chash_slot)), @@ -452,7 +439,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { if (! s[j].hashx) break; const _cx_keyraw _raw = i_keyto(_i_keyref(d + j)); - k = (intptr_t)c_PASTE(fastrange_,i_expandby)(i_hash((&_raw)), (uint64_t)_cap); + k = fastrange_2(i_hash((&_raw)), _cap); if ((j < i) ^ (k <= i) ^ (k > j)) { // is k outside (i, j]? d[i] = d[j]; s[i] = s[j]; @@ -464,7 +451,6 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { } #endif // i_implement #undef i_max_load_factor -#undef i_expandby #undef _i_isset #undef _i_ismap #undef _i_keyref diff --git a/misc/benchmarks/external/ankerl/unordered_dense.h b/misc/benchmarks/external/ankerl/unordered_dense.h index dc4de8ab..b8cacea7 100644 --- a/misc/benchmarks/external/ankerl/unordered_dense.h +++ b/misc/benchmarks/external/ankerl/unordered_dense.h @@ -1,7 +1,7 @@ ///////////////////////// ankerl::unordered_dense::{map, set} ///////////////////////// // A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion. -// Version 4.0.0 +// Version 4.0.1 // https://github.com/martinus/unordered_dense // // Licensed under the MIT License . @@ -32,7 +32,7 @@ // see https://semver.org/spec/v2.0.0.html #define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 4 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes #define ANKERL_UNORDERED_DENSE_VERSION_MINOR 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality -#define ANKERL_UNORDERED_DENSE_VERSION_PATCH 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes +#define ANKERL_UNORDERED_DENSE_VERSION_PATCH 1 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes // API versioning with inline namespace, see https://www.foonathan.net/2018/11/inline-namespaces/ @@ -1907,7 +1907,7 @@ auto erase_if(ankerl::unordered_dense::detail::table +#include static bool schedule(Scheduler* sched) { struct Task task = *Scheduler_front(sched); - Scheduler_pop_front(sched); + Scheduler_pop(sched); if (!cco_done(&task)) task.resume(&task); @@ -27,7 +27,7 @@ static bool schedule(Scheduler* sched) static bool push_task(const struct Task* task) { - Scheduler_push_back(task->sched, *task); + Scheduler_push(task->sched, *task); return false; } -- cgit v1.2.3 From 7dd28530c93b907cc26064232c5498e45e838723 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 30 May 2023 20:23:09 +0200 Subject: Changed extern to dllimport for Sleep() function. --- include/stc/algo/coroutine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index c786eb51..7f2e1244 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -157,7 +157,7 @@ typedef struct { #if defined _WIN32 static inline void csleep_ms(long msec) { - extern void Sleep(unsigned long); + __declspec(dllimport) void Sleep(unsigned long); Sleep((unsigned long)msec); } #else -- cgit v1.2.3 From c23a90112ffc50ed5977874ec31cf4fd3d4afd9b Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 31 May 2023 17:38:49 +0200 Subject: Simplified coroutine API. Removed unneeded cco_await_coro() and cco_yield_coro(). --- docs/ccommon_api.md | 5 ----- include/stc/algo/coroutine.h | 11 ----------- misc/examples/cointerleave.c | 14 +++++++++----- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index beaad7e9..fc4f196b 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -373,17 +373,12 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c |:----------|:-------------------------------------|:----------------------------------------| | | `cco_final:` | Label for cleanup in coroutine | | | `cco_return` | Early return from the coroutine (no arg) | -| `bool` | `cco_suspended(co)` | Is coroutine in suspended state? | | `bool` | `cco_done(co)` | Is coroutine done? | | | `cco_routine(co) { ... }` | The coroutine closure | | | `cco_yield()` | Yield/suspend execution | | | `cco_yield(ret)` | Yield/suspend execution and return ret | -| | `cco_yield_coro(co, call)` | Yield at co call if it is suspended | -| | `cco_yield_coro(co, call, ret)` | Yield at co call with ret if suspended | | | `cco_await(promise)` | Await/suspend until promise is true | | | `cco_await(promise, ret)` | Await/suspend with ret value | -| | `cco_await_coro(co, call)` | Await for co call to finish | -| | `cco_await_coro(co, call, ret)` | Await for co call to finish with ret | | | Semaphores: | | | | `csem` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 7f2e1244..486f6e23 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -65,8 +65,6 @@ enum { }; #define cco_initial(co) ((co)->cco_state == 0) -#define cco_active(co) ((co)->cco_state >= 0) -#define cco_suspended(co) ((co)->cco_state > 0) #define cco_done(co) ((co)->cco_state == cco_state_done) #define cco_routine(co) \ @@ -79,11 +77,6 @@ enum { case __LINE__:; \ } while (0) -#define cco_yield_coro(...) c_MACRO_OVERLOAD(cco_yield_coro, __VA_ARGS__) -#define cco_yield_coro_2(co, call) cco_yield_coro_3(co, call, ) -#define cco_yield_coro_3(co, call, ret) \ - do { call; if (!cco_done(co)) cco_yield(ret); } while (0) - #define cco_await(...) c_MACRO_OVERLOAD(cco_await, __VA_ARGS__) #define cco_await_1(promise) cco_await_2(promise, ) #define cco_await_2(promise, ret) \ @@ -92,10 +85,6 @@ enum { case __LINE__: if (!(promise)) {return ret; goto _begin;} \ } while (0) -#define cco_await_coro(...) c_MACRO_OVERLOAD(cco_await_coro, __VA_ARGS__) -#define cco_await_coro_2(co, call) cco_await_2((call, cco_done(co)), ) -#define cco_await_coro_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) - #define cco_run(co, call) while (call, !cco_done(co)) #define cco_final \ diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 42bf1d32..51b9f39a 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -29,11 +29,15 @@ struct Generator { void interleaved(struct Generator* g) { cco_routine(g) { - while (!(cco_done(&g->x) & cco_done(&g->y))) - { - cco_yield_coro(&g->x, g->value = get_value(&g->x)); - cco_yield_coro(&g->y, g->value = get_value(&g->y)); - } + do { + g->value = get_value(&g->x); + if (!cco_done(&g->x)) + cco_yield(); + + g->value = get_value(&g->y); + if (!cco_done(&g->y)) + cco_yield(); + } while (!(cco_done(&g->x) & cco_done(&g->y))); } } -- cgit v1.2.3 From c82dffc657faedba4c7af75792aa26287d9cf9bc Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 1 Jun 2023 00:14:20 +0200 Subject: Changed API for cco_timer and cco_sem. --- docs/ccommon_api.md | 25 ++++++++++++----------- include/stc/algo/coroutine.h | 47 +++++++++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index fc4f196b..4d18120a 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -379,20 +379,21 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_yield(ret)` | Yield/suspend execution and return ret | | | `cco_await(promise)` | Await/suspend until promise is true | | | `cco_await(promise, ret)` | Await/suspend with ret value | +| | `cco_sleep(long msec)` | Sleep for milliseconds | | | Semaphores: | | -| | `csem` | Semaphore type | -| | `cco_await_sem(sem)` | Await for the semaphore count > 0 | -| | `cco_await_sem(sem, ret)` | Await with ret on the semaphore | -| | `csem_set(sem, long value)` | Set semaphore value | -| | `csem_signal(sem)` | Signal the semaphore | +| | `cco_sem` | Semaphore type | +| | `cco_sem_await(sem)` | Await for the semaphore count > 0 | +| | `cco_sem_await(sem, ret)` | Await with ret on the semaphore | +| cco_sem | `cco_sem_init(long value)` | Set semaphore value | +| | `cco_sem_release(sem)` | Signal the semaphore | | | Timers: | | -| | `ctimer` | Timer type | -| | `cco_await_timer(tm)` | Await for timer to expire | -| | `cco_await_timer(tm, ret)` | Await with ret for timer to expire | -| | `ctimer_start(tm, long msecs)` | Start timer msecs milliseconds | -| | `ctimer_restart(tm)` | Restart timer with same duration | -| `bool` | `ctimer_expired(tm)` | Return true if timer is expired | -| `long` | `ctimer_remaining(tm)` | Return milliseconds remaining | +| | `cco_timer` | Timer type | +| | `cco_timer_await(tm)` | Await for timer to expire | +| | `cco_timer_await(tm, ret)` | Await with ret for timer to expire | +| | `cco_timer_start(tm, long msecs)` | Start timer msecs milliseconds | +| | `cco_timer_restart(tm)` | Restart timer with same duration | +| `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | +| `long` | `cco_timer_remaining(tm)` | Return milliseconds remaining | | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 486f6e23..d3f73229 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -114,18 +114,18 @@ enum { typedef struct { intptr_t count; -} csem; +} cco_sem; -#define cco_await_sem(...) c_MACRO_OVERLOAD(cco_await_sem, __VA_ARGS__) -#define cco_await_sem_1(sem) cco_await_sem_2(sem, ) -#define cco_await_sem_2(sem, ret) \ +#define cco_sem_await(...) c_MACRO_OVERLOAD(cco_sem_await, __VA_ARGS__) +#define cco_sem_await_1(sem) cco_sem_await_2(sem, ) +#define cco_sem_await_2(sem, ret) \ do { \ cco_await_2((sem)->count > 0, ret); \ --(sem)->count; \ } while (0) -#define csem_signal(sem) ++(sem)->count -#define csem_set(sem, value) ((sem)->count = (value)) +#define cco_sem_release(sem) ++(sem)->count +#define cco_sem_with(value) ((cco_sem){value}) /* * Timer @@ -134,48 +134,51 @@ typedef struct { typedef struct { clock_t start; clock_t interval; -} ctimer; +} cco_timer; -#define cco_await_timer(...) c_MACRO_OVERLOAD(cco_await_timer, __VA_ARGS__) -#define cco_await_timer_2(tm, msec) cco_await_timer_3(tm, msec, ) -#define cco_await_timer_3(tm, msec, ret) \ +#define cco_timer_await(...) c_MACRO_OVERLOAD(cco_timer_await, __VA_ARGS__) +#define cco_timer_await_2(tm, msec) cco_timer_await_3(tm, msec, ) +#define cco_timer_await_3(tm, msec, ret) \ do { \ - ctimer_start(tm, msec); \ - cco_await_2(ctimer_expired(tm), ret); \ + cco_timer_start(tm, msec); \ + cco_await_2(cco_timer_expired(tm), ret); \ } while (0) -#if defined _WIN32 - static inline void csleep_ms(long msec) { - __declspec(dllimport) void Sleep(unsigned long); +#ifdef _WIN32 + #ifdef __cplusplus + extern "C" + #endif + __declspec(dllimport) void __stdcall Sleep(unsigned long); + static inline void cco_sleep(long msec) { Sleep((unsigned long)msec); } #else #include - static inline void csleep_ms(long msec) { + static inline void cco_sleep(long msec) { struct timeval tv = {.tv_sec=msec/1000, .tv_usec=1000*(msec % 1000)}; select(0, NULL, NULL, NULL, &tv); } #endif -static inline void ctimer_start(ctimer* tm, long msec) { +static inline void cco_timer_start(cco_timer* tm, long msec) { tm->interval = msec*(CLOCKS_PER_SEC/1000); tm->start = clock(); } -static inline ctimer ctimer_with(long msec) { - ctimer tm = {msec*(CLOCKS_PER_SEC/1000), clock()}; +static inline cco_timer cco_timer_with(long msec) { + cco_timer tm = {msec*(CLOCKS_PER_SEC/1000), clock()}; return tm; } -static inline void ctimer_restart(ctimer* tm) { +static inline void cco_timer_restart(cco_timer* tm) { tm->start = clock(); } -static inline bool ctimer_expired(ctimer* tm) { +static inline bool cco_timer_expired(cco_timer* tm) { return clock() - tm->start >= tm->interval; } -static inline long ctimer_remaining(ctimer* tm) { +static inline long cco_timer_remaining(cco_timer* tm) { return (long)((double)(tm->start + tm->interval - clock())*(1000.0/CLOCKS_PER_SEC)); } -- cgit v1.2.3 From 2d3250d2d35dda415840d8403b7b8957ca40914a Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 4 Jun 2023 22:16:38 +0200 Subject: Added dining_philosophers.c coroutine example. Fixed cco_stop() when in state 0. Renamed cco_timer_with(msec) => cco_timer_from(msec) Renamed cco_sem_with(val) => cco_sem_from(val) --- include/stc/algo/coroutine.h | 15 +++--- misc/examples/dining_philosophers.c | 99 +++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 misc/examples/dining_philosophers.c diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index d3f73229..05307b08 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -98,15 +98,13 @@ enum { #define cco_stop(co) \ do { \ - int* _state = &(co)->cco_state; \ - if (*_state > 0) *_state = cco_state_final; \ + int* _s = &(co)->cco_state; \ + if (*_s > 0) *_s = cco_state_final; \ + else if (*_s == 0) *_s = cco_state_done; \ } while (0) #define cco_reset(co) \ - do { \ - int* _state = &(co)->cco_state; \ - if (*_state == cco_state_done) *_state = 0; \ - } while (0) + (void)((co)->cco_state = 0) /* * Semaphore @@ -125,7 +123,8 @@ typedef struct { } while (0) #define cco_sem_release(sem) ++(sem)->count -#define cco_sem_with(value) ((cco_sem){value}) +#define cco_sem_from(value) ((cco_sem){value}) +#define cco_sem_set(sem, value) ((sem)->count = value) /* * Timer @@ -165,7 +164,7 @@ static inline void cco_timer_start(cco_timer* tm, long msec) { tm->start = clock(); } -static inline cco_timer cco_timer_with(long msec) { +static inline cco_timer cco_timer_from(long msec) { cco_timer tm = {msec*(CLOCKS_PER_SEC/1000), clock()}; return tm; } diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c new file mode 100644 index 00000000..0bf421c6 --- /dev/null +++ b/misc/examples/dining_philosophers.c @@ -0,0 +1,99 @@ +// https://en.wikipedia.org/wiki/Dining_philosophers_problem +#include +#include +#include + +// Define the number of philosophers and forks +enum { + num_philosophers = 5, + num_forks = num_philosophers, +}; + +struct Philosopher { + int id; + cco_timer tm; + cco_sem* left_fork; + cco_sem* right_fork; + int cco_state; // required +}; + +struct Dining { + // Define semaphores for the forks + cco_sem forks[num_forks]; + struct Philosopher ph[num_philosophers]; + int ph_idx; + int cco_state; // required +}; + + +// Philosopher coroutine +void philosopher(struct Philosopher* p) +{ + cco_routine(p) { + while (1) { + int duration = (int)(1000 + crand() % 2000); // 1-3 seconds + printf("Philosopher %d is thinking for %d minutes...\n", p->id, duration/100); + cco_timer_await(&p->tm, duration); + + printf("Philosopher %d is hungry...\n", p->id); + cco_sem_await(p->left_fork); + cco_sem_await(p->right_fork); + + duration = (int)(500 + crand() % 1000); + printf("Philosopher %d is eating for %d minutes...\n", p->id, duration/100); + cco_timer_await(&p->tm, duration); + + cco_sem_release(p->left_fork); + cco_sem_release(p->right_fork); + } + + cco_final: + printf("Philosopher %d finished\n", p->id); + } +} + + +// Dining coroutine +void dining(struct Dining* d) +{ + cco_routine(d) { + for (int i = 0; i < num_forks; ++i) + cco_sem_set(&d->forks[i], 1); // all forks available + for (int i = 0; i < num_philosophers; ++i) { + cco_reset(&d->ph[i]); + d->ph[i].id = i + 1; + d->ph[i].left_fork = &d->forks[i]; + d->ph[i].right_fork = &d->forks[(i + 1) % num_forks]; + } + + while (1) { + for (d->ph_idx = 0; d->ph_idx < num_philosophers; ++d->ph_idx) { + philosopher(&d->ph[d->ph_idx]); + cco_yield(); + } + } + + cco_final: + for (int i = 0; i < num_philosophers; ++i) { + cco_stop(&d->ph[i]); + philosopher(&d->ph[i]); + } + puts("Dining finished"); + } +} + + +int main() +{ + struct Dining dine; + cco_reset(&dine); + cco_timer tm = cco_timer_from(10000); + csrand((uint64_t)time(NULL)); + + while (!cco_done(&dine)) { + if (cco_timer_expired(&tm)) + cco_stop(&dine); + dining(&dine); + cco_sleep(1); + } +} -- cgit v1.2.3 From 4b8f8d2a97ca1411ad6dccdeac6195574edac852 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 5 Jun 2023 19:02:03 +0200 Subject: Updated timers and time functions to microseconds (from milli). --- docs/ccommon_api.md | 12 +++--- include/stc/algo/coroutine.h | 79 +++++++++++++++++++++++-------------- misc/examples/dining_philosophers.c | 12 +++--- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 4d18120a..6276494b 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -379,25 +379,27 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_yield(ret)` | Yield/suspend execution and return ret | | | `cco_await(promise)` | Await/suspend until promise is true | | | `cco_await(promise, ret)` | Await/suspend with ret value | -| | `cco_sleep(long msec)` | Sleep for milliseconds | | | Semaphores: | | | | `cco_sem` | Semaphore type | | | `cco_sem_await(sem)` | Await for the semaphore count > 0 | | | `cco_sem_await(sem, ret)` | Await with ret on the semaphore | -| cco_sem | `cco_sem_init(long value)` | Set semaphore value | +| `cco_sem` | `cco_sem_init(long value)` | Set semaphore value | | | `cco_sem_release(sem)` | Signal the semaphore | | | Timers: | | | | `cco_timer` | Timer type | | | `cco_timer_await(tm)` | Await for timer to expire | | | `cco_timer_await(tm, ret)` | Await with ret for timer to expire | -| | `cco_timer_start(tm, long msecs)` | Start timer msecs milliseconds | +| | `cco_timer_start(tm, long usec)` | Start timer for usec microseconds | | | `cco_timer_restart(tm)` | Restart timer with same duration | | `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | -| `long` | `cco_timer_remaining(tm)` | Return milliseconds remaining | +|`long long`| `cco_timer_remaining(tm)` | Return microseconds remaining | | | From caller side: | | -| `void` | `cco_stop(co)` | Next call of coroutine returns `cco_end()` | +| `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | | `void` | `cco_run(co, corocall) { }` | Run blocking until coro is done | +| | Time functions: | | +|`long long`| `cco_utime(void)` | Return microseconds since Epoch | +| | `cco_usleep(long long usec)` | Sleep for microseconds | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 05307b08..d0c9ad86 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -56,7 +56,6 @@ int main(void) { return 0; } */ -#include #include enum { @@ -130,55 +129,77 @@ typedef struct { * Timer */ -typedef struct { - clock_t start; - clock_t interval; -} cco_timer; - -#define cco_timer_await(...) c_MACRO_OVERLOAD(cco_timer_await, __VA_ARGS__) -#define cco_timer_await_2(tm, msec) cco_timer_await_3(tm, msec, ) -#define cco_timer_await_3(tm, msec, ret) \ - do { \ - cco_timer_start(tm, msec); \ - cco_await_2(cco_timer_expired(tm), ret); \ - } while (0) - #ifdef _WIN32 #ifdef __cplusplus - extern "C" + #define _c_LINKC extern "C" __declspec(dllimport) + #else + #define _c_LINKC __declspec(dllimport) #endif - __declspec(dllimport) void __stdcall Sleep(unsigned long); - static inline void cco_sleep(long msec) { - Sleep((unsigned long)msec); + struct _FILETIME; struct _SECURITY_ATTRIBUTES; union _LARGE_INTEGER; + _c_LINKC void GetSystemTimePreciseAsFileTime(struct _FILETIME*); + _c_LINKC void* CreateWaitableTimerW(struct _SECURITY_ATTRIBUTES*, int, const wchar_t*); + _c_LINKC int SetWaitableTimer(void*, const union _LARGE_INTEGER*, long, void(*)(void*, unsigned long, unsigned long), void*, int); + _c_LINKC unsigned long WaitForSingleObject(void*, unsigned long); + _c_LINKC int CloseHandle(void*); + + static inline long long cco_utime(void) { + static const long long epoch_offset = 11644473600000000LL; /* microseconds betweeen Jan 1,1601 - Jan 1,1970 */ + unsigned long long quad; /* 64-bit value, 100-nanosecond intervals since January 1, 1601 00:00 UTC */ + GetSystemTimePreciseAsFileTime((struct _FILETIME*)&quad); + return (long long)quad/10 - epoch_offset; /* microseconds since epoch */ } + + static inline void cco_usleep(long long usec) { + unsigned long long ft = -10*usec; + void* timer = CreateWaitableTimerW(NULL, true, NULL); + SetWaitableTimer(timer, (const union _LARGE_INTEGER*)&ft, 0, NULL, NULL, 0); + WaitForSingleObject(timer, ~0UL); + CloseHandle(timer); + } #else #include - static inline void cco_sleep(long msec) { - struct timeval tv = {.tv_sec=msec/1000, .tv_usec=1000*(msec % 1000)}; + static inline long long cco_utime(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*1000000LL + tv.tv_usec; + } + + static inline void cco_usleep(long long usec) { + struct timeval tv = {.tv_sec=(time_t)(usec/1000000), .tv_usec=(suseconds_t)(usec % 1000000)}; select(0, NULL, NULL, NULL, &tv); } #endif -static inline void cco_timer_start(cco_timer* tm, long msec) { - tm->interval = msec*(CLOCKS_PER_SEC/1000); - tm->start = clock(); +typedef struct { long long interval, start; } cco_timer; + +#define cco_timer_await(...) c_MACRO_OVERLOAD(cco_timer_await, __VA_ARGS__) +#define cco_timer_await_2(tm, usec) cco_timer_await_3(tm, usec, ) +#define cco_timer_await_3(tm, usec, ret) \ + do { \ + cco_timer_start(tm, usec); \ + cco_await_2(cco_timer_expired(tm), ret); \ + } while (0) + +static inline void cco_timer_start(cco_timer* tm, long long usec) { + tm->interval = usec; + tm->start = cco_utime(); } -static inline cco_timer cco_timer_from(long msec) { - cco_timer tm = {msec*(CLOCKS_PER_SEC/1000), clock()}; +static inline cco_timer cco_timer_from(long long usec) { + cco_timer tm = {.interval=usec, .start=cco_utime()}; return tm; } static inline void cco_timer_restart(cco_timer* tm) { - tm->start = clock(); + tm->start = cco_utime(); } static inline bool cco_timer_expired(cco_timer* tm) { - return clock() - tm->start >= tm->interval; + return cco_utime() - tm->start >= tm->interval; } -static inline long cco_timer_remaining(cco_timer* tm) { - return (long)((double)(tm->start + tm->interval - clock())*(1000.0/CLOCKS_PER_SEC)); +static inline long long cco_timer_remaining(cco_timer* tm) { + return tm->start + tm->interval - cco_utime(); } #endif diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c index 0bf421c6..cc6e5fd2 100644 --- a/misc/examples/dining_philosophers.c +++ b/misc/examples/dining_philosophers.c @@ -1,5 +1,6 @@ // https://en.wikipedia.org/wiki/Dining_philosophers_problem #include +#include #include #include @@ -33,7 +34,7 @@ void philosopher(struct Philosopher* p) while (1) { int duration = (int)(1000 + crand() % 2000); // 1-3 seconds printf("Philosopher %d is thinking for %d minutes...\n", p->id, duration/100); - cco_timer_await(&p->tm, duration); + cco_timer_await(&p->tm, duration*1000); printf("Philosopher %d is hungry...\n", p->id); cco_sem_await(p->left_fork); @@ -41,7 +42,7 @@ void philosopher(struct Philosopher* p) duration = (int)(500 + crand() % 1000); printf("Philosopher %d is eating for %d minutes...\n", p->id, duration/100); - cco_timer_await(&p->tm, duration); + cco_timer_await(&p->tm, duration*1000); cco_sem_release(p->left_fork); cco_sem_release(p->right_fork); @@ -67,10 +68,11 @@ void dining(struct Dining* d) } while (1) { + // per-"frame" logic update of all philosophers states for (d->ph_idx = 0; d->ph_idx < num_philosophers; ++d->ph_idx) { philosopher(&d->ph[d->ph_idx]); - cco_yield(); } + cco_yield(); // suspend, return control back to main } cco_final: @@ -87,13 +89,13 @@ int main() { struct Dining dine; cco_reset(&dine); - cco_timer tm = cco_timer_from(10000); + cco_timer tm = cco_timer_from(10*1000000); // microseconds csrand((uint64_t)time(NULL)); while (!cco_done(&dine)) { if (cco_timer_expired(&tm)) cco_stop(&dine); dining(&dine); - cco_sleep(1); + cco_usleep(100); } } -- cgit v1.2.3 From f2d90c87590133547e474da4ea9d5dd1b834043e Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 6 Jun 2023 01:36:54 +0200 Subject: Switched to double for times in cco_timer and cco_time, etc. Reverted to just use Sleep on win32 - same effect. --- docs/ccommon_api.md | 8 ++--- include/stc/algo/coroutine.h | 63 +++++++++++++++++-------------------- misc/examples/dining_philosophers.c | 20 ++++++------ 3 files changed, 44 insertions(+), 47 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 6276494b..de421f2c 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -389,17 +389,17 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_timer` | Timer type | | | `cco_timer_await(tm)` | Await for timer to expire | | | `cco_timer_await(tm, ret)` | Await with ret for timer to expire | -| | `cco_timer_start(tm, long usec)` | Start timer for usec microseconds | +| | `cco_timer_start(tm, double sec)` | Start timer for sec seconds | | | `cco_timer_restart(tm)` | Restart timer with same duration | | `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | -|`long long`| `cco_timer_remaining(tm)` | Return microseconds remaining | +| `double` | `cco_timer_remaining(tm)` | Return seconds remaining | | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | | `void` | `cco_run(co, corocall) { }` | Run blocking until coro is done | | | Time functions: | | -|`long long`| `cco_utime(void)` | Return microseconds since Epoch | -| | `cco_usleep(long long usec)` | Sleep for microseconds | +| `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | +| | `cco_sleep(double sec)` | Sleep for seconds | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index d0c9ad86..79819c55 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -135,71 +135,66 @@ typedef struct { #else #define _c_LINKC __declspec(dllimport) #endif - struct _FILETIME; struct _SECURITY_ATTRIBUTES; union _LARGE_INTEGER; + struct _FILETIME; _c_LINKC void GetSystemTimePreciseAsFileTime(struct _FILETIME*); - _c_LINKC void* CreateWaitableTimerW(struct _SECURITY_ATTRIBUTES*, int, const wchar_t*); - _c_LINKC int SetWaitableTimer(void*, const union _LARGE_INTEGER*, long, void(*)(void*, unsigned long, unsigned long), void*, int); - _c_LINKC unsigned long WaitForSingleObject(void*, unsigned long); - _c_LINKC int CloseHandle(void*); - - static inline long long cco_utime(void) { - static const long long epoch_offset = 11644473600000000LL; /* microseconds betweeen Jan 1,1601 - Jan 1,1970 */ - unsigned long long quad; /* 64-bit value, 100-nanosecond intervals since January 1, 1601 00:00 UTC */ + _c_LINKC void Sleep(unsigned long); + + static inline double cco_time(void) { + static const unsigned long long epoch_offset = 116444736000000000ULL; /* 1/10th usecs betweeen Jan 1,1601 - Jan 1,1970 */ + unsigned long long quad; /* 64-bit value, 100-nanosecond intervals since January 1, 1601 00:00 UTC */ GetSystemTimePreciseAsFileTime((struct _FILETIME*)&quad); - return (long long)quad/10 - epoch_offset; /* microseconds since epoch */ + return (double)(quad - epoch_offset)*1e-7; /* usecs since epoch */ } - static inline void cco_usleep(long long usec) { - unsigned long long ft = -10*usec; - void* timer = CreateWaitableTimerW(NULL, true, NULL); - SetWaitableTimer(timer, (const union _LARGE_INTEGER*)&ft, 0, NULL, NULL, 0); - WaitForSingleObject(timer, ~0UL); - CloseHandle(timer); - } + static inline void cco_sleep(double sec) { + Sleep((unsigned long)(sec*1000.0)); + } #else #include - static inline long long cco_utime(void) { + static inline double cco_time(void) { struct timeval tv; gettimeofday(&tv, NULL); - return tv.tv_sec*1000000LL + tv.tv_usec; + return tv.tv_sec + tv.tv_usec*1e-6; } - static inline void cco_usleep(long long usec) { - struct timeval tv = {.tv_sec=(time_t)(usec/1000000), .tv_usec=(suseconds_t)(usec % 1000000)}; + static inline void cco_sleep(double sec) { + struct timeval tv; + tv.tv_sec = (time_t)sec; + tv.tv_usec = (suseconds_t)(1e6*(sec - tv.tv_sec)); select(0, NULL, NULL, NULL, &tv); } #endif -typedef struct { long long interval, start; } cco_timer; +typedef struct { double interval, start; } cco_timer; #define cco_timer_await(...) c_MACRO_OVERLOAD(cco_timer_await, __VA_ARGS__) -#define cco_timer_await_2(tm, usec) cco_timer_await_3(tm, usec, ) -#define cco_timer_await_3(tm, usec, ret) \ +#define cco_timer_await_2(tm, sec) cco_timer_await_3(tm, sec, ) +#define cco_timer_await_3(tm, sec, ret) \ do { \ - cco_timer_start(tm, usec); \ + cco_timer_start(tm, sec); \ cco_await_2(cco_timer_expired(tm), ret); \ } while (0) -static inline void cco_timer_start(cco_timer* tm, long long usec) { - tm->interval = usec; - tm->start = cco_utime(); +static inline void cco_timer_start(cco_timer* tm, double sec) { + tm->interval = sec; + tm->start = cco_time(); } -static inline cco_timer cco_timer_from(long long usec) { - cco_timer tm = {.interval=usec, .start=cco_utime()}; +static inline cco_timer cco_timer_from(double sec) { + cco_timer tm = {.interval=sec, .start=cco_time()}; return tm; } static inline void cco_timer_restart(cco_timer* tm) { - tm->start = cco_utime(); + tm->start = cco_time(); } static inline bool cco_timer_expired(cco_timer* tm) { - return cco_utime() - tm->start >= tm->interval; + return cco_time() - tm->start >= tm->interval; } -static inline long long cco_timer_remaining(cco_timer* tm) { - return tm->start + tm->interval - cco_utime(); +static inline double cco_timer_remaining(cco_timer* tm) { + return tm->start + tm->interval - cco_time(); } #endif diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c index cc6e5fd2..57fcef56 100644 --- a/misc/examples/dining_philosophers.c +++ b/misc/examples/dining_philosophers.c @@ -32,17 +32,17 @@ void philosopher(struct Philosopher* p) { cco_routine(p) { while (1) { - int duration = (int)(1000 + crand() % 2000); // 1-3 seconds - printf("Philosopher %d is thinking for %d minutes...\n", p->id, duration/100); - cco_timer_await(&p->tm, duration*1000); + double duration = 1.0 + crandf()*2.0; + printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10); + cco_timer_await(&p->tm, duration); printf("Philosopher %d is hungry...\n", p->id); cco_sem_await(p->left_fork); cco_sem_await(p->right_fork); - duration = (int)(500 + crand() % 1000); - printf("Philosopher %d is eating for %d minutes...\n", p->id, duration/100); - cco_timer_await(&p->tm, duration*1000); + duration = 0.5 + crandf(); + printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10); + cco_timer_await(&p->tm, duration); cco_sem_release(p->left_fork); cco_sem_release(p->right_fork); @@ -84,18 +84,20 @@ void dining(struct Dining* d) } } - int main() { struct Dining dine; cco_reset(&dine); - cco_timer tm = cco_timer_from(10*1000000); // microseconds + int n=0; + cco_timer tm = cco_timer_from(10.0); // seconds csrand((uint64_t)time(NULL)); while (!cco_done(&dine)) { if (cco_timer_expired(&tm)) cco_stop(&dine); dining(&dine); - cco_usleep(100); + cco_sleep(0.001); + ++n; } + printf("n=%d\n", n); } -- cgit v1.2.3 From 8e6e1d2b266e46e3920edf7cc6eaad33c1312880 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 6 Jun 2023 11:42:18 +0200 Subject: Warning fixes and docs update. --- docs/ccommon_api.md | 4 ++-- include/stc/algo/coroutine.h | 10 +++++----- include/stc/algo/sort.h | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index de421f2c..7aa94c50 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -389,7 +389,7 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_timer` | Timer type | | | `cco_timer_await(tm)` | Await for timer to expire | | | `cco_timer_await(tm, ret)` | Await with ret for timer to expire | -| | `cco_timer_start(tm, double sec)` | Start timer for sec seconds | +| | `cco_timer_start(tm, double sec)` | Start timer for sec seconds (usec prec.)| | | `cco_timer_restart(tm)` | Restart timer with same duration | | `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | | `double` | `cco_timer_remaining(tm)` | Return seconds remaining | @@ -399,7 +399,7 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | `void` | `cco_run(co, corocall) { }` | Run blocking until coro is done | | | Time functions: | | | `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | -| | `cco_sleep(double sec)` | Sleep for seconds | +| | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 79819c55..1ac30fff 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -139,11 +139,11 @@ typedef struct { _c_LINKC void GetSystemTimePreciseAsFileTime(struct _FILETIME*); _c_LINKC void Sleep(unsigned long); - static inline double cco_time(void) { + static inline double cco_time(void) { /* seconds since epoch */ static const unsigned long long epoch_offset = 116444736000000000ULL; /* 1/10th usecs betweeen Jan 1,1601 - Jan 1,1970 */ unsigned long long quad; /* 64-bit value, 100-nanosecond intervals since January 1, 1601 00:00 UTC */ GetSystemTimePreciseAsFileTime((struct _FILETIME*)&quad); - return (double)(quad - epoch_offset)*1e-7; /* usecs since epoch */ + return (double)(quad - epoch_offset)*1e-7; } static inline void cco_sleep(double sec) { @@ -151,16 +151,16 @@ typedef struct { } #else #include - static inline double cco_time(void) { + static inline double cco_time(void) { /* seconds since epoch */ struct timeval tv; gettimeofday(&tv, NULL); - return tv.tv_sec + tv.tv_usec*1e-6; + return (double)tv.tv_sec + (double)tv.tv_usec*1e-6; } static inline void cco_sleep(double sec) { struct timeval tv; tv.tv_sec = (time_t)sec; - tv.tv_usec = (suseconds_t)(1e6*(sec - tv.tv_sec)); + tv.tv_usec = (suseconds_t)((sec - (double)(long)sec)*1e6); select(0, NULL, NULL, NULL, &tv); } #endif diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h index 20b7e1b3..bbd58427 100644 --- a/include/stc/algo/sort.h +++ b/include/stc/algo/sort.h @@ -24,7 +24,7 @@ template params: #define i_val - value type [required] #define i_less - less function. default: *x < *y -#define i_tag name - define namearray_qsort(). i_tag defaults {i_val} +#define i_type name - define {{name}}_sort_n(), else {{i_val}}array_sort_n(). // test: #include @@ -32,12 +32,12 @@ template params: #include int main() { - int arr[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21}; + int nums[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21}; - intarray_qsort(arr, c_arraylen(arr)); + intarray_sort_n(nums, c_arraylen(arr)); - for (int i = 0; i < c_arraylen(arr); i++) - printf(" %d", arr[i]); + for (int i = 0; i < c_arraylen(nums); i++) + printf(" %d", nums[i]); puts(""); } */ -- cgit v1.2.3 From 7c57f4fb7edf33d030975a04160f183f71c48ecd Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 6 Jun 2023 18:13:18 +0200 Subject: Fixed some logic in coroutines. Changed API in c11/print.h (not officially part of STC as it is C11). --- docs/ccommon_api.md | 3 +- docs/cspan_api.md | 13 ++++--- include/c11/print.h | 87 ++++++++++++++++++++++---------------------- include/stc/algo/coroutine.h | 12 ++++-- 4 files changed, 61 insertions(+), 54 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 7aa94c50..1fd8af75 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -372,13 +372,14 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| | | `cco_final:` | Label for cleanup in coroutine | -| | `cco_return` | Early return from the coroutine (no arg) | | `bool` | `cco_done(co)` | Is coroutine done? | | | `cco_routine(co) { ... }` | The coroutine closure | | | `cco_yield()` | Yield/suspend execution | | | `cco_yield(ret)` | Yield/suspend execution and return ret | | | `cco_await(promise)` | Await/suspend until promise is true | | | `cco_await(promise, ret)` | Await/suspend with ret value | +| | `cco_return` | Execute final cleanup, enter done-state | +| | `cco_return_v(val)` | Yield final value, enter final-state | | | Semaphores: | | | | `cco_sem` | Semaphore type | | | `cco_sem_await(sem)` | Await for the semaphore count > 0 | diff --git a/docs/cspan_api.md b/docs/cspan_api.md index ec203460..f0c6babd 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -136,6 +136,7 @@ int main() { ## Example 2 Slicing cspan without and with reducing the rank: ```c +#define i_implement #include #include @@ -154,7 +155,7 @@ int main() puts("\niterate span2 flat:"); c_foreach (i, Span2, span2) - print(" {}", *i.ref); + fmt_print(" {}", *i.ref); puts(""); // slice without reducing rank: @@ -164,8 +165,8 @@ int main() c_forrange (i, ss3.shape[0]) { c_forrange (j, ss3.shape[1]) { c_forrange (k, ss3.shape[2]) - print(" {:2}", *cspan_at(&ss3, i, j, k)); - print(" |"); + fmt_print(" {:2}", *cspan_at(&ss3, i, j, k)); + fmt_print(" |"); } } // slice and reduce rank: @@ -174,13 +175,13 @@ int main() puts("\niterate ss2 by dimensions:"); c_forrange (i, ss2.shape[0]) { c_forrange (j, ss2.shape[1]) - print(" {:2}", *cspan_at(&ss2, i, j)); - print(" |"); + fmt_print(" {:2}", *cspan_at(&ss2, i, j)); + fmt_print(" |"); } puts("\niterate ss2 flat:"); c_foreach (i, Span2, ss2) - print(" {:2}", *i.ref); + fmt_print(" {:2}", *i.ref); puts(""); } ``` diff --git a/include/c11/print.h b/include/c11/print.h index 7c155875..ee0d8151 100644 --- a/include/c11/print.h +++ b/include/c11/print.h @@ -1,7 +1,7 @@ #ifndef FMT_H_INCLUDED #define FMT_H_INCLUDED /* -VER 2.1: NEW API: +VER 2.2: NEW API: void print(fmt, ...); void println(fmt, ...); void printd(dest, fmt, ...); @@ -9,28 +9,31 @@ void printd(dest, fmt, ...); void fmt_print(fmt, ...); void fmt_println(fmt, ...); void fmt_printd(dest, fmt, ...); -void fmt_destroy(fmt_buffer* buf); +void fmt_close(fmt_stream* ss); dest - destination, one of: FILE* fp Write to a file char* strbuf Write to a pre-allocated string buffer - fmt_buffer* buf Auto realloc the needed memory (safe). - Set buf->stream=1 for stream-mode. - Call fmt_destroy(buf) after usage. + fmt_stream* ss Write to a string-stream (auto allocated). + Set ss->overwrite=1 for overwrite-mode. + Call fmt_close(ss) after usage. fmt - format string {} Auto-detected format. If :MOD is not specified, float will use ".8g" format, and double ".16g". - {:MOD} Format modifiers: < left align (replaces -), default for char*, char. - > right align, default for numbers. - Other than that MOD can be normal printf format modifiers. - {{, }} Print chars {, and }. (note: a single % prints %). + {:MODS} Format modifiers: '<' left align (replaces '-'). Default for char* and char. + '>' right align. Default for numbers. + Other than that MODS can be regular printf() format modifiers. + {{ }} % Print the '{', '}', and '%' characters. * C11 or higher required. * MAX 255 chars fmt string by default. MAX 12 arguments after fmt string. -* Static linking by default, shared symbols by defining FMT_HEADER / FMT_IMPLEMENT. +* Define FMT_IMPLEMENT or i_implement prior to #include in one translation unit. +* Define FMT_SHORTS to define print(), println() and printd() macros, without fmt_ prefix. * (c) operamint, 2022, MIT License. ----------------------------------------------------------------------------------- +#define FMT_IMPLEMENT +#define FMT_SHORTS #include "c11/print.h" int main() { @@ -50,15 +53,15 @@ int main() { printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World"); printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x); printd(buffer, "Precision: {} {:.10} {}", string, pi, x); - println("{}", buffer); - println("Vector: ({}, {}, {})", 3.2, 3.3, pi); + fmt_println("{}", buffer); + fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi); - fmt_buffer out[1] = {{.stream=1}}; - printd(out, "{} {}", "Pi is:", pi); - print("{}, len={}, cap={}\n", out->data, out->len, out->cap); - printd(out, "{} {}", ", Pi squared is:", pi*pi); - print("{}, len={}, cap={}\n", out->data, out->len, out->cap); - fmt_destroy(out); + fmt_stream ss[1] = {0}; + printd(ss, "{} {}", "Pi is:", pi); + print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); + printd(ss, "{} {}", ", Pi squared is:", pi*pi); + print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); + fmt_close(ss); } */ #include @@ -77,11 +80,6 @@ int main() { #define _fmt_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ _14, _15, _16, N, ...) N -#if defined FMT_HEADER || defined FMT_IMPLEMENT -# define FMT_API -#else -# define FMT_API static inline -#endif #if defined FMT_NDEBUG || defined NDEBUG # define fmt_OK(exp) (void)(exp) #else @@ -91,25 +89,25 @@ int main() { typedef struct { char* data; intptr_t cap, len; - _Bool stream; -} fmt_buffer; + _Bool overwrite; +} fmt_stream; -FMT_API void fmt_destroy(fmt_buffer* buf); -FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...); -FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...); +void fmt_close(fmt_stream* ss); +int _fmt_parse(char* p, int nargs, const char *fmt, ...); +void _fmt_bprint(fmt_stream*, const char* fmt, ...); #ifndef FMT_MAX #define FMT_MAX 256 #endif -#ifndef FMT_NOSHORTS +#ifdef FMT_SHORTS #define print(...) fmt_printd(stdout, __VA_ARGS__) -#define println(...) fmt_printd((fmt_buffer*)0, __VA_ARGS__) +#define println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) #define printd fmt_printd #endif #define fmt_print(...) fmt_printd(stdout, __VA_ARGS__) -#define fmt_println(...) fmt_printd((fmt_buffer*)0, __VA_ARGS__) +#define fmt_println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) #define fmt_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__) /* Primary function. */ @@ -161,7 +159,7 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...); #define _fmt_fn(x) _Generic ((x), \ FILE*: fprintf, \ char*: sprintf, \ - fmt_buffer*: _fmt_bprint) + fmt_stream*: _fmt_bprint) #if defined(_MSC_VER) && !defined(__clang__) # define _signed_char_hhd @@ -192,38 +190,38 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...); const wchar_t*: "ls", \ const void*: "p") -#if defined FMT_IMPLEMENT || !(defined FMT_HEADER || defined FMT_IMPLEMENT) +#if defined FMT_IMPLEMENT || defined i_implement #include #include #include -FMT_API void fmt_destroy(fmt_buffer* buf) { - free(buf->data); +void fmt_close(fmt_stream* ss) { + free(ss->data); } -FMT_API void _fmt_bprint(fmt_buffer* buf, const char* fmt, ...) { +void _fmt_bprint(fmt_stream* ss, const char* fmt, ...) { va_list args, args2; va_start(args, fmt); - if (buf == NULL) { + if (ss == NULL) { vprintf(fmt, args); putchar('\n'); goto done1; } va_copy(args2, args); const int n = vsnprintf(NULL, 0U, fmt, args); if (n < 0) goto done2; - const intptr_t pos = buf->stream ? buf->len : 0; - buf->len = pos + n; - if (buf->len > buf->cap) { - buf->cap = buf->len + buf->cap/2; - buf->data = (char*)realloc(buf->data, (size_t)buf->cap + 1U); + const intptr_t pos = ss->overwrite ? 0 : ss->len; + ss->len = pos + n; + if (ss->len > ss->cap) { + ss->cap = ss->len + ss->cap/2; + ss->data = (char*)realloc(ss->data, (size_t)ss->cap + 1U); } - vsprintf(buf->data + pos, fmt, args2); + vsprintf(ss->data + pos, fmt, args2); done2: va_end(args2); done1: va_end(args); } -FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) { +int _fmt_parse(char* p, int nargs, const char *fmt, ...) { char *arg, *p0, ch; int n = 0, empty; va_list args; @@ -273,3 +271,4 @@ FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) { } #endif #endif +#undef i_implement \ No newline at end of file diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 1ac30fff..f03fc836 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -87,13 +87,19 @@ enum { #define cco_run(co, call) while (call, !cco_done(co)) #define cco_final \ - case cco_state_final + *_state = cco_state_done; case cco_state_final #define cco_return \ - do { *_state = cco_state_final; goto _begin; } while (0) + do { \ + *_state = *_state < 0 ? cco_state_done : cco_state_final; \ + goto _begin; \ + } while (0) #define cco_return_v(value) \ - return (*_state = cco_state_final, value) + do { \ + *_state = *_state < 0 ? cco_state_done : cco_state_final; \ + return value; \ + } while (0) #define cco_stop(co) \ do { \ -- cgit v1.2.3 From 56469c2738effe6d44a3a0c44e821c0ff18ce28e Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 7 Jun 2023 10:35:38 +0200 Subject: cco: Minor internal cleanup + added cco_timer_elapsed(). --- docs/ccommon_api.md | 9 +++++---- include/stc/algo/coroutine.h | 27 ++++++++++++++------------- misc/examples/dining_philosophers.c | 7 +++---- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 1fd8af75..930b8881 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -385,14 +385,15 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_sem_await(sem)` | Await for the semaphore count > 0 | | | `cco_sem_await(sem, ret)` | Await with ret on the semaphore | | `cco_sem` | `cco_sem_init(long value)` | Set semaphore value | -| | `cco_sem_release(sem)` | Signal the semaphore | +| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | | | Timers: | | | | `cco_timer` | Timer type | -| | `cco_timer_await(tm)` | Await for timer to expire | -| | `cco_timer_await(tm, ret)` | Await with ret for timer to expire | -| | `cco_timer_start(tm, double sec)` | Start timer for sec seconds (usec prec.)| +| | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)| +| | `cco_timer_await(tm, double sec, ret)`| Await secs for timer with ret value | +| | `cco_timer_start(tm, double sec)` | Start timer for secs duration | | | `cco_timer_restart(tm)` | Restart timer with same duration | | `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | +| `double` | `cco_timer_elapsed(tm)` | Return seconds elapsed | | `double` | `cco_timer_remaining(tm)` | Return seconds remaining | | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine finalizes | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index f03fc836..81c75aa1 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -67,12 +67,12 @@ enum { #define cco_done(co) ((co)->cco_state == cco_state_done) #define cco_routine(co) \ - for (int *_state = &(co)->cco_state, _once=1; _once; *_state = cco_state_done, _once=0) \ - _begin: switch (*_state) case 0: // thanks, @liigo! + for (int *_state = &(co)->cco_state; *_state != cco_state_done; *_state = cco_state_done) \ + _resume: switch (*_state) case 0: // thanks, @liigo! #define cco_yield(ret) \ do { \ - *_state = __LINE__; return ret; goto _begin; \ + *_state = __LINE__; return ret; goto _resume; \ case __LINE__:; \ } while (0) @@ -81,7 +81,7 @@ enum { #define cco_await_2(promise, ret) \ do { \ *_state = __LINE__; \ - case __LINE__: if (!(promise)) {return ret; goto _begin;} \ + case __LINE__: if (!(promise)) {return ret; goto _resume;} \ } while (0) #define cco_run(co, call) while (call, !cco_done(co)) @@ -91,13 +91,13 @@ enum { #define cco_return \ do { \ - *_state = *_state < 0 ? cco_state_done : cco_state_final; \ - goto _begin; \ + *_state = *_state >= 0 ? cco_state_final : cco_state_done; \ + goto _resume; \ } while (0) #define cco_return_v(value) \ do { \ - *_state = *_state < 0 ? cco_state_done : cco_state_final; \ + *_state = *_state >= 0 ? cco_state_final : cco_state_done; \ return value; \ } while (0) @@ -115,9 +115,7 @@ enum { * Semaphore */ -typedef struct { - intptr_t count; -} cco_sem; +typedef struct { intptr_t count; } cco_sem; #define cco_sem_await(...) c_MACRO_OVERLOAD(cco_sem_await, __VA_ARGS__) #define cco_sem_await_1(sem) cco_sem_await_2(sem, ) @@ -146,10 +144,9 @@ typedef struct { _c_LINKC void Sleep(unsigned long); static inline double cco_time(void) { /* seconds since epoch */ - static const unsigned long long epoch_offset = 116444736000000000ULL; /* 1/10th usecs betweeen Jan 1,1601 - Jan 1,1970 */ - unsigned long long quad; /* 64-bit value, 100-nanosecond intervals since January 1, 1601 00:00 UTC */ + unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */ GetSystemTimePreciseAsFileTime((struct _FILETIME*)&quad); - return (double)(quad - epoch_offset)*1e-7; + return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */ } static inline void cco_sleep(double sec) { @@ -199,6 +196,10 @@ static inline bool cco_timer_expired(cco_timer* tm) { return cco_time() - tm->start >= tm->interval; } +static inline double cco_timer_elapsed(cco_timer* tm) { + return cco_time() - tm->start; +} + static inline double cco_timer_remaining(cco_timer* tm) { return tm->start + tm->interval - cco_time(); } diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c index 57fcef56..f9c05e71 100644 --- a/misc/examples/dining_philosophers.c +++ b/misc/examples/dining_philosophers.c @@ -22,7 +22,6 @@ struct Dining { // Define semaphores for the forks cco_sem forks[num_forks]; struct Philosopher ph[num_philosophers]; - int ph_idx; int cco_state; // required }; @@ -43,7 +42,7 @@ void philosopher(struct Philosopher* p) duration = 0.5 + crandf(); printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10); cco_timer_await(&p->tm, duration); - + cco_sem_release(p->left_fork); cco_sem_release(p->right_fork); } @@ -69,8 +68,8 @@ void dining(struct Dining* d) while (1) { // per-"frame" logic update of all philosophers states - for (d->ph_idx = 0; d->ph_idx < num_philosophers; ++d->ph_idx) { - philosopher(&d->ph[d->ph_idx]); + for (int i = 0; i < num_philosophers; ++i) { + philosopher(&d->ph[i]); } cco_yield(); // suspend, return control back to main } -- cgit v1.2.3 From d6ddb811365d5dd2cbc9c485f43ed4215d8e0148 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 7 Jun 2023 21:10:32 +0200 Subject: Updated and renamed c11/print.h to c11/fmt.h. Added fmt_tm() to print time/date from a struct tm. --- docs/cspan_api.md | 2 +- include/c11/fmt.h | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/c11/print.h | 274 ------------------------------------------------- src/singleupdate.sh | 2 +- 4 files changed, 289 insertions(+), 276 deletions(-) create mode 100644 include/c11/fmt.h delete mode 100644 include/c11/print.h diff --git a/docs/cspan_api.md b/docs/cspan_api.md index f0c6babd..3a811ebf 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -137,7 +137,7 @@ int main() { Slicing cspan without and with reducing the rank: ```c #define i_implement -#include +#include #include using_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3 diff --git a/include/c11/fmt.h b/include/c11/fmt.h new file mode 100644 index 00000000..6c1388af --- /dev/null +++ b/include/c11/fmt.h @@ -0,0 +1,287 @@ +#ifndef FMT_H_INCLUDED +#define FMT_H_INCLUDED +/* +VER 2.2: NEW API: +void fmt_print(fmt, ...); +void fmt_println(fmt, ...); +void fmt_printd(dest, fmt, ...); +const char* fmt_tm(fmt, struct tm* tp); +void fmt_close(fmt_stream* ss); + + dest - destination, one of: + FILE* fp Write to a file + char* strbuf Write to a pre-allocated string buffer + fmt_stream* ss Write to a string-stream (auto allocated). + Set ss->overwrite=1 for overwrite-mode. + Call fmt_close(ss) after usage. + + fmt - format string (const char*) + {} Auto-detected format. If :MOD is not specified, + float will use ".8g" format, and double ".16g". + {:MODS} Format modifiers: '<' left align (replaces '-'). Default for char* and char. + '>' right align. Default for numbers. + Other than that MODS can be regular printf() format modifiers. + {{ }} % Print the '{', '}', and '%' characters. + +* C11 or higher required. +* MAX 255 chars fmt string by default. MAX 12 arguments after fmt string. +* Define FMT_IMPLEMENT or i_implement prior to #include in one translation unit. +* Define FMT_SHORTS to add print(), println() and printd() macros, without fmt_ prefix. +* (c) operamint, 2022, MIT License. +----------------------------------------------------------------------------------- +#define FMT_IMPLEMENT +#define FMT_SHORTS +#include "c11/fmt.h" + +int main() { + const double pi = 3.141592653589793; + const size_t x = 1234567890; + const char* string = "Hello world"; + const wchar_t* wstr = L"The whole"; + const char z = 'z'; + _Bool flag = 1; + unsigned char r = 123, g = 214, b = 90, w = 110; + char buffer[64]; + + print("Color: ({} {} {}), {}\n", r, g, b, flag); + println("Wide: {}, {}", wstr, L"wide world"); + println("{:10} {:10} {:10.2f}", 42ull, 43, pi); + println("{:>10} {:>10} {:>10}", z, z, w); + printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World"); + printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x); + printd(buffer, "Precision: {} {:.10} {}", string, pi, x); + fmt_println("{}", buffer); + fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi); + + fmt_stream ss[1] = {0}; + printd(ss, "{} {}", "Pi is:", pi); + print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); + printd(ss, "{} {}", ", Pi squared is:", pi*pi); + print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); + fmt_close(ss); + + time_t now = time(NULL); + struct tm t1 = *localtime(&now), t2 = t1; + t2.tm_year += 2; + fmt_print(1, "Dates:\n {}\n {}\n", fmt_tm("%Y-%m-%d %X %Z", &t1), + fmt_tm("%Y-%m-%d %X %Z", &t2)); +} +*/ +#include +#include +#include + +#define fmt_OVERLOAD(name, ...) \ + fmt_JOIN(name, fmt_NUMARGS(__VA_ARGS__))(__VA_ARGS__) +#define fmt_CONCAT(a, b) a ## b +#define fmt_JOIN(a, b) fmt_CONCAT(a, b) +#define fmt_EXPAND(...) __VA_ARGS__ +#define fmt_NUMARGS(...) _fmt_APPLY_ARG_N((__VA_ARGS__, _fmt_RSEQ_N)) + +#define _fmt_APPLY_ARG_N(args) fmt_EXPAND(_fmt_ARG_N args) +#define _fmt_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +#define _fmt_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ + _14, _15, _16, N, ...) N + +#if defined FMT_NDEBUG || defined NDEBUG +# define fmt_OK(exp) (void)(exp) +#else +# define fmt_OK(exp) assert(exp) +#endif + +typedef struct { + char* data; + intptr_t cap, len; + _Bool overwrite; +} fmt_stream; + +#define fmt_tm(fmt, tmptr) _fmt_strftime(fmt, tmptr) /* Max 2 usages. Buffer = 64 chars. */ +void fmt_close(fmt_stream* ss); +int _fmt_parse(char* p, int nargs, const char *fmt, ...); +void _fmt_bprint(fmt_stream*, const char* fmt, ...); +struct tm; const char* _fmt_strftime(const char *fmt, const struct tm *tp); + +#ifndef FMT_MAX +#define FMT_MAX 128 +#endif + +#ifdef FMT_SHORTS +#define print(...) fmt_printd(stdout, __VA_ARGS__) +#define println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) +#define printd fmt_printd +#endif + +#define fmt_print(...) fmt_printd(stdout, __VA_ARGS__) +#define fmt_println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) +#define fmt_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__) + +/* Primary function. */ +#define fmt_printd2(to, fmt) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 0, fmt); \ + fmt_OK(_n == 0); _fmt_fn(to)(to, fmt); } while (0) +#define fmt_printd3(to, fmt, c) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 1, fmt, _fc(c)); \ + fmt_OK(_n == 1); _fmt_fn(to)(to, _fs, c); } while (0) +#define fmt_printd4(to, fmt, c, d) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 2, fmt, _fc(c), _fc(d)); \ + fmt_OK(_n == 2); _fmt_fn(to)(to, _fs, c, d); } while (0) +#define fmt_printd5(to, fmt, c, d, e) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 3, fmt, _fc(c), _fc(d), _fc(e)); \ + fmt_OK(_n == 3); _fmt_fn(to)(to, _fs, c, d, e); } while (0) +#define fmt_printd6(to, fmt, c, d, e, f) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 4, fmt, _fc(c), _fc(d), _fc(e), _fc(f)); \ + fmt_OK(_n == 4); _fmt_fn(to)(to, _fs, c, d, e, f); } while (0) +#define fmt_printd7(to, fmt, c, d, e, f, g) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 5, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g)); \ + fmt_OK(_n == 5); _fmt_fn(to)(to, _fs, c, d, e, f, g); } while (0) +#define fmt_printd8(to, fmt, c, d, e, f, g, h) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 6, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h)); \ + fmt_OK(_n == 6); _fmt_fn(to)(to, _fs, c, d, e, f, g, h); } while (0) +#define fmt_printd9(to, fmt, c, d, e, f, g, h, i) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 7, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), _fc(i)); \ + fmt_OK(_n == 7); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i); } while (0) +#define fmt_printd10(to, fmt, c, d, e, f, g, h, i, j) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 8, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j)); \ + fmt_OK(_n == 8); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j); } while (0) +#define fmt_printd11(to, fmt, c, d, e, f, g, h, i, j, k) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 9, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k)); \ + fmt_OK(_n == 9); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k); } while (0) +#define fmt_printd12(to, fmt, c, d, e, f, g, h, i, j, k, m) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 10, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k), _fc(m)); \ + fmt_OK(_n == 10); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m); } while (0) +#define fmt_printd13(to, fmt, c, d, e, f, g, h, i, j, k, m, n) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 11, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k), _fc(m), _fc(n)); \ + fmt_OK(_n == 11); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n); } while (0) +#define fmt_printd14(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o) \ + do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 12, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ + _fc(i), _fc(j), _fc(k), _fc(m), _fc(n), _fc(o)); \ + fmt_OK(_n == 12); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n, o); } while (0) + +#define _fmt_fn(x) _Generic ((x), \ + FILE*: fprintf, \ + char*: sprintf, \ + fmt_stream*: _fmt_bprint) + +#if defined(_MSC_VER) && !defined(__clang__) +# define _signed_char_hhd +#else +# define _signed_char_hhd signed char: "hhd", +#endif + +#define _fc(x) _Generic (x, \ + _Bool: "d", \ + unsigned char: "hhu", \ + _signed_char_hhd \ + char: "c", \ + short: "hd", \ + unsigned short: "hu", \ + int: "d", \ + unsigned: "u", \ + long: "ld", \ + unsigned long: "lu", \ + long long: "lld", \ + unsigned long long: "llu", \ + float: "g", \ + double: "@g", \ + long double: "@Lg", \ + char*: "s", \ + wchar_t*: "ls", \ + void*: "p", \ + const char*: "s", \ + const wchar_t*: "ls", \ + const void*: "p") + +#if defined FMT_IMPLEMENT || defined i_implement + +#include +#include +#include +#include + +void fmt_close(fmt_stream* ss) { + free(ss->data); +} + +const char* _fmt_strftime(const char *fmt, const struct tm *tp) { + static char buf[2][64], i = 0; + i = !i; + strftime(buf[i], 64, fmt, tp); + return buf[i]; +} + +void _fmt_bprint(fmt_stream* ss, const char* fmt, ...) { + va_list args, args2; + va_start(args, fmt); + if (ss == NULL) { + vprintf(fmt, args); putchar('\n'); + goto done1; + } + va_copy(args2, args); + const int n = vsnprintf(NULL, 0U, fmt, args); + if (n < 0) goto done2; + const intptr_t pos = ss->overwrite ? 0 : ss->len; + ss->len = pos + n; + if (ss->len > ss->cap) { + ss->cap = ss->len + ss->cap/2; + ss->data = (char*)realloc(ss->data, (size_t)ss->cap + 1U); + } + vsprintf(ss->data + pos, fmt, args2); + done2: va_end(args2); + done1: va_end(args); +} + +int _fmt_parse(char* p, int nargs, const char *fmt, ...) { + char *arg, *p0, ch; + int n = 0, empty; + va_list args; + va_start(args, fmt); + do { + switch ((ch = *fmt)) { + case '%': + *p++ = '%'; + break; + case '}': + if (*++fmt == '}') break; /* ok */ + n = 99; + continue; + case '{': + if (*++fmt == '{') break; /* ok */ + if (++n > nargs) continue; + if (*fmt != ':' && *fmt != '}') n = 99; + fmt += (*fmt == ':'); + empty = *fmt == '}'; + arg = va_arg(args, char *); + *p++ = '%', p0 = p; + while (1) switch (*fmt) { + case '\0': n = 99; /* nobreak */ + case '}': goto done; + case '<': *p++ = '-', ++fmt; break; + case '>': p0 = NULL; /* nobreak */ + case '-': ++fmt; break; + case '*': if (++n <= nargs) arg = va_arg(args, char *); /* nobreak */ + default: *p++ = *fmt++; + } + done: + switch (*arg) { + case 'g': if (empty) memcpy(p, ".8", 2), p += 2; break; + case '@': ++arg; if (empty) memcpy(p, ".16", 3), p += 3; break; + } + if (!strchr("csdioxXufFeEaAgGnp", fmt[-1])) + while (*arg) *p++ = *arg++; + if (p0 && (p[-1] == 's' || p[-1] == 'c')) /* left-align str */ + memmove(p0 + 1, p0, (size_t)(p++ - p0)), *p0 = '-'; + fmt += *fmt == '}'; + continue; + } + *p++ = *fmt++; + } while (ch); + va_end(args); + return n; +} +#endif +#endif +#undef i_implement diff --git a/include/c11/print.h b/include/c11/print.h deleted file mode 100644 index ee0d8151..00000000 --- a/include/c11/print.h +++ /dev/null @@ -1,274 +0,0 @@ -#ifndef FMT_H_INCLUDED -#define FMT_H_INCLUDED -/* -VER 2.2: NEW API: -void print(fmt, ...); -void println(fmt, ...); -void printd(dest, fmt, ...); - -void fmt_print(fmt, ...); -void fmt_println(fmt, ...); -void fmt_printd(dest, fmt, ...); -void fmt_close(fmt_stream* ss); - - dest - destination, one of: - FILE* fp Write to a file - char* strbuf Write to a pre-allocated string buffer - fmt_stream* ss Write to a string-stream (auto allocated). - Set ss->overwrite=1 for overwrite-mode. - Call fmt_close(ss) after usage. - - fmt - format string - {} Auto-detected format. If :MOD is not specified, - float will use ".8g" format, and double ".16g". - {:MODS} Format modifiers: '<' left align (replaces '-'). Default for char* and char. - '>' right align. Default for numbers. - Other than that MODS can be regular printf() format modifiers. - {{ }} % Print the '{', '}', and '%' characters. - -* C11 or higher required. -* MAX 255 chars fmt string by default. MAX 12 arguments after fmt string. -* Define FMT_IMPLEMENT or i_implement prior to #include in one translation unit. -* Define FMT_SHORTS to define print(), println() and printd() macros, without fmt_ prefix. -* (c) operamint, 2022, MIT License. ------------------------------------------------------------------------------------ -#define FMT_IMPLEMENT -#define FMT_SHORTS -#include "c11/print.h" - -int main() { - const double pi = 3.141592653589793; - const size_t x = 1234567890; - const char* string = "Hello world"; - const wchar_t* wstr = L"The whole"; - const char z = 'z'; - _Bool flag = 1; - unsigned char r = 123, g = 214, b = 90, w = 110; - char buffer[64]; - - print("Color: ({} {} {}), {}\n", r, g, b, flag); - println("Wide: {}, {}", wstr, L"wide world"); - println("{:10} {:10} {:10.2f}", 42ull, 43, pi); - println("{:>10} {:>10} {:>10}", z, z, w); - printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World"); - printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x); - printd(buffer, "Precision: {} {:.10} {}", string, pi, x); - fmt_println("{}", buffer); - fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi); - - fmt_stream ss[1] = {0}; - printd(ss, "{} {}", "Pi is:", pi); - print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); - printd(ss, "{} {}", ", Pi squared is:", pi*pi); - print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap); - fmt_close(ss); -} -*/ -#include -#include -#include - -#define fmt_OVERLOAD(name, ...) \ - fmt_JOIN(name, fmt_NUMARGS(__VA_ARGS__))(__VA_ARGS__) -#define fmt_CONCAT(a, b) a ## b -#define fmt_JOIN(a, b) fmt_CONCAT(a, b) -#define fmt_EXPAND(...) __VA_ARGS__ -#define fmt_NUMARGS(...) _fmt_APPLY_ARG_N((__VA_ARGS__, _fmt_RSEQ_N)) - -#define _fmt_APPLY_ARG_N(args) fmt_EXPAND(_fmt_ARG_N args) -#define _fmt_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 -#define _fmt_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ - _14, _15, _16, N, ...) N - -#if defined FMT_NDEBUG || defined NDEBUG -# define fmt_OK(exp) (void)(exp) -#else -# define fmt_OK(exp) assert(exp) -#endif - -typedef struct { - char* data; - intptr_t cap, len; - _Bool overwrite; -} fmt_stream; - -void fmt_close(fmt_stream* ss); -int _fmt_parse(char* p, int nargs, const char *fmt, ...); -void _fmt_bprint(fmt_stream*, const char* fmt, ...); - -#ifndef FMT_MAX -#define FMT_MAX 256 -#endif - -#ifdef FMT_SHORTS -#define print(...) fmt_printd(stdout, __VA_ARGS__) -#define println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) -#define printd fmt_printd -#endif - -#define fmt_print(...) fmt_printd(stdout, __VA_ARGS__) -#define fmt_println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__) -#define fmt_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__) - -/* Primary function. */ -#define fmt_printd2(to, fmt) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 0, fmt); \ - fmt_OK(_n == 0); _fmt_fn(to)(to, fmt); } while (0) -#define fmt_printd3(to, fmt, c) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 1, fmt, _fc(c)); \ - fmt_OK(_n == 1); _fmt_fn(to)(to, _fs, c); } while (0) -#define fmt_printd4(to, fmt, c, d) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 2, fmt, _fc(c), _fc(d)); \ - fmt_OK(_n == 2); _fmt_fn(to)(to, _fs, c, d); } while (0) -#define fmt_printd5(to, fmt, c, d, e) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 3, fmt, _fc(c), _fc(d), _fc(e)); \ - fmt_OK(_n == 3); _fmt_fn(to)(to, _fs, c, d, e); } while (0) -#define fmt_printd6(to, fmt, c, d, e, f) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 4, fmt, _fc(c), _fc(d), _fc(e), _fc(f)); \ - fmt_OK(_n == 4); _fmt_fn(to)(to, _fs, c, d, e, f); } while (0) -#define fmt_printd7(to, fmt, c, d, e, f, g) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 5, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g)); \ - fmt_OK(_n == 5); _fmt_fn(to)(to, _fs, c, d, e, f, g); } while (0) -#define fmt_printd8(to, fmt, c, d, e, f, g, h) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 6, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h)); \ - fmt_OK(_n == 6); _fmt_fn(to)(to, _fs, c, d, e, f, g, h); } while (0) -#define fmt_printd9(to, fmt, c, d, e, f, g, h, i) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 7, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), _fc(i)); \ - fmt_OK(_n == 7); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i); } while (0) -#define fmt_printd10(to, fmt, c, d, e, f, g, h, i, j) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 8, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j)); \ - fmt_OK(_n == 8); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j); } while (0) -#define fmt_printd11(to, fmt, c, d, e, f, g, h, i, j, k) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 9, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k)); \ - fmt_OK(_n == 9); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k); } while (0) -#define fmt_printd12(to, fmt, c, d, e, f, g, h, i, j, k, m) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 10, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k), _fc(m)); \ - fmt_OK(_n == 10); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m); } while (0) -#define fmt_printd13(to, fmt, c, d, e, f, g, h, i, j, k, m, n) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 11, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k), _fc(m), _fc(n)); \ - fmt_OK(_n == 11); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n); } while (0) -#define fmt_printd14(to, fmt, c, d, e, f, g, h, i, j, k, m, n, o) \ - do { char _fs[FMT_MAX]; int _n = _fmt_parse(_fs, 12, fmt, _fc(c), _fc(d), _fc(e), _fc(f), _fc(g), _fc(h), \ - _fc(i), _fc(j), _fc(k), _fc(m), _fc(n), _fc(o)); \ - fmt_OK(_n == 12); _fmt_fn(to)(to, _fs, c, d, e, f, g, h, i, j, k, m, n, o); } while (0) - -#define _fmt_fn(x) _Generic ((x), \ - FILE*: fprintf, \ - char*: sprintf, \ - fmt_stream*: _fmt_bprint) - -#if defined(_MSC_VER) && !defined(__clang__) -# define _signed_char_hhd -#else -# define _signed_char_hhd signed char: "hhd", -#endif - -#define _fc(x) _Generic (x, \ - _Bool: "d", \ - unsigned char: "hhu", \ - _signed_char_hhd \ - char: "c", \ - short: "hd", \ - unsigned short: "hu", \ - int: "d", \ - unsigned: "u", \ - long: "ld", \ - unsigned long: "lu", \ - long long: "lld", \ - unsigned long long: "llu", \ - float: "g", \ - double: "@g", \ - long double: "@Lg", \ - char*: "s", \ - wchar_t*: "ls", \ - void*: "p", \ - const char*: "s", \ - const wchar_t*: "ls", \ - const void*: "p") - -#if defined FMT_IMPLEMENT || defined i_implement - -#include -#include -#include - -void fmt_close(fmt_stream* ss) { - free(ss->data); -} - -void _fmt_bprint(fmt_stream* ss, const char* fmt, ...) { - va_list args, args2; - va_start(args, fmt); - if (ss == NULL) { - vprintf(fmt, args); putchar('\n'); - goto done1; - } - va_copy(args2, args); - const int n = vsnprintf(NULL, 0U, fmt, args); - if (n < 0) goto done2; - const intptr_t pos = ss->overwrite ? 0 : ss->len; - ss->len = pos + n; - if (ss->len > ss->cap) { - ss->cap = ss->len + ss->cap/2; - ss->data = (char*)realloc(ss->data, (size_t)ss->cap + 1U); - } - vsprintf(ss->data + pos, fmt, args2); - done2: va_end(args2); - done1: va_end(args); -} - -int _fmt_parse(char* p, int nargs, const char *fmt, ...) { - char *arg, *p0, ch; - int n = 0, empty; - va_list args; - va_start(args, fmt); - do { - switch ((ch = *fmt)) { - case '%': - *p++ = '%'; - break; - case '}': - if (*++fmt == '}') break; /* ok */ - n = 99; - continue; - case '{': - if (*++fmt == '{') break; /* ok */ - if (++n > nargs) continue; - if (*fmt != ':' && *fmt != '}') n = 99; - fmt += (*fmt == ':'); - empty = *fmt == '}'; - arg = va_arg(args, char *); - *p++ = '%', p0 = p; - while (1) switch (*fmt) { - case '\0': n = 99; /* nobreak */ - case '}': goto done; - case '<': *p++ = '-', ++fmt; break; - case '>': p0 = NULL; /* nobreak */ - case '-': ++fmt; break; - case '*': if (++n <= nargs) arg = va_arg(args, char *); /* nobreak */ - default: *p++ = *fmt++; - } - done: - switch (*arg) { - case 'g': if (empty) memcpy(p, ".8", 2), p += 2; break; - case '@': ++arg; if (empty) memcpy(p, ".16", 3), p += 3; break; - } - if (!strchr("csdioxXufFeEaAgGnp", fmt[-1])) - while (*arg) *p++ = *arg++; - if (p0 && (p[-1] == 's' || p[-1] == 'c')) /* left-align str */ - memmove(p0 + 1, p0, (size_t)(p++ - p0)), *p0 = '-'; - fmt += *fmt == '}'; - continue; - } - *p++ = *fmt++; - } while (ch); - va_end(args); - return n; -} -#endif -#endif -#undef i_implement \ No newline at end of file diff --git a/src/singleupdate.sh b/src/singleupdate.sh index 9b1d37a0..8a621e57 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -1,6 +1,6 @@ d=$(git rev-parse --show-toplevel) mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc -python singleheader.py $d/include/c11/print.h > $d/../stcsingle/c11/print.h +python singleheader.py $d/include/c11/fmt.h > $d/../stcsingle/c11/fmt.h python singleheader.py $d/include/stc/calgo.h > $d/../stcsingle/stc/calgo.h python singleheader.py $d/include/stc/carc.h > $d/../stcsingle/stc/carc.h python singleheader.py $d/include/stc/cbits.h > $d/../stcsingle/stc/cbits.h -- cgit v1.2.3 From 2bac1dff09459ce55f6e6813af96f845a8c981a1 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 7 Jun 2023 21:17:41 +0200 Subject: Minor adjustment in fmt.h --- include/c11/fmt.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/c11/fmt.h b/include/c11/fmt.h index 6c1388af..7e85e4dd 100644 --- a/include/c11/fmt.h +++ b/include/c11/fmt.h @@ -95,11 +95,11 @@ typedef struct { _Bool overwrite; } fmt_stream; -#define fmt_tm(fmt, tmptr) _fmt_strftime(fmt, tmptr) /* Max 2 usages. Buffer = 64 chars. */ -void fmt_close(fmt_stream* ss); +struct tm; /* Max 2 usages. Buffer = 64 chars. */ +const char* fmt_tm(const char *fmt, const struct tm *tp); +void fmt_close(fmt_stream* ss); int _fmt_parse(char* p, int nargs, const char *fmt, ...); void _fmt_bprint(fmt_stream*, const char* fmt, ...); -struct tm; const char* _fmt_strftime(const char *fmt, const struct tm *tp); #ifndef FMT_MAX #define FMT_MAX 128 @@ -206,7 +206,7 @@ void fmt_close(fmt_stream* ss) { free(ss->data); } -const char* _fmt_strftime(const char *fmt, const struct tm *tp) { +const char* fmt_tm(const char *fmt, const struct tm *tp) { static char buf[2][64], i = 0; i = !i; strftime(buf[i], 64, fmt, tp); -- cgit v1.2.3 From abd3b4372dee2291a81271f02588228279139960 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Thu, 8 Jun 2023 06:55:42 +0200 Subject: More small adjustments. --- docs/ccommon_api.md | 2 +- include/stc/algo/coroutine.h | 2 +- include/stc/cstr.h | 3 ++- misc/benchmarks/plotbench/plot.py | 4 ++-- misc/examples/triples.c | 10 +++++----- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 930b8881..cd9be505 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -378,7 +378,7 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_yield(ret)` | Yield/suspend execution and return ret | | | `cco_await(promise)` | Await/suspend until promise is true | | | `cco_await(promise, ret)` | Await/suspend with ret value | -| | `cco_return` | Execute final cleanup, enter done-state | +| | `cco_return` | Replaces return. Jump to cco_final: if exist| | | `cco_return_v(val)` | Yield final value, enter final-state | | | Semaphores: | | | | `cco_sem` | Semaphore type | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 81c75aa1..67ea5a40 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -87,7 +87,7 @@ enum { #define cco_run(co, call) while (call, !cco_done(co)) #define cco_final \ - *_state = cco_state_done; case cco_state_final + *_state = cco_state_final; case cco_state_final #define cco_return \ do { \ diff --git a/include/stc/cstr.h b/include/stc/cstr.h index d496b85e..03eefd2f 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -504,7 +504,8 @@ STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) { if (cap > cstr_s_cap) { char* data = (char *)c_malloc(cap + 1); const intptr_t len = cstr_s_size(self); - c_memcpy(data, self->sml.data, cstr_s_cap + 1); + /* copy full short buffer to emulate realloc() */ + c_memcpy(data, self->sml.data, cstr_s_cap + 2); self->lon.data = data; self->lon.size = (size_t)len; cstr_l_set_cap(self, cap); diff --git a/misc/benchmarks/plotbench/plot.py b/misc/benchmarks/plotbench/plot.py index 0ba92264..e65631b7 100644 --- a/misc/benchmarks/plotbench/plot.py +++ b/misc/benchmarks/plotbench/plot.py @@ -12,8 +12,8 @@ df = df[df.Method != 'total'] if n > 0: df = df[df.Compiler == comp[n]] -g = sns.catplot(data=df, x='Method', y='Seconds', hue='Library', col='C', kind='bar', - ci=68, legend=False, col_wrap=2, sharex=False, aspect=1.4, height=3.1) +g = sns.catplot(data=df, x='Method', y='Seconds', hue='Library', col='C', kind='bar', orient='v', + errorbar=('ci', 68), legend=False, col_wrap=2, sharex=False, aspect=1.4, height=3.1) g.set_xlabels('') g.add_legend(bbox_to_anchor=(0.75, 0.2), borderaxespad=0.) diff --git a/misc/examples/triples.c b/misc/examples/triples.c index 06142916..17e3d40b 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -32,7 +32,7 @@ struct triples { int cco_state; }; -bool triples_coro(struct triples* t) { +void triples_coro(struct triples* t) { cco_routine(t) { t->count = 0; for (t->c = 5; t->size; ++t->c) { @@ -41,15 +41,14 @@ bool triples_coro(struct triples* t) { if ((int64_t)t->a*t->a + (int64_t)t->b*t->b == (int64_t)t->c*t->c) { if (t->count++ == t->size) cco_return; - cco_yield(false); + cco_yield(); } } } } - cco_final: + cco_final: puts("done"); } - return true; } int main() @@ -61,7 +60,8 @@ int main() struct triples t = {INT32_MAX}; int n = 0; - while (!triples_coro(&t)) { + while (!cco_done(&t)) { + triples_coro(&t); if (gcd(t.a, t.b) > 1) continue; if (t.c < 100) -- cgit v1.2.3 From 72b0f0e7839b487a5df7c79ffe84511480cad251 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 9 Jun 2023 19:31:59 +0200 Subject: Fixed issues with linking params i_implement, i_extern. --- docs/cregex_api.md | 6 +-- include/c11/fmt.h | 1 + include/stc/cbits.h | 6 +-- include/stc/ccommon.h | 2 +- include/stc/cdeq.h | 2 +- include/stc/clist.h | 2 +- include/stc/cmap.h | 2 +- include/stc/cpque.h | 2 +- include/stc/cqueue.h | 2 +- include/stc/crand.h | 2 +- include/stc/cregex.h | 10 ++-- include/stc/csmap.h | 2 +- include/stc/cspan.h | 2 +- include/stc/cstr.h | 102 ++++++++++++++++++++-------------------- include/stc/csview.h | 36 +++++++------- include/stc/cvec.h | 2 +- include/stc/forward.h | 1 + include/stc/utf8.h | 16 +++++-- misc/examples/arc_containers.c | 2 +- misc/examples/astar.c | 1 + misc/examples/books.c | 1 + misc/examples/box.c | 1 + misc/examples/complex.c | 3 +- misc/examples/convert.c | 2 +- misc/examples/coread.c | 2 +- misc/examples/csmap_erase.c | 1 + misc/examples/csmap_find.c | 1 + misc/examples/csmap_insert.c | 1 + misc/examples/cstr_match.c | 1 + misc/examples/demos.c | 1 + misc/examples/forfilter.c | 1 + misc/examples/gauss2.c | 3 +- misc/examples/hashmap.c | 1 + misc/examples/inits.c | 2 +- misc/examples/list_splice.c | 1 - misc/examples/make.sh | 2 +- misc/examples/mapmap.c | 2 +- misc/examples/mmap.c | 1 + misc/examples/multimap.c | 1 + misc/examples/music_arc.c | 1 + misc/examples/new_map.c | 1 + misc/examples/new_smap.c | 1 + misc/examples/new_sptr.c | 1 + misc/examples/person_arc.c | 1 + misc/examples/phonebook.c | 2 +- misc/examples/printspan.c | 1 + misc/examples/rawptr_elements.c | 2 +- misc/examples/read.c | 1 + misc/examples/regex_match.c | 1 + misc/examples/replace.c | 1 + misc/examples/splitstr.c | 1 + misc/examples/sso_map.c | 1 + misc/examples/sso_substr.c | 2 + misc/examples/sview_split.c | 2 + misc/examples/unordered_set.c | 1 + misc/examples/utf8replace_c.c | 1 + misc/examples/vikings.c | 1 + src/cregex.c | 19 +++++++- src/libstc.c | 12 +++++ src/utf8code.c | 5 +- 60 files changed, 180 insertions(+), 107 deletions(-) diff --git a/docs/cregex_api.md b/docs/cregex_api.md index e702c47c..fc86cc63 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -44,15 +44,15 @@ bool cregex_is_match(const cregex* re, const char* input); // Replace all matches in input cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX); - // Replace count matches in input string-view. Optionally transform replacement with mfun. + // Replace count matches in input string-view. Optionally transform replacement. cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX); cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count, - bool(*mfun)(int capgrp, csview match, cstr* mstr), int rflags); + bool(*transform)(int group, csview match, cstr* result), int rflags); // All-in-one replacement (compile + find/replace + drop) cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX); cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count, - bool(*mfun)(int capgrp, csview match, cstr* mstr), int rflags); + bool(*transform)(int group, csview match, cstr* result), int rflags); // destroy void cregex_drop(cregex* self); ``` diff --git a/include/c11/fmt.h b/include/c11/fmt.h index 7e85e4dd..45044e33 100644 --- a/include/c11/fmt.h +++ b/include/c11/fmt.h @@ -69,6 +69,7 @@ int main() { */ #include #include +#include #include #define fmt_OVERLOAD(name, ...) \ diff --git a/include/stc/cbits.h b/include/stc/cbits.h index fe422202..8a6558bf 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -161,9 +161,9 @@ STC_INLINE void cbits_resize(cbits* self, const int64_t size, const bool value) if (new_n >= old_n) { c_memset(self->data64 + old_n, -(int)value, (new_n - old_n)*8); if (old_n > 0) { - uint64_t m = _cbits_bit(osize) - 1; /* mask */ - value ? (self->data64[old_n - 1] |= ~m) - : (self->data64[old_n - 1] &= m); + uint64_t mask = _cbits_bit(osize) - 1; + if (value) self->data64[old_n - 1] |= ~mask; + else self->data64[old_n - 1] &= mask; } } } diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 01ead57a..87522a6e 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -253,6 +253,6 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { #if defined(STC_EXTERN) #define i_extern #endif -#if defined(i_static) || defined(STC_IMPLEMENT) || defined(i_extern) +#if defined(STC_IMPLEMENT) || defined(i_extern) #define i_implement #endif diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index b3714bf8..8bb62602 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -113,7 +113,7 @@ _cx_memb(_get_mut)(_cx_self* self, _cx_raw raw) #endif /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value) { diff --git a/include/stc/clist.h b/include/stc/clist.h index 128e848d..310db204 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -214,7 +214,7 @@ STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { #endif // -------------------------- IMPLEMENTATION ------------------------- -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) #if !defined i_no_clone STC_DEF _cx_self diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 837631f8..f6c3eb07 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -261,7 +261,7 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) #ifndef i_max_load_factor #define i_max_load_factor 0.80f #endif diff --git a/include/stc/cpque.h b/include/stc/cpque.h index 85002c67..31a53ece 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -108,7 +108,7 @@ STC_INLINE void _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) #endif // !i_no_emplace /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF void _cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) { diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 571c1fe9..28515877 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -121,7 +121,7 @@ STC_INLINE void _cx_memb(_adjust_end_)(_cx_self* self, intptr_t n) { self->end = (self->end + n) & self->capmask; } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t n) { intptr_t len = _cx_memb(_size)(it._s); diff --git a/include/stc/crand.h b/include/stc/crand.h index f566c1cf..b9687c01 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -92,7 +92,7 @@ STC_INLINE double crand_f64(crand_t* rng) { } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) /* Global random() */ static crand_t crand_global = {{ diff --git a/include/stc/cregex.h b/include/stc/cregex.h index 919f5474..e6180a31 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -135,7 +135,7 @@ STC_INLINE bool cregex_is_match(const cregex* re, const char* input) #define cregex_replace_sv_4(pattern, input, replace, count) \ cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, - bool (*mfun)(int i, csview match, cstr* mstr), int rflags); + bool (*transform)(int group, csview match, cstr* result), int rflags); /* replace input with replace using regular expression */ #define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__) @@ -153,20 +153,20 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char #define cregex_replace_pattern_4(pattern, input, replace, count) \ cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*mfun)(int i, csview match, cstr* mstr), int crflags); + bool (*transform)(int group, csview match, cstr* result), int crflags); /* destroy regex */ void cregex_drop(cregex* re); -#endif // CREGEX_H_INCLUDED -#if defined i_extern || defined i_implement +#if defined i_implement # include "../../src/cregex.c" #endif #if defined i_extern # include "../../src/utf8code.c" #endif +#endif // CREGEX_H_INCLUDED #undef i_opt #undef i_header #undef i_static -#undef i_implement #undef i_extern +#undef i_implement diff --git a/include/stc/csmap.h b/include/stc/csmap.h index e8138926..7638b8f2 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -249,7 +249,7 @@ _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF void _cx_memb(_next)(_cx_iter *it) { diff --git a/include/stc/cspan.h b/include/stc/cspan.h index b07e75a8..5b592098 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -212,7 +212,7 @@ STC_API intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank, int rank, const int32_t a[][2]); /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stri[], const int32_t a[]) { intptr_t off = a[0]; diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 03eefd2f..ae80dab4 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -24,16 +24,12 @@ /* A string type with short string optimization in C99 with good small-string * optimization (22 characters with 24 bytes string). */ +#define _i_no_undef +#include "utf8.h" + #ifndef CSTR_H_INCLUDED #define CSTR_H_INCLUDED -#define i_header -#if defined i_extern || defined STC_EXTERN -# define _i_extern -#endif -#include "ccommon.h" -#include "forward.h" -#include "utf8.h" #include /* malloc */ #include #include /* vsnprintf */ @@ -65,8 +61,8 @@ enum { cstr_s_cap = sizeof(cstr_buf) - 2 }; #define cstr_l_drop(s) c_free((s)->lon.data) #define cstr_is_long(s) ((s)->sml.size > 127) -STC_API char* _cstr_init(cstr* self, intptr_t len, intptr_t cap); -STC_API char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); +extern char* _cstr_init(cstr* self, intptr_t len, intptr_t cap); +extern char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); /**************************** PUBLIC API **********************************/ @@ -74,19 +70,21 @@ STC_API char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); #define cstr_NULL (c_LITERAL(cstr){{{0}, 0}}) #define cstr_toraw(self) cstr_str(self) -STC_API char* cstr_reserve(cstr* self, intptr_t cap); -STC_API void cstr_shrink_to_fit(cstr* self); -STC_API char* cstr_resize(cstr* self, intptr_t size, char value); -STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); -STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len); -STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len); -STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp); -STC_API void cstr_erase(cstr* self, intptr_t pos, intptr_t len); -STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); -STC_API cstr cstr_from_fmt(const char* fmt, ...); -STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); -STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...); -STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); +extern char* cstr_reserve(cstr* self, intptr_t cap); +extern void cstr_shrink_to_fit(cstr* self); +extern char* cstr_resize(cstr* self, intptr_t size, char value); +extern intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); +extern intptr_t cstr_find_sv(const cstr* self, csview search); +extern char* cstr_assign_n(cstr* self, const char* str, intptr_t len); +extern char* cstr_append_n(cstr* self, const char* str, intptr_t len); +extern bool cstr_getdelim(cstr *self, int delim, FILE *fp); +extern void cstr_erase(cstr* self, intptr_t pos, intptr_t len); +extern void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); +extern cstr cstr_from_fmt(const char* fmt, ...); +extern intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); +extern intptr_t cstr_printf(cstr* self, const char* fmt, ...); +extern cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); +extern uint64_t cstr_hash(const cstr *self); STC_INLINE cstr_buf cstr_buffer(cstr* s) { return cstr_is_long(s) @@ -284,8 +282,6 @@ STC_INLINE intptr_t cstr_find(const cstr* self, const char* search) { return res ? (res - str) : c_NPOS; } -STC_API intptr_t cstr_find_sv(const cstr* self, csview search); - STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search) { return cstr_find(self, cstr_str(&search)); } @@ -404,13 +400,15 @@ STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) { cstr_replace_at_sv(self, pos, 0, sv); } - STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } -STC_API uint64_t cstr_hash(const cstr *self); +#endif // CSTR_H_INCLUDED + +/* -------------------------- EXTERN ------------------------- */ +#if defined(i_extern) && !defined(CSTR_X_INCLUDED) +#define CSTR_X_INCLUDED -#ifdef _i_extern static struct { int (*conv_asc)(int); uint32_t (*conv_utf)(uint32_t); @@ -439,23 +437,25 @@ cstr cstr_tocase(csview sv, int k) { cstr_shrink_to_fit(&out); return out; } -#endif +#endif // i_extern /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#ifndef CSTR_C_INCLUDED +#if defined i_extern || (defined i_implement && !defined _i_no_undef) +#define CSTR_C_INCLUDED -STC_DEF uint64_t cstr_hash(const cstr *self) { +uint64_t cstr_hash(const cstr *self) { csview sv = cstr_sv(self); return cfasthash(sv.str, sv.size); } -STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { +intptr_t cstr_find_sv(const cstr* self, csview search) { csview sv = cstr_sv(self); char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); return res ? (res - sv.str) : c_NPOS; } -STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { +char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { cstr_buf r = cstr_buffer(self); if (pos1 != pos2) { const intptr_t newlen = (r.size + pos2 - pos1); @@ -467,7 +467,7 @@ STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_ return r.data; } -STC_DEF char* _cstr_init(cstr* self, const intptr_t len, const intptr_t cap) { +char* _cstr_init(cstr* self, const intptr_t len, const intptr_t cap) { if (cap > cstr_s_cap) { self->lon.data = (char *)c_malloc(cap + 1); cstr_l_set_size(self, len); @@ -478,7 +478,7 @@ STC_DEF char* _cstr_init(cstr* self, const intptr_t len, const intptr_t cap) { return self->sml.data; } -STC_DEF void cstr_shrink_to_fit(cstr* self) { +void cstr_shrink_to_fit(cstr* self) { cstr_buf r = cstr_buffer(self); if (r.size == r.cap) return; @@ -492,7 +492,7 @@ STC_DEF void cstr_shrink_to_fit(cstr* self) { } } -STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) { +char* cstr_reserve(cstr* self, const intptr_t cap) { if (cstr_is_long(self)) { if (cap > cstr_l_cap(self)) { self->lon.data = (char *)c_realloc(self->lon.data, cap + 1); @@ -505,7 +505,7 @@ STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) { char* data = (char *)c_malloc(cap + 1); const intptr_t len = cstr_s_size(self); /* copy full short buffer to emulate realloc() */ - c_memcpy(data, self->sml.data, cstr_s_cap + 2); + c_memcpy(data, self->sml.data, sizeof self->sml); self->lon.data = data; self->lon.size = (size_t)len; cstr_l_set_cap(self, cap); @@ -514,7 +514,7 @@ STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) { return self->sml.data; } -STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) { +char* cstr_resize(cstr* self, const intptr_t size, const char value) { cstr_buf r = cstr_buffer(self); if (size > r.size) { if (size > r.cap && !(r.data = cstr_reserve(self, size))) @@ -525,20 +525,20 @@ STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) { return r.data; } -STC_DEF intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { +intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { csview sv = cstr_sv(self); if (pos > sv.size) return c_NPOS; const char* res = strstr((char*)sv.str + pos, search); return res ? (res - sv.str) : c_NPOS; } -STC_DEF char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { +char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { char* d = cstr_reserve(self, len); if (d) { c_memmove(d, str, len); _cstr_set_size(self, len); } return d; } -STC_DEF char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { +char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { cstr_buf r = cstr_buffer(self); if (r.size + len > r.cap) { const size_t off = (size_t)(str - r.data); @@ -551,7 +551,7 @@ STC_DEF char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { return r.data; } -STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { +bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { int c = fgetc(fp); if (c == EOF) return false; @@ -571,7 +571,7 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } } -STC_DEF cstr +cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { cstr out = cstr_NULL; intptr_t from = 0; char* res; @@ -587,14 +587,14 @@ cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { return out; } -STC_DEF void cstr_erase(cstr* self, const intptr_t pos, intptr_t len) { +void cstr_erase(cstr* self, const intptr_t pos, intptr_t len) { cstr_buf r = cstr_buffer(self); if (len > r.size - pos) len = r.size - pos; c_memmove(&r.data[pos], &r.data[pos + len], r.size - (pos + len)); _cstr_set_size(self, r.size - len); } -STC_DEF void cstr_u8_erase(cstr* self, const intptr_t bytepos, const intptr_t u8len) { +void cstr_u8_erase(cstr* self, const intptr_t bytepos, const intptr_t u8len) { cstr_buf r = cstr_buffer(self); intptr_t len = utf8_pos(r.data + bytepos, u8len); c_memmove(&r.data[bytepos], &r.data[bytepos + len], r.size - (bytepos + len)); @@ -609,7 +609,7 @@ STC_DEF void cstr_u8_erase(cstr* self, const intptr_t bytepos, const intptr_t u8 # pragma warning(disable: 4996) #endif -STC_DEF intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list args) { +intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list args) { va_list args2; va_copy(args2, args); const int n = vsnprintf(NULL, 0ULL, fmt, args); @@ -624,7 +624,7 @@ STC_DEF intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list # pragma warning(pop) #endif -STC_DEF cstr cstr_from_fmt(const char* fmt, ...) { +cstr cstr_from_fmt(const char* fmt, ...) { cstr s = cstr_NULL; va_list args; va_start(args, fmt); @@ -633,7 +633,7 @@ STC_DEF cstr cstr_from_fmt(const char* fmt, ...) { return s; } -STC_DEF intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...) { +intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...) { va_list args; va_start(args, fmt); const intptr_t n = cstr_vfmt(self, cstr_size(self), fmt, args); @@ -642,21 +642,21 @@ STC_DEF intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...) { } /* NB! self-data in args is UB */ -STC_DEF intptr_t cstr_printf(cstr* self, const char* fmt, ...) { +intptr_t cstr_printf(cstr* self, const char* fmt, ...) { va_list args; va_start(args, fmt); const intptr_t n = cstr_vfmt(self, 0, fmt, args); va_end(args); return n; } - #endif // i_implement +#endif // CSTR_C_INCLUDED + #if defined __GNUC__ && !defined __clang__ # pragma GCC diagnostic pop #endif -#endif // CSTR_H_INCLUDED #undef i_opt #undef i_header #undef i_static #undef i_implement -#undef _i_extern +#undef i_extern diff --git a/include/stc/csview.h b/include/stc/csview.h index e8a3ad9b..d38d5f59 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,12 +20,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#define _i_no_undef +#include "utf8.h" + #ifndef CSVIEW_H_INCLUDED #define CSVIEW_H_INCLUDED -#include "ccommon.h" -#include "utf8.h" - #define csview_NULL c_sv_1("") #define csview_init() csview_NULL #define csview_drop(p) c_default_drop(p) @@ -33,12 +33,12 @@ #define csview_lit(literal) c_sv_1(literal) #define csview_from_n(str, n) c_sv_2(str, n) -STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); -STC_API intptr_t csview_find_sv(csview sv, csview search); -STC_API uint64_t csview_hash(const csview *self); -STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); -STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); -STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); +extern csview_iter csview_advance(csview_iter it, intptr_t pos); +extern intptr_t csview_find_sv(csview sv, csview search); +extern uint64_t csview_hash(const csview *self); +extern csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); +extern csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); +extern csview csview_token(csview sv, const char* sep, intptr_t* start); STC_INLINE csview csview_from(const char* str) { return c_LITERAL(csview){str, c_strlen(str)}; } @@ -147,10 +147,14 @@ STC_INLINE int csview_icmp(const csview* x, const csview* y) STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } +#endif // CSVIEW_H_INCLUDED + /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#ifndef CSVIEW_C_INCLUDED +#if defined i_extern || (defined i_implement && !defined _i_no_undef) +#define CSVIEW_C_INCLUDED -STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { +csview_iter csview_advance(csview_iter it, intptr_t pos) { int inc = -1; if (pos > 0) pos = -pos, inc = 1; while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; @@ -159,15 +163,15 @@ STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { return it; } -STC_DEF intptr_t csview_find_sv(csview sv, csview search) { +intptr_t csview_find_sv(csview sv, csview search) { char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); return res ? (res - sv.str) : c_NPOS; } -STC_DEF uint64_t csview_hash(const csview *self) +uint64_t csview_hash(const csview *self) { return cfasthash(self->str, self->size); } -STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { +csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { if (pos < 0) { pos += sv.size; if (pos < 0) pos = 0; @@ -178,7 +182,7 @@ STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { return sv; } -STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { +csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { if (p1 < 0) { p1 += sv.size; if (p1 < 0) p1 = 0; @@ -189,7 +193,7 @@ STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { return sv; } -STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { +csview csview_token(csview sv, const char* sep, intptr_t* start) { intptr_t sep_size = c_strlen(sep); csview slice = {sv.str + *start, sv.size - *start}; const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 512dbf67..747c654d 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -264,7 +264,7 @@ _cx_memb(_sort)(_cx_self* self) { } #endif // !c_no_cmp /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF _cx_self _cx_memb(_init)(void) { diff --git a/include/stc/forward.h b/include/stc/forward.h index 9eafb857..484a8b63 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -24,6 +24,7 @@ #define STC_FORWARD_H_INCLUDED #include +#include #define forward_carc(CX, VAL) _c_carc_types(CX, VAL) #define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL) diff --git a/include/stc/utf8.h b/include/stc/utf8.h index a4cc3846..338f0db9 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -1,3 +1,4 @@ + #ifndef UTF8_H_INCLUDED #define UTF8_H_INCLUDED @@ -5,7 +6,6 @@ #include "forward.h" #include "ccommon.h" -// utf8 methods defined in src/utf8code.c: enum { U8G_Cc, U8G_Lt, U8G_Nd, U8G_Nl, U8G_Pc, U8G_Pd, U8G_Pf, U8G_Pi, @@ -16,6 +16,7 @@ enum { U8G_SIZE }; +// utf8 methods defined in src/utf8code.c: extern bool utf8_isgroup(int group, uint32_t c); extern bool utf8_isalpha(uint32_t c); extern uint32_t utf8_casefold(uint32_t c); @@ -112,9 +113,16 @@ STC_INLINE const char* utf8_at(const char *s, intptr_t index) { STC_INLINE intptr_t utf8_pos(const char* s, intptr_t index) { return (intptr_t)(utf8_at(s, index) - s); } - #endif // UTF8_H_INCLUDED -#if defined(i_extern) + +#if defined i_extern || (defined i_implement && !defined _i_no_undef) # include "../../src/utf8code.c" -# undef i_extern #endif +#ifndef _i_no_undef +#undef i_static +#undef i_header +#undef i_implement +#undef i_extern +#undef i_opt +#endif +#undef _i_no_undef diff --git a/misc/examples/arc_containers.c b/misc/examples/arc_containers.c index d6a0afa8..7038734e 100644 --- a/misc/examples/arc_containers.c +++ b/misc/examples/arc_containers.c @@ -1,6 +1,6 @@ // Create a stack and a list of shared pointers to maps, // and demonstrate sharing and cloning of maps. -#define i_static +#define i_implement #include #include #define i_type Map diff --git a/misc/examples/astar.c b/misc/examples/astar.c index dae6d609..db6bbd70 100644 --- a/misc/examples/astar.c +++ b/misc/examples/astar.c @@ -4,6 +4,7 @@ // This is a reimplementation of the CTL example to STC: // https://github.com/glouw/ctl/blob/master/examples/astar.c // https://www.redblobgames.com/pathfinding/a-star/introduction.html +#define i_implement #include #include #include diff --git a/misc/examples/books.c b/misc/examples/books.c index a62769b0..7f0660b8 100644 --- a/misc/examples/books.c +++ b/misc/examples/books.c @@ -1,4 +1,5 @@ // https://doc.rust-lang.org/std/collections/struct.HashMap.html +#define i_implement #include #define i_key_str #define i_val_str diff --git a/misc/examples/box.c b/misc/examples/box.c index 9954883c..e352aa2b 100644 --- a/misc/examples/box.c +++ b/misc/examples/box.c @@ -1,4 +1,5 @@ /* cbox: heap allocated boxed type */ +#define i_implement #include typedef struct { cstr name, last; } Person; diff --git a/misc/examples/complex.c b/misc/examples/complex.c index c730db33..2d8dbf62 100644 --- a/misc/examples/complex.c +++ b/misc/examples/complex.c @@ -5,10 +5,9 @@ // using StackList = std::stack; // using ListMap = std::unordered_map>; // using MapMap = std::unordered_map; - +#define i_implement #include - #define i_type FloatStack #define i_val float #include diff --git a/misc/examples/convert.c b/misc/examples/convert.c index c5649c55..318f09b8 100644 --- a/misc/examples/convert.c +++ b/misc/examples/convert.c @@ -1,3 +1,4 @@ +#define i_implement #include #include @@ -9,7 +10,6 @@ #include #define i_val_str -#define i_extern // define _clist_mergesort() once #include int main() diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 2585fb81..63162ba3 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -1,4 +1,4 @@ -#define i_static +#define i_implement #include #include #include diff --git a/misc/examples/csmap_erase.c b/misc/examples/csmap_erase.c index 568dae29..9433d370 100644 --- a/misc/examples/csmap_erase.c +++ b/misc/examples/csmap_erase.c @@ -1,5 +1,6 @@ // map_erase.c // From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16 +#define i_implement #include #include diff --git a/misc/examples/csmap_find.c b/misc/examples/csmap_find.c index 92dd0031..a8928410 100644 --- a/misc/examples/csmap_find.c +++ b/misc/examples/csmap_find.c @@ -1,5 +1,6 @@ // This implements the c++ std::map::find example at: // https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17 +#define i_implement #include #define i_key int diff --git a/misc/examples/csmap_insert.c b/misc/examples/csmap_insert.c index 7708fdc9..f96cc08f 100644 --- a/misc/examples/csmap_insert.c +++ b/misc/examples/csmap_insert.c @@ -5,6 +5,7 @@ #define i_tag ii // Map of int => int #include +#define i_implement #include #define i_key int #define i_val_str diff --git a/misc/examples/cstr_match.c b/misc/examples/cstr_match.c index 58cf8884..10a843cf 100644 --- a/misc/examples/cstr_match.c +++ b/misc/examples/cstr_match.c @@ -1,3 +1,4 @@ +#define i_implement #include #include #include diff --git a/misc/examples/demos.c b/misc/examples/demos.c index de92e378..8488dfb9 100644 --- a/misc/examples/demos.c +++ b/misc/examples/demos.c @@ -1,3 +1,4 @@ +#define i_implement #include void stringdemo1() diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index 8ea3e6a1..f9505aa9 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -1,6 +1,7 @@ #include #define i_extern #include +#define i_implement #include #include #include diff --git a/misc/examples/gauss2.c b/misc/examples/gauss2.c index e786824b..67586181 100644 --- a/misc/examples/gauss2.c +++ b/misc/examples/gauss2.c @@ -1,8 +1,9 @@ #include #include -#include +#define i_implement #include +#include // Declare int -> int sorted map. #define i_key int diff --git a/misc/examples/hashmap.c b/misc/examples/hashmap.c index 47a3bcff..cf11b7f7 100644 --- a/misc/examples/hashmap.c +++ b/misc/examples/hashmap.c @@ -1,4 +1,5 @@ // https://doc.rust-lang.org/rust-by-example/std/hash.html +#define i_implement #include #define i_key_str #define i_val_str diff --git a/misc/examples/inits.c b/misc/examples/inits.c index 1f01f88a..a3a6c4d2 100644 --- a/misc/examples/inits.c +++ b/misc/examples/inits.c @@ -1,3 +1,4 @@ +#define i_implement #include #define i_key int @@ -25,7 +26,6 @@ inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) { #define i_val ipair_t #define i_cmp ipair_cmp #define i_tag ip -#define i_extern // define _clist_mergesort() once #include #define i_val float diff --git a/misc/examples/list_splice.c b/misc/examples/list_splice.c index 73015454..e457694d 100644 --- a/misc/examples/list_splice.c +++ b/misc/examples/list_splice.c @@ -2,7 +2,6 @@ #define i_val int #define i_tag i -#define i_extern // define _clist_mergesort() once #include void print_ilist(const char* s, clist_i list) diff --git a/misc/examples/make.sh b/misc/examples/make.sh index d58ed0cb..61d9f879 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -6,7 +6,7 @@ if [ "$(uname)" = 'Linux' ]; then oflag='-o ' fi -cc=gcc; cflags="-DSTC_STATIC -std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-implicit-fallthrough -Wno-missing-field-initializers" +cc=gcc; cflags="-std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-implicit-fallthrough -Wno-missing-field-initializers" #cc=gcc; cflags="-DSTC_STATIC -std=c99 -g -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" #cc=tcc; cflags="-DSTC_STATIC -std=c99 -Wall" #cc=clang; cflags="-DSTC_STATIC -std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -Wno-missing-field-initializers" diff --git a/misc/examples/mapmap.c b/misc/examples/mapmap.c index 668da5de..d3065659 100644 --- a/misc/examples/mapmap.c +++ b/misc/examples/mapmap.c @@ -1,5 +1,5 @@ // create a structure like: std::map>: - +#define i_implement #include // People: std::map diff --git a/misc/examples/mmap.c b/misc/examples/mmap.c index 0394a2df..63312e04 100644 --- a/misc/examples/mmap.c +++ b/misc/examples/mmap.c @@ -2,6 +2,7 @@ // https://en.cppreference.com/w/cpp/container/multimap/insert // Multimap entries +#define i_implement #include #define i_val_str #include diff --git a/misc/examples/multimap.c b/misc/examples/multimap.c index d8981a81..dc4a1ee0 100644 --- a/misc/examples/multimap.c +++ b/misc/examples/multimap.c @@ -1,3 +1,4 @@ +#define i_implement #include // Olympics multimap example diff --git a/misc/examples/music_arc.c b/misc/examples/music_arc.c index 87a57783..9c7173ef 100644 --- a/misc/examples/music_arc.c +++ b/misc/examples/music_arc.c @@ -1,5 +1,6 @@ // shared_ptr-examples.cpp // based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 +#define i_implement #include typedef struct diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c index 1f50db83..277bcbc2 100644 --- a/misc/examples/new_map.c +++ b/misc/examples/new_map.c @@ -1,3 +1,4 @@ +#define i_implement #include #include diff --git a/misc/examples/new_smap.c b/misc/examples/new_smap.c index 2eaae836..77c4cdce 100644 --- a/misc/examples/new_smap.c +++ b/misc/examples/new_smap.c @@ -1,3 +1,4 @@ +#define i_implement #include #include diff --git a/misc/examples/new_sptr.c b/misc/examples/new_sptr.c index 1b72e4f5..aa8dd175 100644 --- a/misc/examples/new_sptr.c +++ b/misc/examples/new_sptr.c @@ -1,3 +1,4 @@ +#define i_implement #include typedef struct { cstr name, last; } Person; diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c index c931089d..b4b926da 100644 --- a/misc/examples/person_arc.c +++ b/misc/examples/person_arc.c @@ -1,4 +1,5 @@ /* cbox: heap allocated boxed type */ +#define i_implement #include #include diff --git a/misc/examples/phonebook.c b/misc/examples/phonebook.c index 38a71089..faf7566e 100644 --- a/misc/examples/phonebook.c +++ b/misc/examples/phonebook.c @@ -20,7 +20,7 @@ // IN THE SOFTWARE. // Program to emulates the phone book. - +#define i_implement #include #define i_key_str diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c index b9ec2476..b5099ed5 100644 --- a/misc/examples/printspan.c +++ b/misc/examples/printspan.c @@ -1,6 +1,7 @@ // printspan.c #include +#define i_implement #include #define i_val int #include diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c index 01bcdc44..8dd52aee 100644 --- a/misc/examples/rawptr_elements.c +++ b/misc/examples/rawptr_elements.c @@ -1,6 +1,6 @@ #include #include - +#define i_implement #include // Create cmap of cstr => long* diff --git a/misc/examples/read.c b/misc/examples/read.c index edc89f0e..545d706a 100644 --- a/misc/examples/read.c +++ b/misc/examples/read.c @@ -1,3 +1,4 @@ +#define i_implement #include #include #define i_val_str diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c index e49ebd0b..b4932015 100644 --- a/misc/examples/regex_match.c +++ b/misc/examples/regex_match.c @@ -1,5 +1,6 @@ #define i_extern #include +#define i_implement #include #define i_val float diff --git a/misc/examples/replace.c b/misc/examples/replace.c index cf5b45cb..9ac26c07 100644 --- a/misc/examples/replace.c +++ b/misc/examples/replace.c @@ -1,3 +1,4 @@ +#define i_implement #include int main () diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c index 2bc6fc07..658c46a1 100644 --- a/misc/examples/splitstr.c +++ b/misc/examples/splitstr.c @@ -1,6 +1,7 @@ #include #define i_extern // cstr + utf8 functions #include +#define i_implement #include int main() diff --git a/misc/examples/sso_map.c b/misc/examples/sso_map.c index 70450e21..b78dcb2e 100644 --- a/misc/examples/sso_map.c +++ b/misc/examples/sso_map.c @@ -1,3 +1,4 @@ +#define i_implement #include #define i_key_str #define i_val_str diff --git a/misc/examples/sso_substr.c b/misc/examples/sso_substr.c index 4b2dbcc8..9b062eed 100644 --- a/misc/examples/sso_substr.c +++ b/misc/examples/sso_substr.c @@ -1,4 +1,6 @@ +#define i_implement #include +#define i_implement #include int main () diff --git a/misc/examples/sview_split.c b/misc/examples/sview_split.c index 31a28e51..782e4096 100644 --- a/misc/examples/sview_split.c +++ b/misc/examples/sview_split.c @@ -1,4 +1,6 @@ +#define i_implement #include +#define i_implement #include int main() diff --git a/misc/examples/unordered_set.c b/misc/examples/unordered_set.c index 90c78521..006a1e80 100644 --- a/misc/examples/unordered_set.c +++ b/misc/examples/unordered_set.c @@ -1,5 +1,6 @@ // https://iq.opengenus.org/containers-cpp-stl/ // C program to demonstrate various function of stc cset +#define i_implement #include #include #define i_key_str diff --git a/misc/examples/utf8replace_c.c b/misc/examples/utf8replace_c.c index 3cde8701..17352fee 100644 --- a/misc/examples/utf8replace_c.c +++ b/misc/examples/utf8replace_c.c @@ -1,3 +1,4 @@ +#define i_implement #include int main() diff --git a/misc/examples/vikings.c b/misc/examples/vikings.c index abb909c3..cf087119 100644 --- a/misc/examples/vikings.c +++ b/misc/examples/vikings.c @@ -1,3 +1,4 @@ +#define i_implement #include typedef struct Viking { diff --git a/src/cregex.c b/src/cregex.c index 730d35a4..62a64b11 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -25,9 +25,24 @@ THE SOFTWARE. */ #ifndef CREGEX_C_INCLUDED #define CREGEX_C_INCLUDED -#include -#include // header only + #include +#ifdef i_extern +# define _i_extern +#endif +#ifndef CREGEX_H_INCLUDED +# include "../include/stc/cregex.h" +#endif +#ifdef _i_extern +# include "utf8code.c" +#endif +#ifdef _i_extern +# define i_implement +#else +# undef i_implement +#endif +#undef _i_extern +#include "../include/stc/cstr.h" typedef uint32_t _Rune; /* Utf8 code point */ typedef int32_t _Token; diff --git a/src/libstc.c b/src/libstc.c index bc61e37c..99611e05 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,4 +1,16 @@ +#include +#if 1 +#define i_extern +#include "../include/stc/utf8.h" +#define i_implement +#include "../include/stc/cstr.h" +#define i_implement +#include "../include/stc/cregex.h" +#define i_implement +#include "../include/stc/csview.h" +#else #define i_extern #include "../include/stc/cregex.h" #define i_implement #include "../include/stc/csview.h" +#endif diff --git a/src/utf8code.c b/src/utf8code.c index 496f5eef..6a133050 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -1,6 +1,9 @@ #ifndef UTF8_C_INCLUDED #define UTF8_C_INCLUDED -#include // header only + +#ifndef UTF8_H_INCLUDED +#include "../include/stc/utf8.h" /* header only */ +#endif #include "utf8tabs.inc" const uint8_t utf8_dtab[] = { -- cgit v1.2.3 From 5f935739d2ce280beda36c7a7ddb0e0ee34c8fb3 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 9 Jun 2023 22:37:15 +0200 Subject: Rename i_extern template flag to i_import. i_extern still available, but deprecated. --- README.md | 6 +++--- docs/clist_api.md | 1 - docs/cregex_api.md | 4 ++-- docs/csview_api.md | 4 ++-- include/stc/ccommon.h | 8 ++++---- include/stc/crand.h | 2 +- include/stc/cregex.h | 4 ++-- include/stc/cspan.h | 2 +- include/stc/cstr.h | 10 +++++----- include/stc/csview.h | 5 ++--- include/stc/priv/template2.h | 2 +- include/stc/utf8.h | 4 ++-- misc/examples/forfilter.c | 2 +- misc/examples/regex1.c | 2 +- misc/examples/regex2.c | 2 +- misc/examples/regex_match.c | 2 +- misc/examples/regex_replace.c | 2 +- misc/examples/splitstr.c | 2 +- misc/tests/cregex_test.c | 2 +- src/cregex.c | 2 +- src/libstc.c | 4 ++-- 21 files changed, 35 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index e63a56e4..f14858e7 100644 --- a/README.md +++ b/README.md @@ -333,6 +333,7 @@ After erasing the elements found: --- ## Installation +*NEEDS REWRITE!* Because it is headers-only, headers can simply be included in your program. By default, functions are static (some inlined). You may add the *include* folder to the **CPATH** environment variable to let GCC, Clang, and TinyC locate the headers. @@ -345,8 +346,7 @@ You may also cherry-pick shared linking mode on individual containers by `#defin `#define i_implement`, or force static symbols by `#define i_static` before container includes. As a special case, there may be non-templated functions in templated containers that should be implemented only -once and if needed. Currently, define `i_extern` before including **clist** for its sorting function, and before -**cregex** or **utf8** to implement them (global `STC_EXTERN` can alternatively be defined). +once and if needed. Currently, define `i_import` before including **cregex** or **utf8** to implement them. It is possible to generate single headers by executing the python script `src/singleheader.py header-file > single`. @@ -356,7 +356,7 @@ or define your own, e.g.: ```c // stc_libs.c #define STC_IMPLEMENT // implement all the following as shared objects - +#define i_implement #include #include "Point.h" diff --git a/docs/clist_api.md b/docs/clist_api.md index 36935c88..51b7af6a 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -118,7 +118,6 @@ Interleave *push_front()* / *push_back()* then *sort()*: ```c #define i_type DList #define i_val double -#define i_extern // link with sort() fn. #include #include diff --git a/docs/cregex_api.md b/docs/cregex_api.md index fc86cc63..ff69c549 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -99,7 +99,7 @@ If an error occurs ```cregex_compile``` returns a negative error code stored in [ [Run this code](https://godbolt.org/z/z434TMKfo) ] ```c -#define i_extern // include external cstr, utf8, cregex functions implementation. +#define i_import // include dependent cstr, utf8 and cregex function definitions. #include int main() { @@ -151,7 +151,7 @@ c_formatch (it, &re, input) ## Using cregex in a project -The easiest is to `#define i_extern` before `#include `. Make sure to do that in one translation unit only. +The easiest is to `#define i_import` before `#include `. Make sure to do that in one translation unit only. For reference, **cregex** uses the following files: - `stc/cregex.h`, `stc/utf8.h`, `stc/csview.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` diff --git a/docs/csview_api.md b/docs/csview_api.md index b697b7d6..879822d3 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -148,8 +148,8 @@ red Apples ### Example 2: UTF8 handling ```c -#define i_extern -#include // i_extern: implement cstr + dependencies (utf8) +#define i_import // include dependent cstr, utf8 and cregex function definitions. +#include int main() { diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 87522a6e..e491a567 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -241,6 +241,9 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { #undef STC_API #undef STC_DEF +#ifdef i_extern +# define i_import +#endif #if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \ defined(i_implement) || defined(STC_IMPLEMENT)) #define STC_API extern @@ -250,9 +253,6 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { #define STC_API static inline #define STC_DEF static inline #endif -#if defined(STC_EXTERN) - #define i_extern -#endif -#if defined(STC_IMPLEMENT) || defined(i_extern) +#if defined(STC_IMPLEMENT) || defined(i_import) #define i_implement #endif diff --git a/include/stc/crand.h b/include/stc/crand.h index b9687c01..95a65fb0 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -158,4 +158,4 @@ STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) { #undef i_static #undef i_header #undef i_implement -#undef i_extern +#undef i_import diff --git a/include/stc/cregex.h b/include/stc/cregex.h index e6180a31..43a7fcbf 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -161,12 +161,12 @@ void cregex_drop(cregex* re); #if defined i_implement # include "../../src/cregex.c" #endif -#if defined i_extern +#if defined i_import # include "../../src/utf8code.c" #endif #endif // CREGEX_H_INCLUDED #undef i_opt #undef i_header #undef i_static -#undef i_extern +#undef i_import #undef i_implement diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 5b592098..dd6cb1c0 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -265,4 +265,4 @@ STC_DEF intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank, #undef i_header #undef i_implement #undef i_static -#undef i_extern +#undef i_import diff --git a/include/stc/cstr.h b/include/stc/cstr.h index ae80dab4..f47889b4 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -405,8 +405,8 @@ STC_INLINE bool cstr_getline(cstr *self, FILE *fp) #endif // CSTR_H_INCLUDED -/* -------------------------- EXTERN ------------------------- */ -#if defined(i_extern) && !defined(CSTR_X_INCLUDED) +/* -------------------------- UTF8 CASE CONVERSION ------------------------- */ +#if defined(i_import) && !defined(CSTR_X_INCLUDED) #define CSTR_X_INCLUDED static struct { @@ -437,11 +437,11 @@ cstr cstr_tocase(csview sv, int k) { cstr_shrink_to_fit(&out); return out; } -#endif // i_extern +#endif // i_import /* -------------------------- IMPLEMENTATION ------------------------- */ #ifndef CSTR_C_INCLUDED -#if defined i_extern || (defined i_implement && !defined _i_no_undef) +#if defined i_import || (defined i_implement && !defined _i_no_undef) #define CSTR_C_INCLUDED uint64_t cstr_hash(const cstr *self) { @@ -659,4 +659,4 @@ intptr_t cstr_printf(cstr* self, const char* fmt, ...) { #undef i_header #undef i_static #undef i_implement -#undef i_extern +#undef i_import diff --git a/include/stc/csview.h b/include/stc/csview.h index d38d5f59..ee217e98 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -151,7 +151,7 @@ STC_INLINE bool csview_eq(const csview* x, const csview* y) /* -------------------------- IMPLEMENTATION ------------------------- */ #ifndef CSVIEW_C_INCLUDED -#if defined i_extern || (defined i_implement && !defined _i_no_undef) +#if defined i_import || (defined i_implement && !defined _i_no_undef) #define CSVIEW_C_INCLUDED csview_iter csview_advance(csview_iter it, intptr_t pos) { @@ -201,11 +201,10 @@ csview csview_token(csview sv, const char* sep, intptr_t* start) { *start += tok.size + sep_size; return tok; } - #endif #endif #undef i_opt #undef i_header #undef i_implement #undef i_static -#undef i_extern +#undef i_import diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index d7588ca0..75402150 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -59,7 +59,7 @@ #undef i_header #undef i_implement #undef i_static -#undef i_extern +#undef i_import #undef i_allocator #undef i_malloc diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 338f0db9..e853263b 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -115,14 +115,14 @@ STC_INLINE intptr_t utf8_pos(const char* s, intptr_t index) { return (intptr_t)(utf8_at(s, index) - s); } #endif // UTF8_H_INCLUDED -#if defined i_extern || (defined i_implement && !defined _i_no_undef) +#if defined i_import || (defined i_implement && !defined _i_no_undef) # include "../../src/utf8code.c" #endif #ifndef _i_no_undef #undef i_static #undef i_header #undef i_implement -#undef i_extern +#undef i_import #undef i_opt #endif #undef _i_no_undef diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index f9505aa9..94a84065 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -1,5 +1,5 @@ #include -#define i_extern +#define i_import #include #define i_implement #include diff --git a/misc/examples/regex1.c b/misc/examples/regex1.c index 4a56b8ac..d8032358 100644 --- a/misc/examples/regex1.c +++ b/misc/examples/regex1.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include int main(int argc, char* argv[]) diff --git a/misc/examples/regex2.c b/misc/examples/regex2.c index 3133f7c2..5718a1d8 100644 --- a/misc/examples/regex2.c +++ b/misc/examples/regex2.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include int main() diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c index b4932015..ebda366f 100644 --- a/misc/examples/regex_match.c +++ b/misc/examples/regex_match.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include #define i_implement #include diff --git a/misc/examples/regex_replace.c b/misc/examples/regex_replace.c index cad195d5..2c7794af 100644 --- a/misc/examples/regex_replace.c +++ b/misc/examples/regex_replace.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include #include #include diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c index 658c46a1..32b5f17f 100644 --- a/misc/examples/splitstr.c +++ b/misc/examples/splitstr.c @@ -1,5 +1,5 @@ #include -#define i_extern // cstr + utf8 functions +#define i_import // cstr + utf8 functions #include #define i_implement #include diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 301ecf4f..3ddcc608 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include #include #include diff --git a/src/cregex.c b/src/cregex.c index 62a64b11..1af719b4 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -27,7 +27,7 @@ THE SOFTWARE. #define CREGEX_C_INCLUDED #include -#ifdef i_extern +#ifdef i_import # define _i_extern #endif #ifndef CREGEX_H_INCLUDED diff --git a/src/libstc.c b/src/libstc.c index 99611e05..afc19a08 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,6 +1,6 @@ #include #if 1 -#define i_extern +#define i_import #include "../include/stc/utf8.h" #define i_implement #include "../include/stc/cstr.h" @@ -9,7 +9,7 @@ #define i_implement #include "../include/stc/csview.h" #else -#define i_extern +#define i_import #include "../include/stc/cregex.h" #define i_implement #include "../include/stc/csview.h" -- cgit v1.2.3 From f3529a2600141dc7f84c734ea3bf5db8f7090e56 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 11 Jun 2023 07:36:31 +0200 Subject: More internal structuring --- include/stc/cstr.h | 3 +++ include/stc/csview.h | 39 +++++++++++++++++++++------------------ include/stc/utf8.h | 3 ++- src/libstc.c | 16 ++++------------ 4 files changed, 30 insertions(+), 31 deletions(-) diff --git a/include/stc/cstr.h b/include/stc/cstr.h index f47889b4..0c5b67d8 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -655,8 +655,11 @@ intptr_t cstr_printf(cstr* self, const char* fmt, ...) { #if defined __GNUC__ && !defined __clang__ # pragma GCC diagnostic pop #endif +#ifndef _i_no_undef #undef i_opt #undef i_header #undef i_static #undef i_implement #undef i_import +#endif +#undef _i_no_undef diff --git a/include/stc/csview.h b/include/stc/csview.h index ee217e98..a1893063 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -114,6 +114,22 @@ STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c #define c_fortoken(it, input, sep) \ c_fortoken_sv(it, csview_from(input), sep) +/* ---- Container helper functions ---- */ + +STC_INLINE int csview_cmp(const csview* x, const csview* y) { + intptr_t n = x->size < y->size ? x->size : y->size; + int c = c_memcmp(x->str, y->str, n); + return c ? c : (int)(x->size - y->size); +} + +STC_INLINE int csview_icmp(const csview* x, const csview* y) + { return utf8_icmp_sv(*x, *y); } + +STC_INLINE bool csview_eq(const csview* x, const csview* y) + { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } + +#endif // CSVIEW_H_INCLUDED + /* csview interaction with cstr: */ #ifdef CSTR_H_INCLUDED @@ -131,23 +147,7 @@ STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) { return csview_u8_substr(cstr_sv(self), bytepos, u8len); } - #endif -/* ---- Container helper functions ---- */ - -STC_INLINE int csview_cmp(const csview* x, const csview* y) { - intptr_t n = x->size < y->size ? x->size : y->size; - int c = c_memcmp(x->str, y->str, n); - return c ? c : (int)(x->size - y->size); -} - -STC_INLINE int csview_icmp(const csview* x, const csview* y) - { return utf8_icmp_sv(*x, *y); } - -STC_INLINE bool csview_eq(const csview* x, const csview* y) - { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } - -#endif // CSVIEW_H_INCLUDED /* -------------------------- IMPLEMENTATION ------------------------- */ #ifndef CSVIEW_C_INCLUDED @@ -203,8 +203,11 @@ csview csview_token(csview sv, const char* sep, intptr_t* start) { } #endif #endif -#undef i_opt +#ifndef _i_no_undef +#undef i_static #undef i_header #undef i_implement -#undef i_static #undef i_import +#undef i_opt +#endif +#undef _i_no_undef diff --git a/include/stc/utf8.h b/include/stc/utf8.h index e853263b..d6c759eb 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -1,10 +1,11 @@ +#include "ccommon.h" + #ifndef UTF8_H_INCLUDED #define UTF8_H_INCLUDED #include #include "forward.h" -#include "ccommon.h" enum { U8G_Cc, U8G_Lt, U8G_Nd, U8G_Nl, diff --git a/src/libstc.c b/src/libstc.c index afc19a08..7b49540a 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,16 +1,8 @@ -#include -#if 1 #define i_import -#include "../include/stc/utf8.h" -#define i_implement -#include "../include/stc/cstr.h" -#define i_implement -#include "../include/stc/cregex.h" -#define i_implement -#include "../include/stc/csview.h" -#else -#define i_import -#include "../include/stc/cregex.h" +#include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement #include "../include/stc/csview.h" +#if __STDC_VERSION__ >= 201112L +# define i_implement +# include "../include/c11/fmt.h" #endif -- cgit v1.2.3 From b564ef6bdfcd2437f1b4997f42054c45ccdedbb1 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 11 Jun 2023 14:03:16 +0200 Subject: Added priv/linkage.h and renamed priv/template2.h => priv/template_undef.h. Make all examples c++ compatible, except those using cspan.h Removed: crange_obj() Renamed: crange_make() => crange_init() Renamed: cspan_make() => cspan_init() Renamed: cstr_NULL => cstr_null Renamed: csview_NULL => csview_null --- docs/carc_api.md | 2 +- docs/cbox_api.md | 2 +- docs/ccommon_api.md | 14 +++++----- docs/cmap_api.md | 2 +- docs/cspan_api.md | 2 +- docs/cstr_api.md | 4 +-- docs/csview_api.md | 2 +- include/stc/algo/coroutine.h | 2 +- include/stc/algo/crange.h | 18 ++++++------- include/stc/algo/filter.h | 2 +- include/stc/algo/sort.h | 1 + include/stc/carc.h | 5 ++-- include/stc/cbox.h | 5 ++-- include/stc/ccommon.h | 51 +++++++++++++++---------------------- include/stc/clist.h | 3 ++- include/stc/cmap.h | 3 ++- include/stc/cpque.h | 3 ++- include/stc/cqueue.h | 3 ++- include/stc/crand.h | 3 ++- include/stc/cregex.h | 4 ++- include/stc/csmap.h | 3 ++- include/stc/cspan.h | 9 ++++--- include/stc/cstack.h | 3 ++- include/stc/cstr.h | 20 +++++++-------- include/stc/csview.h | 18 ++++++------- include/stc/cvec.h | 3 ++- include/stc/priv/linkage.h | 40 +++++++++++++++++++++++++++++ include/stc/utf8.h | 34 ++++++++++++++++++++----- misc/examples/astar.c | 2 +- misc/examples/box.c | 2 +- misc/examples/box2.c | 6 ++--- misc/examples/csmap_find.c | 12 ++++----- misc/examples/csmap_insert.c | 12 ++++----- misc/examples/dining_philosophers.c | 5 ++-- misc/examples/forfilter.c | 5 ++-- misc/examples/make.sh | 14 +++++----- misc/examples/music_arc.c | 2 +- misc/examples/new_list.c | 2 +- misc/examples/new_sptr.c | 3 ++- misc/examples/new_vec.c | 8 +++--- misc/examples/person_arc.c | 3 ++- misc/examples/prime.c | 4 ++- misc/examples/printspan.c | 8 +++--- misc/examples/read.c | 2 +- misc/examples/shape.c | 2 +- misc/examples/vikings.c | 10 ++++---- src/cregex.c | 32 +++++++++++------------ src/utf8code.c | 41 +++++++++++++++-------------- 48 files changed, 254 insertions(+), 182 deletions(-) create mode 100644 include/stc/priv/linkage.h diff --git a/docs/carc_api.md b/docs/carc_api.md index 9f3d8cb9..22e6bac2 100644 --- a/docs/carc_api.md +++ b/docs/carc_api.md @@ -67,7 +67,7 @@ bool carc_X_value_eq(const i_val* x, const i_val* y); | Type name | Type definition | Used to represent... | |:------------------|:--------------------------------------------------|:-----------------------| -| `carc_NULL` | `{NULL, NULL}` | Init nullptr const | +| `carc_null` | `{0}` | Init nullptr const | | `carc_X` | `struct { carc_X_value* get; long* use_count; }` | The carc type | | `carc_X_value` | `i_val` | The carc element type | | `carc_X_raw` | `i_valraw` | Convertion type | diff --git a/docs/cbox_api.md b/docs/cbox_api.md index 5914a5ad..9151f56d 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -64,7 +64,7 @@ bool cbox_X_value_eq(const i_val* x, const i_val* y); | Type name | Type definition | Used to represent... | |:-------------------|:--------------------------------|:------------------------| -| `cbox_NULL` | `{NULL}` | Init nullptr const | +| `cbox_null` | `{0}` | Init nullptr const | | `cbox_X` | `struct { cbox_X_value* get; }` | The cbox type | | `cbox_X_value` | `i_val` | The cbox element type | diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index cd9be505..1f0847da 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -82,17 +82,16 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i); ### crange A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: ```c -crange& crange_obj(...) // create a compound literal crange object -crange crange_make(stop); // will generate 0, 1, ..., stop-1 -crange crange_make(start, stop); // will generate start, start+1, ... stop-1 -crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop +crange crange_init(stop); // will generate 0, 1, ..., stop-1 +crange crange_init(start, stop); // will generate start, start+1, ... stop-1 +crange crange_init(start, stop, step); // will generate start, start+step, ... upto-not-including stop // note that step may be negative. crange_iter crange_begin(crange* self); crange_iter crange_end(crange* self); void crange_next(crange_iter* it); // 1. All primes less than 32: -crange r1 = crange_make(3, 32, 2); +crange r1 = crange_init(3, 32, 2); printf("2"); // first prime c_forfilter (i, crange, r1, isPrime(*i.ref)) printf(" %lld", *i.ref); @@ -100,7 +99,8 @@ c_forfilter (i, crange, r1, isPrime(*i.ref)) // 2. The first 11 primes: printf("2"); -c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2), +crange range = crange_init(3, INT64_MAX, 2); +c_forfilter (i, crange, range, isPrime(*i.ref) && c_flt_take(10) ){ @@ -140,7 +140,7 @@ bool isPrime(long long i) { int main() { // Get 10 prime numbers starting from 1000. Skip the first 15 primes, // then select every 25th prime (including the initial). - crange R = crange_make(1001, INT64_MAX, 2); // 1001, 1003, ... + crange R = crange_init(1001, INT64_MAX, 2); // 1001, 1003, ... c_forfilter (i, crange, R, isPrime(*i.ref) && diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 69e547a0..8ef322e6 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -277,7 +277,7 @@ typedef struct { cstr country; } Viking; -#define Viking_init() ((Viking){cstr_NULL, cstr_NULL}) +#define Viking_init() ((Viking){cstr_null, cstr_null}) static inline int Viking_cmp(const Viking* a, const Viking* b) { int c = cstr_cmp(&a->name, &b->name); diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 3a811ebf..c78bb8a0 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -26,7 +26,7 @@ i.e., it may be expanded multiple times. However, all integer arguments are safe `cspan_at(&ms3, i++, j++, k++)` is allowed. If the number of arguments does not match the span rank, a compile error is issued. Runtime bounds checks are enabled by default (define `STC_NDEBUG` or `NDEBUG` to disable). ```c -SpanType cspan_make(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values +SpanType cspan_init(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from compatible STC container SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from C array SpanTypeN cspan_md(ValueType* data, intptr_t xdim, ...); // make a multi-dimensional cspan diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 438dbf27..c7d19e0c 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -18,7 +18,7 @@ All cstr definitions and prototypes are available by including a single header f ## Methods ```c -cstr cstr_init(void); // constructor; same as cstr_NULL. +cstr cstr_init(void); // constructor; same as cstr_null. cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call. cstr cstr_from(const char* str); // constructor using strlen() cstr cstr_from_n(const char* str, intptr_t n); // constructor with n first bytes of str @@ -153,7 +153,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt | Name | Value | |:------------------|:------------------| | `c_NPOS` | `INTPTR_MAX` | -| `cstr_NULL` | cstr null value | +| `cstr_null` | empty cstr value | ## Example ```c diff --git a/docs/csview_api.md b/docs/csview_api.md index 879822d3..a02b007a 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -112,7 +112,7 @@ uint64_t csview_hash(const csview* x); | Name | Value | Usage | |:---------------|:---------------------|:---------------------------------------------| -| `csview_NULL` | same as `c_sv("")` | `sview = csview_NULL;` | +| `csview_null` | same as `c_sv("")` | `sview = csview_null;` | | `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` | ## Example diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 67ea5a40..5cd6d68f 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -56,7 +56,7 @@ int main(void) { return 0; } */ -#include +#include "../ccommon.h" enum { cco_state_final = -1, diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h index 56c317da..34ed541b 100644 --- a/include/stc/algo/crange.h +++ b/include/stc/algo/crange.h @@ -27,14 +27,15 @@ int main() { - crange r1 = crange_make(80, 90); + crange r1 = crange_init(80, 90); c_foreach (i, crange, r1) printf(" %lld", *i.ref); puts(""); // use a temporary crange object. int a = 100, b = INT32_MAX; - c_forfilter (i, crange, crange_obj(a, b, 8), + crange r2 = crange_init(a, b, 8); + c_forfilter (i, crange, r2, c_flt_skip(i, 10) && c_flt_take(i, 3)) printf(" %lld", *i.ref); @@ -44,20 +45,17 @@ int main() #ifndef STC_CRANGE_H_INCLUDED #define STC_CRANGE_H_INCLUDED -#include - -#define crange_obj(...) \ - (*(crange[]){crange_make(__VA_ARGS__)}) +#include "../ccommon.h" typedef long long crange_value; typedef struct { crange_value start, end, step, value; } crange; typedef struct { crange_value *ref, end, step; } crange_iter; -#define crange_make(...) c_MACRO_OVERLOAD(crange_make, __VA_ARGS__) -#define crange_make_1(stop) crange_make_3(0, stop, 1) -#define crange_make_2(start, stop) crange_make_3(start, stop, 1) +#define crange_init(...) c_MACRO_OVERLOAD(crange_init, __VA_ARGS__) +#define crange_init_1(stop) crange_init_3(0, stop, 1) +#define crange_init_2(start, stop) crange_init_3(start, stop, 1) -STC_INLINE crange crange_make_3(crange_value start, crange_value stop, crange_value step) +STC_INLINE crange crange_init_3(crange_value start, crange_value stop, crange_value step) { crange r = {start, stop - (step > 0), step}; return r; } STC_INLINE crange_iter crange_begin(crange* self) diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index 8dc1ad74..f5de1811 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -47,7 +47,7 @@ int main() #ifndef STC_FILTER_H_INCLUDED #define STC_FILTER_H_INCLUDED -#include +#include "../ccommon.h" // c_forfilter: diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h index bbd58427..2e73b0fb 100644 --- a/include/stc/algo/sort.h +++ b/include/stc/algo/sort.h @@ -42,6 +42,7 @@ int main() { } */ #include "../ccommon.h" + #ifndef i_type #define i_at(arr, idx) (&arr[idx]) #ifndef i_tag diff --git a/include/stc/carc.h b/include/stc/carc.h index 756b604f..749b1fc1 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -49,10 +49,11 @@ int main() { c_drop(ArcPers, &p, &q); } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CARC_H_INCLUDED #define CARC_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include @@ -72,7 +73,7 @@ int main() { #define c_atomic_dec_and_test(v) (atomic_fetch_sub(v, 1) == 1) #endif -#define carc_NULL {NULL, NULL} +#define carc_null {0} #endif // CARC_H_INCLUDED #define _i_prefix carc_ diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 699b32ac..d7f6246d 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -57,15 +57,16 @@ int main() { } } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CBOX_H_INCLUDED #define CBOX_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include #include -#define cbox_NULL {NULL} +#define cbox_null {0} #endif // CBOX_H_INCLUDED #define _i_prefix cbox_ diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index e491a567..5f280218 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -117,10 +117,6 @@ /* Function macros and others */ -#define c_init(C, ...) \ - C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) -#define c_make(C, ...) c_init(C, __VA_ARGS__) // [deprecated] - #define c_litstrlen(literal) (c_sizeof("" literal) - 1) #define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a]) @@ -210,16 +206,23 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { ; (_inc > 0) ^ (i > _end); i += _inc) #ifndef __cplusplus + #define c_init(C, ...) \ + C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) #define c_forlist(it, T, ...) \ - for (struct {T* ref; int size, index;} \ - it = {.ref=(T[])__VA_ARGS__, .size=(int)(sizeof((T[])__VA_ARGS__)/sizeof(T))} \ - ; it.index < it.size; ++it.ref, ++it.index) + for (struct {T* ref; int size, index;} \ + it = {.ref=(T[])__VA_ARGS__, .size=(int)(sizeof((T[])__VA_ARGS__)/sizeof(T))} \ + ; it.index < it.size; ++it.ref, ++it.index) #else - #include - #define c_forlist(it, T, ...) \ - for (struct {std::initializer_list _il; std::initializer_list::iterator ref; size_t size, index;} \ - it = {._il=__VA_ARGS__, .ref=it._il.begin(), .size=it._il.size()} \ - ; it.index < it.size; ++it.ref, ++it.index) + #include + template + inline C _from_n(C (*func)(const T[], intptr_t), std::initializer_list il) + { return func(&*il.begin(), il.size()); } + + #define c_init(C, ...) _from_n(C##_from_n, __VA_ARGS__) + #define c_forlist(it, T, ...) \ + for (struct {std::initializer_list _il; std::initializer_list::iterator ref; size_t size, index;} \ + it = {._il=__VA_ARGS__, .ref=it._il.begin(), .size=it._il.size()} \ + ; it.index < it.size; ++it.ref, ++it.index) #endif #define c_drop(C, ...) \ @@ -236,23 +239,9 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { #define c_umul128(a, b, lo, hi) \ asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) #endif -#endif // CCOMMON_H_INCLUDED -#undef STC_API -#undef STC_DEF - -#ifdef i_extern -# define i_import -#endif -#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \ - defined(i_implement) || defined(STC_IMPLEMENT)) - #define STC_API extern - #define STC_DEF -#else - #define i_static - #define STC_API static inline - #define STC_DEF static inline -#endif -#if defined(STC_IMPLEMENT) || defined(i_import) - #define i_implement -#endif +// [deprecated]: +#define c_make(...) c_init(__VA_ARGS__) +#define cspan_make(...) cspan_init(__VA_ARGS__) +#define crange_make(...) crange_init(__VA_ARGS__) +#endif // CCOMMON_H_INCLUDED diff --git a/include/stc/clist.h b/include/stc/clist.h index 310db204..4d05a3d1 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -51,9 +51,10 @@ } } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CLIST_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include #include diff --git a/include/stc/cmap.h b/include/stc/cmap.h index f6c3eb07..2e234fb5 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -47,9 +47,10 @@ int main(void) { cmap_ichar_drop(&m); } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CMAP_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include #include diff --git a/include/stc/cpque.h b/include/stc/cpque.h index 31a53ece..b66c7735 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -20,9 +20,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CPQUE_H_INCLUDED +#include "ccommon.h" #include #include "forward.h" #endif diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 28515877..3adc1bcb 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -20,9 +20,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CQUEUE_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include #include diff --git a/include/stc/crand.h b/include/stc/crand.h index 95a65fb0..89b681cd 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -20,10 +20,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CRAND_H_INCLUDED #define CRAND_H_INCLUDED +#include "ccommon.h" /* // crand: Pseudo-random number generator #include "stc/crand.h" diff --git a/include/stc/cregex.h b/include/stc/cregex.h index 43a7fcbf..1d1d441f 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -22,6 +22,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "priv/linkage.h" + #ifndef CREGEX_H_INCLUDED #define CREGEX_H_INCLUDED /* @@ -157,6 +159,7 @@ cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char /* destroy regex */ void cregex_drop(cregex* re); +#endif // CREGEX_H_INCLUDED #if defined i_implement # include "../../src/cregex.c" @@ -164,7 +167,6 @@ void cregex_drop(cregex* re); #if defined i_import # include "../../src/utf8code.c" #endif -#endif // CREGEX_H_INCLUDED #undef i_opt #undef i_header #undef i_static diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 7638b8f2..28598f0a 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -49,9 +49,10 @@ int main(void) { csmap_sx_drop(&m); } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CSMAP_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include #include diff --git a/include/stc/cspan.h b/include/stc/cspan.h index dd6cb1c0..d7a72267 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -60,6 +60,7 @@ int demo2() { #ifndef STC_CSPAN_H_INCLUDED #define STC_CSPAN_H_INCLUDED +#include "priv/linkage.h" #include "ccommon.h" #define using_cspan(...) c_MACRO_OVERLOAD(using_cspan, __VA_ARGS__) @@ -80,7 +81,7 @@ int demo2() { return (Self){.data=raw, .shape={(int32_t)n}}; \ } \ STC_INLINE Self Self##_slice_(Self##_value* v, const int32_t shape[], const int32_t stri[], \ - const int rank, const int32_t a[][2]) { \ + const int rank, const int32_t a[][2]) { \ Self s = {.data=v}; int outrank; \ s.data += _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ c_ASSERT(outrank == RANK); \ @@ -115,8 +116,8 @@ typedef struct { int32_t d[6]; } cspan_idx6; #define cspan_md(array, ...) \ {.data=array, .shape={__VA_ARGS__}, .stride={.d={__VA_ARGS__}}} -/* For static initialization, use cspan_make(). c_init() for non-static only. */ -#define cspan_make(SpanType, ...) \ +/* For static initialization, use cspan_init(). c_init() for non-static only. */ +#define cspan_init(SpanType, ...) \ {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}} #define cspan_slice(OutSpan, parent, ...) \ @@ -210,6 +211,7 @@ STC_API intptr_t _cspan_next2(int rank, int32_t pos[], const int32_t shape[], co STC_API intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank, const int32_t shape[], const int32_t stri[], int rank, const int32_t a[][2]); +#endif // STC_CSPAN_H_INCLUDED /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) @@ -260,7 +262,6 @@ STC_DEF intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank, return off; } #endif -#endif #undef i_opt #undef i_header #undef i_implement diff --git a/include/stc/cstack.h b/include/stc/cstack.h index fa0fab2b..fb4eae4b 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -20,10 +20,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CSTACK_H_INCLUDED #define CSTACK_H_INCLUDED +#include "ccommon.h" #include #include "forward.h" #endif // CSTACK_H_INCLUDED diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 0c5b67d8..bdfee39b 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -24,7 +24,7 @@ /* A string type with short string optimization in C99 with good small-string * optimization (22 characters with 24 bytes string). */ -#define _i_no_undef +#define _i_nested #include "utf8.h" #ifndef CSTR_H_INCLUDED @@ -67,7 +67,7 @@ extern char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); /**************************** PUBLIC API **********************************/ #define cstr_lit(literal) cstr_from_n(literal, c_litstrlen(literal)) -#define cstr_NULL (c_LITERAL(cstr){{{0}, 0}}) +#define cstr_null (c_LITERAL(cstr){0}) #define cstr_toraw(self) cstr_str(self) extern char* cstr_reserve(cstr* self, intptr_t cap); @@ -97,7 +97,7 @@ STC_INLINE csview cstr_sv(const cstr* s) { } STC_INLINE cstr cstr_init(void) - { return cstr_NULL; } + { return cstr_null; } STC_INLINE cstr cstr_from_n(const char* str, const intptr_t len) { cstr s; @@ -132,7 +132,7 @@ STC_INLINE cstr* cstr_take(cstr* self, const cstr s) { STC_INLINE cstr cstr_move(cstr* self) { cstr tmp = *self; - *self = cstr_NULL; + *self = cstr_null; return tmp; } @@ -440,8 +440,8 @@ cstr cstr_tocase(csview sv, int k) { #endif // i_import /* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined i_import || (defined i_implement && !defined _i_nested) #ifndef CSTR_C_INCLUDED -#if defined i_import || (defined i_implement && !defined _i_no_undef) #define CSTR_C_INCLUDED uint64_t cstr_hash(const cstr *self) { @@ -573,7 +573,7 @@ bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { - cstr out = cstr_NULL; + cstr out = cstr_null; intptr_t from = 0; char* res; if (!count) count = INT32_MAX; if (search.size) @@ -625,7 +625,7 @@ intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list args) { #endif cstr cstr_from_fmt(const char* fmt, ...) { - cstr s = cstr_NULL; + cstr s = cstr_null; va_list args; va_start(args, fmt); cstr_vfmt(&s, 0, fmt, args); @@ -649,17 +649,17 @@ intptr_t cstr_printf(cstr* self, const char* fmt, ...) { va_end(args); return n; } -#endif // i_implement #endif // CSTR_C_INCLUDED +#endif // i_implement #if defined __GNUC__ && !defined __clang__ # pragma GCC diagnostic pop #endif -#ifndef _i_no_undef +#ifndef _i_nested #undef i_opt #undef i_header #undef i_static #undef i_implement #undef i_import #endif -#undef _i_no_undef +#undef _i_nested diff --git a/include/stc/csview.h b/include/stc/csview.h index a1893063..c16f58bc 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,14 +20,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#define _i_no_undef +#define _i_nested #include "utf8.h" #ifndef CSVIEW_H_INCLUDED #define CSVIEW_H_INCLUDED -#define csview_NULL c_sv_1("") -#define csview_init() csview_NULL +#define csview_null c_sv_1("") +#define csview_init() csview_null #define csview_drop(p) c_default_drop(p) #define csview_clone(sv) c_default_clone(sv) #define csview_lit(literal) c_sv_1(literal) @@ -42,7 +42,7 @@ extern csview csview_token(csview sv, const char* sep, intptr_t* start); STC_INLINE csview csview_from(const char* str) { return c_LITERAL(csview){str, c_strlen(str)}; } -STC_INLINE void csview_clear(csview* self) { *self = csview_NULL; } +STC_INLINE void csview_clear(csview* self) { *self = csview_null; } STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } @@ -150,8 +150,8 @@ STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u #endif /* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined i_import || (defined i_implement && !defined _i_nested) #ifndef CSVIEW_C_INCLUDED -#if defined i_import || (defined i_implement && !defined _i_no_undef) #define CSVIEW_C_INCLUDED csview_iter csview_advance(csview_iter it, intptr_t pos) { @@ -201,13 +201,13 @@ csview csview_token(csview sv, const char* sep, intptr_t* start) { *start += tok.size + sep_size; return tok; } -#endif -#endif -#ifndef _i_no_undef +#endif // CSVIEW_C_INCLUDED +#endif // i_implement +#ifndef _i_nested #undef i_static #undef i_header #undef i_implement #undef i_import #undef i_opt #endif -#undef _i_no_undef +#undef _i_nested diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 747c654d..874f4f47 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -58,9 +58,10 @@ int main() { cvec_str_drop(&svec); } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CVEC_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include #include diff --git a/include/stc/priv/linkage.h b/include/stc/priv/linkage.h new file mode 100644 index 00000000..7f63f5f1 --- /dev/null +++ b/include/stc/priv/linkage.h @@ -0,0 +1,40 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#undef STC_API +#undef STC_DEF + +#ifdef i_extern // [deprecated] +# define i_import +#endif +#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \ + defined(i_implement) || defined(STC_IMPLEMENT)) + #define STC_API extern + #define STC_DEF +#else + #define i_static + #define STC_API static inline + #define STC_DEF static inline +#endif +#if defined(STC_IMPLEMENT) || defined(i_import) + #define i_implement +#endif diff --git a/include/stc/utf8.h b/include/stc/utf8.h index d6c759eb..190cc7f3 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -1,9 +1,31 @@ - -#include "ccommon.h" +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "priv/linkage.h" #ifndef UTF8_H_INCLUDED #define UTF8_H_INCLUDED +#include "ccommon.h" #include #include "forward.h" @@ -53,9 +75,9 @@ STC_INLINE bool utf8_isspace(uint32_t c) { /* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */ typedef struct { uint32_t state, codep; } utf8_decode_t; +extern const uint8_t utf8_dtab[]; /* utf8code.c */ STC_INLINE uint32_t utf8_decode(utf8_decode_t* d, const uint32_t byte) { - extern const uint8_t utf8_dtab[]; /* utf8code.c */ const uint32_t type = utf8_dtab[byte]; d->codep = d->state ? (byte & 0x3fu) | (d->codep << 6) : (0xffU >> type) & byte; @@ -116,14 +138,14 @@ STC_INLINE intptr_t utf8_pos(const char* s, intptr_t index) { return (intptr_t)(utf8_at(s, index) - s); } #endif // UTF8_H_INCLUDED -#if defined i_import || (defined i_implement && !defined _i_no_undef) +#if defined i_import || (defined i_implement && !defined _i_nested) # include "../../src/utf8code.c" #endif -#ifndef _i_no_undef +#ifndef _i_nested #undef i_static #undef i_header #undef i_implement #undef i_import #undef i_opt #endif -#undef _i_no_undef +#undef _i_nested diff --git a/misc/examples/astar.c b/misc/examples/astar.c index db6bbd70..1b3876aa 100644 --- a/misc/examples/astar.c +++ b/misc/examples/astar.c @@ -21,7 +21,7 @@ point; point point_init(int x, int y, int width) { - return (point) { x, y, 0, width }; + return c_LITERAL(point){ x, y, 0, width }; } int diff --git a/misc/examples/box.c b/misc/examples/box.c index e352aa2b..a9131afa 100644 --- a/misc/examples/box.c +++ b/misc/examples/box.c @@ -5,7 +5,7 @@ typedef struct { cstr name, last; } Person; Person Person_make(const char* name, const char* last) { - return (Person){.name = cstr_from(name), .last = cstr_from(last)}; + return c_LITERAL(Person){.name = cstr_from(name), .last = cstr_from(last)}; } uint64_t Person_hash(const Person* a) { diff --git a/misc/examples/box2.c b/misc/examples/box2.c index 33212ef4..963a3815 100644 --- a/misc/examples/box2.c +++ b/misc/examples/box2.c @@ -29,12 +29,12 @@ typedef struct { #include // BoxBoxPoint Point origin(void) { - return (Point){ .x=1.0, .y=2.0 }; + return c_LITERAL(Point){ .x=1.0, .y=2.0 }; } cbox_Point boxed_origin(void) { // Allocate this point on the heap, and return a pointer to it - return cbox_Point_make((Point){ .x=1.0, .y=2.0 }); + return cbox_Point_make(c_LITERAL(Point){ .x=1.0, .y=2.0 }); } @@ -47,7 +47,7 @@ int main(void) { }; // Heap allocated rectangle - cbox_Rectangle boxed_rectangle = cbox_Rectangle_make((Rectangle){ + cbox_Rectangle boxed_rectangle = cbox_Rectangle_make(c_LITERAL(Rectangle){ .top_left = origin(), .bottom_right = { .x=3.0, .y=-4.0 } }); diff --git a/misc/examples/csmap_find.c b/misc/examples/csmap_find.c index a8928410..c123e398 100644 --- a/misc/examples/csmap_find.c +++ b/misc/examples/csmap_find.c @@ -50,12 +50,12 @@ int main() print_collection_csmap_istr(&m1); typedef cvec_istr_value pair; - cvec_istr_push(&v, (pair){43, "Tc"}); - cvec_istr_push(&v, (pair){41, "Nb"}); - cvec_istr_push(&v, (pair){46, "Pd"}); - cvec_istr_push(&v, (pair){42, "Mo"}); - cvec_istr_push(&v, (pair){44, "Ru"}); - cvec_istr_push(&v, (pair){44, "Ru"}); // attempt a duplicate + cvec_istr_push(&v, c_LITERAL(pair){43, "Tc"}); + cvec_istr_push(&v, c_LITERAL(pair){41, "Nb"}); + cvec_istr_push(&v, c_LITERAL(pair){46, "Pd"}); + cvec_istr_push(&v, c_LITERAL(pair){42, "Mo"}); + cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); + cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); // attempt a duplicate puts("Inserting the following vector data into m1:"); print_collection_cvec_istr(&v); diff --git a/misc/examples/csmap_insert.c b/misc/examples/csmap_insert.c index f96cc08f..18a88ec3 100644 --- a/misc/examples/csmap_insert.c +++ b/misc/examples/csmap_insert.c @@ -34,7 +34,7 @@ int main() // insert single values csmap_ii m1 = {0}; csmap_ii_insert(&m1, 1, 10); - csmap_ii_push(&m1, (csmap_ii_value){2, 20}); + csmap_ii_push(&m1, c_LITERAL(csmap_ii_value){2, 20}); puts("The original key and mapped values of m1 are:"); print_ii(m1); @@ -61,11 +61,11 @@ int main() csmap_ii m2 = {0}; cvec_ii v = {0}; typedef cvec_ii_value ipair; - cvec_ii_push(&v, (ipair){43, 294}); - cvec_ii_push(&v, (ipair){41, 262}); - cvec_ii_push(&v, (ipair){45, 330}); - cvec_ii_push(&v, (ipair){42, 277}); - cvec_ii_push(&v, (ipair){44, 311}); + cvec_ii_push(&v, c_LITERAL(ipair){43, 294}); + cvec_ii_push(&v, c_LITERAL(ipair){41, 262}); + cvec_ii_push(&v, c_LITERAL(ipair){45, 330}); + cvec_ii_push(&v, c_LITERAL(ipair){42, 277}); + cvec_ii_push(&v, c_LITERAL(ipair){44, 311}); puts("Inserting the following vector data into m2:"); c_foreach (e, cvec_ii, v) diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c index f9c05e71..e13eb055 100644 --- a/misc/examples/dining_philosophers.c +++ b/misc/examples/dining_philosophers.c @@ -29,9 +29,10 @@ struct Dining { // Philosopher coroutine void philosopher(struct Philosopher* p) { + double duration; cco_routine(p) { while (1) { - double duration = 1.0 + crandf()*2.0; + duration = 1.0 + crandf()*2.0; printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10); cco_timer_await(&p->tm, duration); @@ -46,7 +47,7 @@ void philosopher(struct Philosopher* p) cco_sem_release(p->left_fork); cco_sem_release(p->right_fork); } - + cco_final: printf("Philosopher %d finished\n", p->id); } diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index 94a84065..d39693b5 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -55,7 +55,8 @@ fn main() { void demo2(void) { IVec vector = {0}; - c_forfilter (x, crange, crange_obj(INT64_MAX), + crange r = crange_init(INT64_MAX); + c_forfilter (x, crange, r, c_flt_skipwhile(x, *x.ref != 11) && (*x.ref % 2) != 0 && c_flt_take(x, 5) @@ -124,7 +125,7 @@ void demo5(void) { #define flt_even(i) ((*i.ref & 1) == 0) #define flt_mid_decade(i) ((*i.ref % 10) != 0) - crange R = crange_make(1963, INT32_MAX); + crange R = crange_init(1963, INT32_MAX); c_forfilter (i, crange, R, c_flt_skip(i,15) && diff --git a/misc/examples/make.sh b/misc/examples/make.sh index 61d9f879..cf224950 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -7,13 +7,13 @@ if [ "$(uname)" = 'Linux' ]; then fi cc=gcc; cflags="-std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-implicit-fallthrough -Wno-missing-field-initializers" -#cc=gcc; cflags="-DSTC_STATIC -std=c99 -g -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" -#cc=tcc; cflags="-DSTC_STATIC -std=c99 -Wall" -#cc=clang; cflags="-DSTC_STATIC -std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -Wno-missing-field-initializers" -#cc=gcc; cflags="-DSTC_STATIC -x c++ -std=c++20 -O2 -s -Wall" -#cc=cl; cflags="-DSTC_STATIC -nologo -O2 -MD -W3 -wd4003" -#cc=cl; cflags="-DSTC_STATIC -nologo -TP -wd4003" -#cc=cl; cflags="-DSTC_STATIC -nologo -std:c11 -wd4003" +#cc=gcc; cflags="-std=c99 -g -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" +#cc=tcc; cflags="-std=c99 -Wall" +#cc=clang; cflags="-std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -Wno-missing-field-initializers" +#cc=gcc; cflags="-x c++ -std=c++20 -O2 -s -Wall" +#cc=cl; cflags="-nologo -O2 -MD -W3 -wd4003" +#cc=cl; cflags="-nologo -TP -std:c++20 -wd4003" +#cc=cl; cflags="-nologo -std:c11 -wd4003" if [ "$cc" = "cl" ]; then oflag='/Fe:' diff --git a/misc/examples/music_arc.c b/misc/examples/music_arc.c index 9c7173ef..18ea30c0 100644 --- a/misc/examples/music_arc.c +++ b/misc/examples/music_arc.c @@ -13,7 +13,7 @@ int Song_cmp(const Song* x, const Song* y) { return cstr_cmp(&x->title, &y->title); } Song Song_make(const char* artist, const char* title) - { return (Song){cstr_from(artist), cstr_from(title)}; } + { return c_LITERAL(Song){cstr_from(artist), cstr_from(title)}; } void Song_drop(Song* s) { printf("drop: %s\n", cstr_str(&s->title)); diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index 993f1aac..382943bb 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -45,7 +45,7 @@ int main() { MyStruct my = {0}; clist_i32_push_back(&my.intlst, 123); - clist_pnt_push_back(&my.pntlst, (Point){123, 456}); + clist_pnt_push_back(&my.pntlst, c_LITERAL(Point){123, 456}); MyStruct_drop(&my); clist_pnt plst = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); diff --git a/misc/examples/new_sptr.c b/misc/examples/new_sptr.c index aa8dd175..36a61f9c 100644 --- a/misc/examples/new_sptr.c +++ b/misc/examples/new_sptr.c @@ -30,7 +30,8 @@ uint64_t Person_hash(const Person* p); Person Person_make(const char* name, const char* last) { - return (Person){.name = cstr_from(name), .last = cstr_from(last)}; + Person p = {.name = cstr_from(name), .last = cstr_from(last)}; + return p; } int Person_cmp(const Person* a, const Person* b) { diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c index d4b66883..e10910d9 100644 --- a/misc/examples/new_vec.c +++ b/misc/examples/new_vec.c @@ -26,10 +26,10 @@ int main() { MyStruct my = {0}; - cvec_pnt_push(&my.pntvec, (Point){42, 14}); - cvec_pnt_push(&my.pntvec, (Point){32, 94}); - cvec_pnt_push(&my.pntvec, (Point){62, 81}); - cvec_pnt_push(&my.pntvec, (Point){32, 91}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){42, 14}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 94}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){62, 81}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 91}); cvec_pnt_sort(&my.pntvec); diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c index b4b926da..3614c02d 100644 --- a/misc/examples/person_arc.c +++ b/misc/examples/person_arc.c @@ -6,7 +6,8 @@ typedef struct { cstr name, last; } Person; Person Person_make(const char* name, const char* last) { - return (Person){.name = cstr_from(name), .last = cstr_from(last)}; + Person p = {.name = cstr_from(name), .last = cstr_from(last)}; + return p; } int Person_cmp(const Person* a, const Person* b) { diff --git a/misc/examples/prime.c b/misc/examples/prime.c index cb0f8926..34fa144c 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -41,7 +41,9 @@ int main(void) puts("\n"); puts("Show the last 50 primes using a temporary crange generator:"); - c_forfilter (i, crange, crange_obj(n - 1, 0, -2), + crange range = crange_init(n - 1, 0, -2); + + c_forfilter (i, crange, range, cbits_test(&primes, *i.ref/2) && c_flt_take(i, 50) ){ diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c index b5099ed5..7564bd88 100644 --- a/misc/examples/printspan.c +++ b/misc/examples/printspan.c @@ -22,22 +22,22 @@ void printMe(intspan container) { int main() { - intspan sp1 = cspan_make(intspan, {1, 2}); + intspan sp1 = cspan_init(intspan, {1, 2}); printMe( sp1 ); printMe( c_init(intspan, {1, 2, 3}) ); int arr[] = {1, 2, 3, 4, 5, 6}; intspan sp2 = cspan_from_array(arr); - printMe( (intspan)cspan_subspan(&sp2, 1, 4) ); + printMe( c_LITERAL(intspan)cspan_subspan(&sp2, 1, 4) ); cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5}); - printMe( (intspan)cspan_from(&vec) ); + printMe( c_LITERAL(intspan)cspan_from(&vec) ); printMe( sp2 ); cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7}); - printMe( (intspan)cspan_from(&stk) ); + printMe( c_LITERAL(intspan)cspan_from(&stk) ); csset_str set = c_init(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); printf("%d:", (int)csset_str_size(&set)); diff --git a/misc/examples/read.c b/misc/examples/read.c index 545d706a..3c1cadf6 100644 --- a/misc/examples/read.c +++ b/misc/examples/read.c @@ -9,7 +9,7 @@ cvec_str read_file(const char* name) { cvec_str vec = cvec_str_init(); c_with (FILE* f = fopen(name, "r"), fclose(f)) - c_with (cstr line = cstr_NULL, cstr_drop(&line)) + c_with (cstr line = cstr_null, cstr_drop(&line)) while (cstr_getline(&line, f)) cvec_str_push(&vec, cstr_clone(line)); return vec; diff --git a/misc/examples/shape.c b/misc/examples/shape.c index 22e993db..1d9fe5c5 100644 --- a/misc/examples/shape.c +++ b/misc/examples/shape.c @@ -137,7 +137,7 @@ int main(void) { Shapes shapes = {0}; - Triangle* tri1 = c_new(Triangle, Triangle_from((Point){5, 7}, (Point){12, 7}, (Point){12, 20})); + Triangle* tri1 = c_new(Triangle, Triangle_from(c_LITERAL(Point){5, 7}, c_LITERAL(Point){12, 7}, c_LITERAL(Point){12, 20})); Polygon* pol1 = c_new(Polygon, Polygon_init()); Polygon* pol2 = c_new(Polygon, Polygon_init()); diff --git a/misc/examples/vikings.c b/misc/examples/vikings.c index cf087119..d9024052 100644 --- a/misc/examples/vikings.c +++ b/misc/examples/vikings.c @@ -44,12 +44,12 @@ static inline RViking Viking_toraw(const Viking* vp) { int main() { Vikings vikings = {0}; - Vikings_emplace(&vikings, (RViking){"Einar", "Norway"}, 20); - Vikings_emplace(&vikings, (RViking){"Olaf", "Denmark"}, 24); - Vikings_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12); - Vikings_emplace(&vikings, (RViking){"Björn", "Sweden"}, 10); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Einar", "Norway"}, 20); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Olaf", "Denmark"}, 24); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Harald", "Iceland"}, 12); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Björn", "Sweden"}, 10); - Vikings_value* v = Vikings_get_mut(&vikings, (RViking){"Einar", "Norway"}); + Vikings_value* v = Vikings_get_mut(&vikings, c_LITERAL(RViking){"Einar", "Norway"}); v->second += 3; // add 3 hp points to Einar c_forpair (vk, hp, Vikings, vikings) { diff --git a/src/cregex.c b/src/cregex.c index 1af719b4..9b7179b6 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -28,20 +28,20 @@ THE SOFTWARE. #include #ifdef i_import -# define _i_extern +# define _i_import #endif #ifndef CREGEX_H_INCLUDED # include "../include/stc/cregex.h" #endif -#ifdef _i_extern +#ifdef _i_import # include "utf8code.c" #endif -#ifdef _i_extern +#ifdef _i_import # define i_implement #else # undef i_implement #endif -#undef _i_extern +#undef _i_import #include "../include/stc/cstr.h" typedef uint32_t _Rune; /* Utf8 code point */ @@ -944,14 +944,14 @@ _runematch(_Rune s, _Rune r) case ASC_LO: inv = 1; case ASC_lo: return inv ^ (islower((int)r) != 0); case ASC_UP: inv = 1; case ASC_up: return inv ^ (isupper((int)r) != 0); case ASC_XD: inv = 1; case ASC_xd: return inv ^ (isxdigit((int)r) != 0); - case UTF_AN: inv = 1; case UTF_an: return inv ^ utf8_isalnum(r); - case UTF_BL: inv = 1; case UTF_bl: return inv ^ utf8_isblank(r); - case UTF_SP: inv = 1; case UTF_sp: return inv ^ utf8_isspace(r); - case UTF_LL: inv = 1; case UTF_ll: return inv ^ utf8_islower(r); - case UTF_LU: inv = 1; case UTF_lu: return inv ^ utf8_isupper(r); - case UTF_LC: inv = 1; case UTF_lc: return inv ^ utf8_iscased(r); - case UTF_AL: inv = 1; case UTF_al: return inv ^ utf8_isalpha(r); - case UTF_WR: inv = 1; case UTF_wr: return inv ^ utf8_isword(r); + case UTF_AN: inv = 1; case UTF_an: return inv ^ (int)utf8_isalnum(r); + case UTF_BL: inv = 1; case UTF_bl: return inv ^ (int)utf8_isblank(r); + case UTF_SP: inv = 1; case UTF_sp: return inv ^ (int)utf8_isspace(r); + case UTF_LL: inv = 1; case UTF_ll: return inv ^ (int)utf8_islower(r); + case UTF_LU: inv = 1; case UTF_lu: return inv ^ (int)utf8_isupper(r); + case UTF_LC: inv = 1; case UTF_lc: return inv ^ (int)utf8_iscased(r); + case UTF_AL: inv = 1; case UTF_al: return inv ^ (int)utf8_isalpha(r); + case UTF_WR: inv = 1; case UTF_wr: return inv ^ (int)utf8_isword(r); case UTF_cc: case UTF_CC: case UTF_lt: case UTF_LT: case UTF_nd: case UTF_ND: @@ -972,7 +972,7 @@ _runematch(_Rune s, _Rune r) case UTF_latin: case UTF_LATIN: n = (int)s - UTF_GRP; inv = n & 1; - return inv ^ utf8_isgroup(n / 2, r); + return inv ^ (int)utf8_isgroup(n / 2, r); } return s == r; } @@ -1220,7 +1220,7 @@ _build_subst(const char* replace, int nmatch, const csview match[], cstr_buf buf = cstr_buffer(subst); intptr_t len = 0, cap = buf.cap; char* dst = buf.data; - cstr mstr = cstr_NULL; + cstr mstr = cstr_null; while (*replace != '\0') { if (*replace == '$') { @@ -1293,8 +1293,8 @@ cregex_find_pattern_4(const char* pattern, const char* input, cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, bool (*mfun)(int, csview, cstr*), int rflags) { - cstr out = cstr_NULL; - cstr subst = cstr_NULL; + cstr out = cstr_null; + cstr subst = cstr_null; csview match[CREG_MAX_CAPTURES]; int nmatch = cregex_captures(re) + 1; if (!count) count = INT32_MAX; diff --git a/src/utf8code.c b/src/utf8code.c index 6a133050..4abf10ea 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -461,28 +461,31 @@ static const URange16 Latin_range16[] = { #define UNI_ENTRY(Code) \ { Code##_range16, sizeof(Code##_range16)/sizeof(URange16) } -#ifndef __cplusplus +#ifdef __cplusplus +#define _e_arg(k, v) v +#else +#define _e_arg(k, v) [k] = v static #endif const UGroup _utf8_unicode_groups[U8G_SIZE] = { - [U8G_Cc] = UNI_ENTRY(Cc), - [U8G_Lt] = UNI_ENTRY(Lt), - [U8G_Nd] = UNI_ENTRY(Nd), - [U8G_Nl] = UNI_ENTRY(Nl), - [U8G_Pc] = UNI_ENTRY(Pc), - [U8G_Pd] = UNI_ENTRY(Pd), - [U8G_Pf] = UNI_ENTRY(Pf), - [U8G_Pi] = UNI_ENTRY(Pi), - [U8G_Sc] = UNI_ENTRY(Sc), - [U8G_Zl] = UNI_ENTRY(Zl), - [U8G_Zp] = UNI_ENTRY(Zp), - [U8G_Zs] = UNI_ENTRY(Zs), - [U8G_Arabic] = UNI_ENTRY(Arabic), - [U8G_Cyrillic] = UNI_ENTRY(Cyrillic), - [U8G_Devanagari] = UNI_ENTRY(Devanagari), - [U8G_Greek] = UNI_ENTRY(Greek), - [U8G_Han] = UNI_ENTRY(Han), - [U8G_Latin] = UNI_ENTRY(Latin), + _e_arg(U8G_Cc, UNI_ENTRY(Cc)), + _e_arg(U8G_Lt, UNI_ENTRY(Lt)), + _e_arg(U8G_Nd, UNI_ENTRY(Nd)), + _e_arg(U8G_Nl, UNI_ENTRY(Nl)), + _e_arg(U8G_Pc, UNI_ENTRY(Pc)), + _e_arg(U8G_Pd, UNI_ENTRY(Pd)), + _e_arg(U8G_Pf, UNI_ENTRY(Pf)), + _e_arg(U8G_Pi, UNI_ENTRY(Pi)), + _e_arg(U8G_Sc, UNI_ENTRY(Sc)), + _e_arg(U8G_Zl, UNI_ENTRY(Zl)), + _e_arg(U8G_Zp, UNI_ENTRY(Zp)), + _e_arg(U8G_Zs, UNI_ENTRY(Zs)), + _e_arg(U8G_Arabic, UNI_ENTRY(Arabic)), + _e_arg(U8G_Cyrillic, UNI_ENTRY(Cyrillic)), + _e_arg(U8G_Devanagari, UNI_ENTRY(Devanagari)), + _e_arg(U8G_Greek, UNI_ENTRY(Greek)), + _e_arg(U8G_Han, UNI_ENTRY(Han)), + _e_arg(U8G_Latin, UNI_ENTRY(Latin)), }; #endif -- cgit v1.2.3 From 06f3ae1d904d776aea8a78113c16fc30309817ed Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 13 Jun 2023 18:21:04 +0200 Subject: Added cco_closue(Ret, Closure) to define coroutine closure. Added back cco_await_on(child) calls. --- docs/ccommon_api.md | 6 +++++- include/stc/algo/coroutine.h | 16 +++++++++++++++- include/stc/cstr.h | 7 ++----- include/stc/csview.h | 7 ++----- include/stc/utf8.h | 6 +++--- misc/examples/cointerleave.c | 2 +- misc/examples/coread.c | 2 +- 7 files changed, 29 insertions(+), 17 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 1f0847da..89a98cbb 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -380,6 +380,9 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_await(promise, ret)` | Await/suspend with ret value | | | `cco_return` | Replaces return. Jump to cco_final: if exist| | | `cco_return_v(val)` | Yield final value, enter final-state | +| | `cco_closure(Ret, Closure, ...)` | Define coroutine closure struct. | +| `void` | `cco_await_on(closure) { }` | Await on closure to finish | +| `void` | `cco_await_on(co, func) { }` | Await on func(co) to finish | | | Semaphores: | | | | `cco_sem` | Semaphore type | | | `cco_sem_await(sem)` | Await for the semaphore count > 0 | @@ -398,7 +401,8 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_run(co, corocall) { }` | Run blocking until coro is done | +| `void` | `cco_block_on(closure) { }` | Run blocking until closure is finished | +| `void` | `cco_block_on(co, func) { }` | Run blocking until func is finished | | | Time functions: | | | `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | | | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 5cd6d68f..61581f64 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -84,7 +84,21 @@ enum { case __LINE__: if (!(promise)) {return ret; goto _resume;} \ } while (0) -#define cco_run(co, call) while (call, !cco_done(co)) +#define cco_closure(Ret, Closure, ...) \ + struct Closure { \ + Ret (*coroutine)(struct Closure*); \ + __VA_ARGS__ \ + int cco_state; \ + } + +#define cco_resume(closure) (closure)->coroutine(closure) +#define cco_await_on(...) c_MACRO_OVERLOAD(cco_await_on, __VA_ARGS__) +#define cco_await_on_1(closure) cco_await_on_2(closure, cco_resume(closure)) +#define cco_await_on_2(co, func) cco_await_1((func(co), !cco_done(co))) + +#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) +#define cco_block_on_1(closure) while (cco_resume(closure), !cco_done(closure)) +#define cco_block_on_2(co, func) while (func(co), !cco_done(co)) #define cco_final \ *_state = cco_state_final; case cco_state_final diff --git a/include/stc/cstr.h b/include/stc/cstr.h index bdfee39b..b9b066ad 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -24,7 +24,7 @@ /* A string type with short string optimization in C99 with good small-string * optimization (22 characters with 24 bytes string). */ -#define _i_nested +#define _i_inc_utf8 #include "utf8.h" #ifndef CSTR_H_INCLUDED @@ -440,7 +440,7 @@ cstr cstr_tocase(csview sv, int k) { #endif // i_import /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_import || (defined i_implement && !defined _i_nested) +#if defined i_import || defined i_implement #ifndef CSTR_C_INCLUDED #define CSTR_C_INCLUDED @@ -655,11 +655,8 @@ intptr_t cstr_printf(cstr* self, const char* fmt, ...) { #if defined __GNUC__ && !defined __clang__ # pragma GCC diagnostic pop #endif -#ifndef _i_nested #undef i_opt #undef i_header #undef i_static #undef i_implement #undef i_import -#endif -#undef _i_nested diff --git a/include/stc/csview.h b/include/stc/csview.h index c16f58bc..07ab4059 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#define _i_nested +#define _i_inc_utf8 #include "utf8.h" #ifndef CSVIEW_H_INCLUDED @@ -150,7 +150,7 @@ STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u #endif /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_import || (defined i_implement && !defined _i_nested) +#if defined i_import || defined i_implement #ifndef CSVIEW_C_INCLUDED #define CSVIEW_C_INCLUDED @@ -203,11 +203,8 @@ csview csview_token(csview sv, const char* sep, intptr_t* start) { } #endif // CSVIEW_C_INCLUDED #endif // i_implement -#ifndef _i_nested #undef i_static #undef i_header #undef i_implement #undef i_import #undef i_opt -#endif -#undef _i_nested diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 190cc7f3..6d12856f 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -138,14 +138,14 @@ STC_INLINE intptr_t utf8_pos(const char* s, intptr_t index) { return (intptr_t)(utf8_at(s, index) - s); } #endif // UTF8_H_INCLUDED -#if defined i_import || (defined i_implement && !defined _i_nested) +#if defined i_import || (defined i_implement && !defined _i_inc_utf8) # include "../../src/utf8code.c" #endif -#ifndef _i_nested +#ifndef _i_inc_utf8 #undef i_static #undef i_header #undef i_implement #undef i_import #undef i_opt #endif -#undef _i_nested +#undef _i_inc_utf8 diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 51b9f39a..1ba7b861 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -48,7 +48,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - cco_run(&g, interleaved(&g)) { + cco_block_on(&g, interleaved) { printf("%d ", g.value); } puts(""); diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 63162ba3..622228c0 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -32,7 +32,7 @@ int main(void) { struct file_read g = {__FILE__}; int n = 0; - cco_run(&g, file_read(&g)) + cco_block_on(&g, file_read) { printf("%3d %s\n", ++n, cstr_str(&g.line)); //if (n == 10) cco_stop(&g); -- cgit v1.2.3 From c51bdc8d8aeac63c0af955f81593ef0be326a7e0 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 13 Jun 2023 18:24:52 +0200 Subject: Missed an update --- misc/examples/coroutines.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 040b8472..1e900fa1 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -102,7 +102,7 @@ int main(void) { struct combined c = {.prm={.count=8}, .fib={14}}; - cco_run(&c, combined(&c)) { + cco_block_on(&c, combined) { printf("Prime(%d)=%lld, Fib(%d)=%lld\n", c.prm.idx, c.prm.result, c.fib.idx, c.fib.result); -- cgit v1.2.3 From 3f919a3b38a88e1c96399cd6096dec16060802a1 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 14 Jun 2023 13:24:29 +0200 Subject: Fixed a bug in cco_await_on(), and added _pull() function to random access containers (moves element out of container, ie no drop). --- include/stc/algo/coroutine.h | 4 ++-- include/stc/cdeq.h | 7 +++++++ include/stc/cqueue.h | 9 ++++++++- include/stc/cstack.h | 5 ++++- include/stc/cvec.h | 4 +++- misc/examples/scheduler.c | 9 +++------ 6 files changed, 27 insertions(+), 11 deletions(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 61581f64..e0952e1f 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -93,8 +93,8 @@ enum { #define cco_resume(closure) (closure)->coroutine(closure) #define cco_await_on(...) c_MACRO_OVERLOAD(cco_await_on, __VA_ARGS__) -#define cco_await_on_1(closure) cco_await_on_2(closure, cco_resume(closure)) -#define cco_await_on_2(co, func) cco_await_1((func(co), !cco_done(co))) +#define cco_await_on_1(closure) cco_await_2((cco_resume(closure), cco_done(closure)), ) +#define cco_await_on_2(co, func) cco_await_2((func(co), cco_done(co)), ) #define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) #define cco_block_on_1(closure) while (cco_resume(closure), !cco_done(closure)) diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 8bb62602..a406c2b0 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -22,6 +22,7 @@ */ #define _i_prefix cdeq_ #define _pop _pop_front +#define _pull _pull_front #ifdef i_more #include "cqueue.h" #define i_more @@ -55,6 +56,12 @@ _cx_memb(_pop_back)(_cx_self* self) { i_keydrop((self->data + self->end)); } +STC_INLINE _cx_value _cx_memb(_pull_back)(_cx_self* self) { // move back out of deq + assert(!_cx_memb(_empty)(self)); + self->end = (self->end - 1) & self->capmask; + return self->data[self->end]; +} + STC_INLINE _cx_iter _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, const _cx_value val) { intptr_t idx = _cdeq_toidx(self, it.pos); diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 3adc1bcb..aa3d7384 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -93,6 +93,13 @@ STC_INLINE void _cx_memb(_pop)(_cx_self* self) { // pop_front self->start = (self->start + 1) & self->capmask; } +STC_INLINE _cx_value _cx_memb(_pull)(_cx_self* self) { // move front out of queue + assert(!_cx_memb(_empty)(self)); + intptr_t s = self->start; + self->start = (s + 1) & self->capmask; + return self->data[s]; +} + STC_INLINE void _cx_memb(_copy)(_cx_self* self, const _cx_self* other) { if (self->data == other->data) return; _cx_memb(_drop)(self); @@ -162,7 +169,7 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t n) { if (!data) return false; intptr_t head = oldcap - self->start; - if (self->start < self->end || self->start == 0) + if (self->start <= self->end) ; else if (head < self->end) { self->start = newcap - head; diff --git a/include/stc/cstack.h b/include/stc/cstack.h index fb4eae4b..5f0ffe2b 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -129,7 +129,10 @@ STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value val) { } STC_INLINE void _cx_memb(_pop)(_cx_self* self) - { assert(!_cx_memb(_empty)(self)); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } + { assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } + +STC_INLINE _cx_value _cx_memb(_pull)(_cx_self* self) + { assert(self->_len); return self->data[--self->_len]; } STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 874f4f47..71787733 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -133,7 +133,9 @@ STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->da STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) { return self->data + self->_len - 1; } STC_INLINE void _cx_memb(_pop)(_cx_self* self) - { assert(!_cx_memb(_empty)(self)); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } + { assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } +STC_INLINE _cx_value _cx_memb(_pull)(_cx_self* self) + { assert(self->_len); return self->data[--self->_len]; } STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) { return _cx_memb(_push)(self, value); } STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) { _cx_memb(_pop)(self); } diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index aecb1a26..54fefc47 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -2,12 +2,9 @@ #include #include -struct Scheduler; -struct Task { - bool (*resume)(struct Task*); +cco_closure(bool, Task, struct Scheduler* sched; - int cco_state; -}; +); #define i_type Scheduler #define i_val struct Task @@ -20,7 +17,7 @@ static bool schedule(Scheduler* sched) Scheduler_pop(sched); if (!cco_done(&task)) - task.resume(&task); + cco_resume(&task); return !Scheduler_empty(sched); } -- cgit v1.2.3 From b617eded8cee98dd3ff9ac896328b172d37fcf91 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 20 Jun 2023 15:17:07 +0200 Subject: Minor internals. --- include/stc/cqueue.h | 10 +++++----- include/stc/priv/template.h | 10 ++++------ include/stc/priv/template2.h | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index aa3d7384..2f709172 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -165,21 +165,21 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t n) { if (n <= self->capmask) return true; intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1); - _cx_value* data = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data); - if (!data) + _cx_value* d = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data); + if (!d) return false; intptr_t head = oldcap - self->start; if (self->start <= self->end) ; else if (head < self->end) { self->start = newcap - head; - c_memmove(data + self->start, data + oldcap - head, head*c_sizeof *data); + c_memmove(d + self->start, d + oldcap - head, head*c_sizeof *d); } else { - c_memmove(data + oldcap, data, self->end*c_sizeof *data); + c_memmove(d + oldcap, d, self->end*c_sizeof *d); self->end += oldcap; } self->capmask = newcap - 1; - self->data = data; + self->data = d; return true; } diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index f70281c7..b3f3eabe 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -112,7 +112,6 @@ #if defined i_key_str #define i_keyclass cstr #define i_rawclass crawstr - #define i_keyfrom cstr_from #ifndef i_tag #define i_tag str #endif @@ -188,7 +187,7 @@ #ifndef i_keyfrom #define i_keyfrom c_default_clone #else - #define _i_has_from + #define i_has_emplace #endif #ifndef i_keyto #define i_keyto c_default_toraw @@ -225,8 +224,7 @@ #ifdef i_val_str #define i_valclass cstr - #define i_valraw crawstr - #define i_valfrom cstr_from + #define i_valraw const char* #elif defined i_val_ssv #define i_valclass cstr #define i_valraw csview @@ -266,7 +264,7 @@ #ifndef i_valfrom #define i_valfrom c_default_clone #else - #define _i_has_from + #define i_has_emplace #endif #ifndef i_valto #define i_valto c_default_toraw @@ -286,7 +284,7 @@ #ifndef i_valraw #define i_valraw i_keyraw #endif -#ifndef _i_has_from +#ifndef i_has_emplace #define i_no_emplace #endif #endif diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 75402150..4604e610 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -72,10 +72,10 @@ #undef i_no_clone #undef i_no_emplace #undef i_is_forward +#undef i_has_emplace #undef _i_prefix #undef _i_expandby -#undef _i_has_from #undef _i_has_eq #undef _i_has_cmp #undef _i_template -- cgit v1.2.3 From de4f8fa86f141dfeab15f5576029910474f56fa1 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 20 Jun 2023 15:28:02 +0200 Subject: Internal only: Renamed _cx_memb() macro to _cx_MEMB() Renamed _cx_self macro to _cx_Self --- include/stc/algo/sort.h | 14 +-- include/stc/carc.h | 76 ++++++------- include/stc/cbox.h | 74 ++++++------- include/stc/cdeq.h | 100 ++++++++--------- include/stc/clist.h | 212 +++++++++++++++++------------------ include/stc/cmap.h | 194 ++++++++++++++++---------------- include/stc/cpque.h | 84 +++++++------- include/stc/cqueue.h | 130 +++++++++++----------- include/stc/csmap.h | 264 ++++++++++++++++++++++---------------------- include/stc/cstack.h | 102 ++++++++--------- include/stc/cvec.h | 220 ++++++++++++++++++------------------ include/stc/extend.h | 2 +- include/stc/priv/template.h | 22 ++-- 13 files changed, 747 insertions(+), 747 deletions(-) diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h index 2e73b0fb..291d90a6 100644 --- a/include/stc/algo/sort.h +++ b/include/stc/algo/sort.h @@ -52,12 +52,12 @@ int main() { typedef i_val i_type; #endif #ifndef i_at - #define i_at(arr, idx) _cx_memb(_at_mut)(arr, idx) + #define i_at(arr, idx) _cx_MEMB(_at_mut)(arr, idx) #endif #include "../priv/template.h" -static inline void _cx_memb(_insertsort_ij)(_cx_self* arr, intptr_t lo, intptr_t hi) { +static inline void _cx_MEMB(_insertsort_ij)(_cx_Self* arr, intptr_t lo, intptr_t hi) { for (intptr_t j = lo, i = lo + 1; i <= hi; j = i, ++i) { i_val key = *i_at(arr, i); while (j >= 0 && (i_less((&key), i_at(arr, j)))) { @@ -68,7 +68,7 @@ static inline void _cx_memb(_insertsort_ij)(_cx_self* arr, intptr_t lo, intptr_t } } -static inline void _cx_memb(_sort_ij)(_cx_self* arr, intptr_t lo, intptr_t hi) { +static inline void _cx_MEMB(_sort_ij)(_cx_Self* arr, intptr_t lo, intptr_t hi) { intptr_t i = lo, j; while (lo < hi) { i_val pivot = *i_at(arr, lo + (hi - lo)*7/16); @@ -87,14 +87,14 @@ static inline void _cx_memb(_sort_ij)(_cx_self* arr, intptr_t lo, intptr_t hi) { c_swap(intptr_t, &hi, &j); } - if (j - lo > 64) _cx_memb(_sort_ij)(arr, lo, j); - else if (j > lo) _cx_memb(_insertsort_ij)(arr, lo, j); + if (j - lo > 64) _cx_MEMB(_sort_ij)(arr, lo, j); + else if (j > lo) _cx_MEMB(_insertsort_ij)(arr, lo, j); lo = i; } } -static inline void _cx_memb(_sort_n)(_cx_self* arr, intptr_t len) { - _cx_memb(_sort_ij)(arr, 0, len - 1); +static inline void _cx_MEMB(_sort_n)(_cx_Self* arr, intptr_t len) { + _cx_MEMB(_sort_ij)(arr, 0, len - 1); } #include "../priv/template2.h" diff --git a/include/stc/carc.h b/include/stc/carc.h index 749b1fc1..3b60fe78 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -91,119 +91,119 @@ typedef i_keyraw _cx_raw; #define _i_atomic_dec_and_test(v) !(--*(v)) #endif #ifndef i_is_forward -_cx_deftypes(_c_carc_types, _cx_self, i_key); +_cx_DEFTYPES(_c_carc_types, _cx_Self, i_key); #endif -struct _cx_memb(_rep_) { catomic_long counter; i_key value; }; +struct _cx_MEMB(_rep_) { catomic_long counter; i_key value; }; -STC_INLINE _cx_self _cx_memb(_init)(void) - { return c_LITERAL(_cx_self){NULL, NULL}; } +STC_INLINE _cx_Self _cx_MEMB(_init)(void) + { return c_LITERAL(_cx_Self){NULL, NULL}; } -STC_INLINE long _cx_memb(_use_count)(const _cx_self* self) +STC_INLINE long _cx_MEMB(_use_count)(const _cx_Self* self) { return self->use_count ? *self->use_count : 0; } -STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) { - _cx_self ptr = {p}; +STC_INLINE _cx_Self _cx_MEMB(_from_ptr)(_cx_value* p) { + _cx_Self ptr = {p}; if (p) *(ptr.use_count = _i_alloc(catomic_long)) = 1; return ptr; } // c++: std::make_shared<_cx_value>(val) -STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) { - _cx_self ptr; - struct _cx_memb(_rep_)* rep = _i_alloc(struct _cx_memb(_rep_)); +STC_INLINE _cx_Self _cx_MEMB(_make)(_cx_value val) { + _cx_Self ptr; + struct _cx_MEMB(_rep_)* rep = _i_alloc(struct _cx_MEMB(_rep_)); *(ptr.use_count = &rep->counter) = 1; *(ptr.get = &rep->value) = val; return ptr; } -STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self) +STC_INLINE _cx_raw _cx_MEMB(_toraw)(const _cx_Self* self) { return i_keyto(self->get); } -STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) { - _cx_self ptr = *self; +STC_INLINE _cx_Self _cx_MEMB(_move)(_cx_Self* self) { + _cx_Self ptr = *self; self->get = NULL, self->use_count = NULL; return ptr; } -STC_INLINE void _cx_memb(_drop)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) { if (self->use_count && _i_atomic_dec_and_test(self->use_count)) { i_keydrop(self->get); - if ((char *)self->get != (char *)self->use_count + offsetof(struct _cx_memb(_rep_), value)) + if ((char *)self->get != (char *)self->use_count + offsetof(struct _cx_MEMB(_rep_), value)) i_free(self->get); i_free((long*)self->use_count); } } -STC_INLINE void _cx_memb(_reset)(_cx_self* self) { - _cx_memb(_drop)(self); +STC_INLINE void _cx_MEMB(_reset)(_cx_Self* self) { + _cx_MEMB(_drop)(self); self->use_count = NULL, self->get = NULL; } -STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) { - _cx_memb(_drop)(self); - *self = _cx_memb(_from_ptr)(p); +STC_INLINE void _cx_MEMB(_reset_to)(_cx_Self* self, _cx_value* p) { + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_from_ptr)(p); } #ifndef i_no_emplace -STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw) - { return _cx_memb(_make)(i_keyfrom(raw)); } +STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_raw raw) + { return _cx_MEMB(_make)(i_keyfrom(raw)); } #else -STC_INLINE _cx_self _cx_memb(_from)(_cx_value val) - { return _cx_memb(_make)(val); } +STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_value val) + { return _cx_MEMB(_make)(val); } #endif // does not use i_keyclone, so OK to always define. -STC_INLINE _cx_self _cx_memb(_clone)(_cx_self ptr) { +STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self ptr) { if (ptr.use_count) _i_atomic_inc(ptr.use_count); return ptr; } // take ownership of unowned -STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) { - _cx_memb(_drop)(self); +STC_INLINE void _cx_MEMB(_take)(_cx_Self* self, _cx_Self unowned) { + _cx_MEMB(_drop)(self); *self = unowned; } // share ownership with ptr -STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self ptr) { +STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { if (ptr.use_count) _i_atomic_inc(ptr.use_count); - _cx_memb(_drop)(self); + _cx_MEMB(_drop)(self); *self = ptr; } #ifndef i_no_cmp -STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) +STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } -STC_INLINE int _cx_memb(_cmp)(const _cx_self* self, const _cx_self* other) { +STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_cmp((&rx), (&ry)); } #endif #ifdef _i_eq -STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) +STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { +STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_eq((&rx), (&ry)); } #elif !defined i_no_cmp -STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) +STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry) == 0; } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) - { return _cx_memb(_cmp)(self, other) == 0; } +STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) + { return _cx_MEMB(_cmp)(self, other) == 0; } #endif #ifndef i_no_hash -STC_INLINE uint64_t _cx_memb(_raw_hash)(const _cx_raw* rx) +STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } -STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self) +STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } #endif diff --git a/include/stc/cbox.h b/include/stc/cbox.h index d7f6246d..86283ad7 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -77,119 +77,119 @@ int main() { typedef i_keyraw _cx_raw; #ifndef i_is_forward -_cx_deftypes(_c_cbox_types, _cx_self, i_key); +_cx_DEFTYPES(_c_cbox_types, _cx_Self, i_key); #endif // constructors (take ownership) -STC_INLINE _cx_self _cx_memb(_init)(void) - { return c_LITERAL(_cx_self){NULL}; } +STC_INLINE _cx_Self _cx_MEMB(_init)(void) + { return c_LITERAL(_cx_Self){NULL}; } -STC_INLINE long _cx_memb(_use_count)(const _cx_self* self) +STC_INLINE long _cx_MEMB(_use_count)(const _cx_Self* self) { return (long)(self->get != NULL); } -STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) - { return c_LITERAL(_cx_self){p}; } +STC_INLINE _cx_Self _cx_MEMB(_from_ptr)(_cx_value* p) + { return c_LITERAL(_cx_Self){p}; } // c++: std::make_unique(val) -STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) { - _cx_self ptr = {_i_alloc(_cx_value)}; +STC_INLINE _cx_Self _cx_MEMB(_make)(_cx_value val) { + _cx_Self ptr = {_i_alloc(_cx_value)}; *ptr.get = val; return ptr; } -STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self) +STC_INLINE _cx_raw _cx_MEMB(_toraw)(const _cx_Self* self) { return i_keyto(self->get); } // destructor -STC_INLINE void _cx_memb(_drop)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) { if (self->get) { i_keydrop(self->get); i_free(self->get); } } -STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) { - _cx_self ptr = *self; +STC_INLINE _cx_Self _cx_MEMB(_move)(_cx_Self* self) { + _cx_Self ptr = *self; self->get = NULL; return ptr; } -STC_INLINE _cx_value* _cx_memb(_release)(_cx_self* self) - { return _cx_memb(_move)(self).get; } +STC_INLINE _cx_value* _cx_MEMB(_release)(_cx_Self* self) + { return _cx_MEMB(_move)(self).get; } -STC_INLINE void _cx_memb(_reset)(_cx_self* self) { - _cx_memb(_drop)(self); +STC_INLINE void _cx_MEMB(_reset)(_cx_Self* self) { + _cx_MEMB(_drop)(self); self->get = NULL; } // take ownership of p -STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) { - _cx_memb(_drop)(self); +STC_INLINE void _cx_MEMB(_reset_to)(_cx_Self* self, _cx_value* p) { + _cx_MEMB(_drop)(self); self->get = p; } #ifndef i_no_emplace -STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw) - { return _cx_memb(_make)(i_keyfrom(raw)); } +STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_raw raw) + { return _cx_MEMB(_make)(i_keyfrom(raw)); } #else -STC_INLINE _cx_self _cx_memb(_from)(_cx_value val) - { return _cx_memb(_make)(val); } +STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_value val) + { return _cx_MEMB(_make)(val); } #endif #if !defined i_no_clone - STC_INLINE _cx_self _cx_memb(_clone)(_cx_self other) { + STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self other) { if (!other.get) return other; - _cx_self out = {_i_alloc(i_key)}; + _cx_Self out = {_i_alloc(i_key)}; *out.get = i_keyclone((*other.get)); return out; } #endif // !i_no_clone // take ownership of unowned -STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) { - _cx_memb(_drop)(self); +STC_INLINE void _cx_MEMB(_take)(_cx_Self* self, _cx_Self unowned) { + _cx_MEMB(_drop)(self); *self = unowned; } // transfer ownership from moved; set moved to NULL -STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self* moved) { +STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) { if (moved->get == self->get) return; - _cx_memb(_drop)(self); + _cx_MEMB(_drop)(self); *self = *moved; moved->get = NULL; } #ifndef i_no_cmp -STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) +STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } -STC_INLINE int _cx_memb(_cmp)(const _cx_self* self, const _cx_self* other) { +STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_cmp((&rx), (&ry)); } #endif #ifdef _i_eq -STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) +STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { +STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_eq((&rx), (&ry)); } #elif !defined i_no_cmp -STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) +STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry) == 0; } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) - { return _cx_memb(_cmp)(self, other) == 0; } +STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) + { return _cx_MEMB(_cmp)(self, other) == 0; } #endif #ifndef i_no_hash -STC_INLINE uint64_t _cx_memb(_raw_hash)(const _cx_raw* rx) +STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } -STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self) +STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } #endif diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index a406c2b0..0eac5a1d 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -32,101 +32,101 @@ #endif #undef _pop -STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value); -STC_API _cx_iter _cx_memb(_insert_n)(_cx_self* self, intptr_t idx, const _cx_value* arr, intptr_t n); -STC_API _cx_iter _cx_memb(_insert_uninit)(_cx_self* self, intptr_t idx, intptr_t n); -STC_API void _cx_memb(_erase_n)(_cx_self* self, intptr_t idx, intptr_t n); +STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value); +STC_API _cx_iter _cx_MEMB(_insert_n)(_cx_Self* self, intptr_t idx, const _cx_value* arr, intptr_t n); +STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n); +STC_API void _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n); STC_INLINE const _cx_value* -_cx_memb(_at)(const _cx_self* self, intptr_t idx) +_cx_MEMB(_at)(const _cx_Self* self, intptr_t idx) { return self->data + _cdeq_topos(self, idx); } STC_INLINE _cx_value* -_cx_memb(_at_mut)(_cx_self* self, intptr_t idx) +_cx_MEMB(_at_mut)(_cx_Self* self, intptr_t idx) { return self->data + _cdeq_topos(self, idx); } STC_INLINE _cx_value* -_cx_memb(_push_back)(_cx_self* self, _cx_value val) - { return _cx_memb(_push)(self, val); } +_cx_MEMB(_push_back)(_cx_Self* self, _cx_value val) + { return _cx_MEMB(_push)(self, val); } STC_INLINE void -_cx_memb(_pop_back)(_cx_self* self) { - assert(!_cx_memb(_empty)(self)); +_cx_MEMB(_pop_back)(_cx_Self* self) { + assert(!_cx_MEMB(_empty)(self)); self->end = (self->end - 1) & self->capmask; i_keydrop((self->data + self->end)); } -STC_INLINE _cx_value _cx_memb(_pull_back)(_cx_self* self) { // move back out of deq - assert(!_cx_memb(_empty)(self)); +STC_INLINE _cx_value _cx_MEMB(_pull_back)(_cx_Self* self) { // move back out of deq + assert(!_cx_MEMB(_empty)(self)); self->end = (self->end - 1) & self->capmask; return self->data[self->end]; } STC_INLINE _cx_iter -_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, const _cx_value val) { +_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, const _cx_value val) { intptr_t idx = _cdeq_toidx(self, it.pos); - return _cx_memb(_insert_n)(self, idx, &val, 1); + return _cx_MEMB(_insert_n)(self, idx, &val, 1); } STC_INLINE _cx_iter -_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { - _cx_memb(_erase_n)(self, _cdeq_toidx(self, it.pos), 1); +_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) { + _cx_MEMB(_erase_n)(self, _cdeq_toidx(self, it.pos), 1); if (it.pos == self->end) it.ref = NULL; return it; } STC_INLINE _cx_iter -_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { +_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) { intptr_t idx1 = _cdeq_toidx(self, it1.pos); intptr_t idx2 = _cdeq_toidx(self, it2.pos); - _cx_memb(_erase_n)(self, idx1, idx2 - idx1); + _cx_MEMB(_erase_n)(self, idx1, idx2 - idx1); if (it1.pos == self->end) it1.ref = NULL; return it1; } #if !defined i_no_emplace STC_API _cx_iter -_cx_memb(_emplace_n)(_cx_self* self, intptr_t idx, const _cx_raw* raw, intptr_t n); +_cx_MEMB(_emplace_n)(_cx_Self* self, intptr_t idx, const _cx_raw* raw, intptr_t n); STC_INLINE _cx_value* -_cx_memb(_emplace_front)(_cx_self* self, const _cx_raw raw) - { return _cx_memb(_push_front)(self, i_keyfrom(raw)); } +_cx_MEMB(_emplace_front)(_cx_Self* self, const _cx_raw raw) + { return _cx_MEMB(_push_front)(self, i_keyfrom(raw)); } STC_INLINE _cx_value* -_cx_memb(_emplace_back)(_cx_self* self, const _cx_raw raw) - { return _cx_memb(_push)(self, i_keyfrom(raw)); } +_cx_MEMB(_emplace_back)(_cx_Self* self, const _cx_raw raw) + { return _cx_MEMB(_push)(self, i_keyfrom(raw)); } STC_INLINE _cx_iter -_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, const _cx_raw raw) - { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); } +_cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, const _cx_raw raw) + { return _cx_MEMB(_insert_at)(self, it, i_keyfrom(raw)); } #endif #if defined _i_has_cmp || defined _i_has_eq -STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw); +STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw); STC_INLINE _cx_iter -_cx_memb(_find)(const _cx_self* self, _cx_raw raw) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw); +_cx_MEMB(_find)(const _cx_Self* self, _cx_raw raw) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw); } STC_INLINE const _cx_value* -_cx_memb(_get)(const _cx_self* self, _cx_raw raw) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw).ref; +_cx_MEMB(_get)(const _cx_Self* self, _cx_raw raw) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw).ref; } STC_INLINE _cx_value* -_cx_memb(_get_mut)(_cx_self* self, _cx_raw raw) - { return (_cx_value *) _cx_memb(_get)(self, raw); } +_cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw raw) + { return (_cx_value *) _cx_MEMB(_get)(self, raw); } #endif /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) STC_DEF _cx_value* -_cx_memb(_push_front)(_cx_self* self, i_key value) { +_cx_MEMB(_push_front)(_cx_Self* self, i_key value) { intptr_t start = (self->start - 1) & self->capmask; if (start == self->end) { // full - _cx_memb(_reserve)(self, self->capmask + 3); // => 2x expand + _cx_MEMB(_reserve)(self, self->capmask + 3); // => 2x expand start = (self->start - 1) & self->capmask; } _cx_value *v = self->data + start; @@ -136,24 +136,24 @@ _cx_memb(_push_front)(_cx_self* self, i_key value) { } STC_DEF void -_cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t n) { - const intptr_t len = _cx_memb(_size)(self); +_cx_MEMB(_erase_n)(_cx_Self* self, const intptr_t idx, const intptr_t n) { + const intptr_t len = _cx_MEMB(_size)(self); for (intptr_t i = idx + n - 1; i >= idx; --i) - i_keydrop(_cx_memb(_at_mut)(self, i)); + i_keydrop(_cx_MEMB(_at_mut)(self, i)); for (intptr_t i = idx, j = i + n; j < len; ++i, ++j) - *_cx_memb(_at_mut)(self, i) = *_cx_memb(_at)(self, j); + *_cx_MEMB(_at_mut)(self, i) = *_cx_MEMB(_at)(self, j); self->end = (self->end - n) & self->capmask; } STC_DEF _cx_iter -_cx_memb(_insert_uninit)(_cx_self* self, const intptr_t idx, const intptr_t n) { - const intptr_t len = _cx_memb(_size)(self); +_cx_MEMB(_insert_uninit)(_cx_Self* self, const intptr_t idx, const intptr_t n) { + const intptr_t len = _cx_MEMB(_size)(self); _cx_iter it = {._s=self}; if (len + n > self->capmask) - if (!_cx_memb(_reserve)(self, len + n)) + if (!_cx_MEMB(_reserve)(self, len + n)) return it; for (intptr_t i = len - 1, j = i + n; i >= idx; --i, --j) - *_cx_memb(_at_mut)(self, j) = *_cx_memb(_at)(self, i); + *_cx_MEMB(_at_mut)(self, j) = *_cx_MEMB(_at)(self, i); self->end = (self->end + n) & self->capmask; it.pos = _cdeq_topos(self, idx); @@ -162,27 +162,27 @@ _cx_memb(_insert_uninit)(_cx_self* self, const intptr_t idx, const intptr_t n) { } STC_DEF _cx_iter -_cx_memb(_insert_n)(_cx_self* self, const intptr_t idx, const _cx_value* arr, const intptr_t n) { - _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); +_cx_MEMB(_insert_n)(_cx_Self* self, const intptr_t idx, const _cx_value* arr, const intptr_t n) { + _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n); for (intptr_t i = idx, j = 0; j < n; ++i, ++j) - *_cx_memb(_at_mut)(self, i) = arr[j]; + *_cx_MEMB(_at_mut)(self, i) = arr[j]; return it; } #if !defined i_no_emplace STC_DEF _cx_iter -_cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw* raw, const intptr_t n) { - _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); +_cx_MEMB(_emplace_n)(_cx_Self* self, const intptr_t idx, const _cx_raw* raw, const intptr_t n) { + _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n); for (intptr_t i = idx, j = 0; j < n; ++i, ++j) - *_cx_memb(_at_mut)(self, i) = i_keyfrom(raw[j]); + *_cx_MEMB(_at_mut)(self, i) = i_keyfrom(raw[j]); return it; } #endif #if defined _i_has_cmp || defined _i_has_eq STC_DEF _cx_iter -_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { - for (; i1.pos != i2.pos; _cx_memb(_next)(&i1)) { +_cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { + for (; i1.pos != i2.pos; _cx_MEMB(_next)(&i1)) { const _cx_raw r = i_keyto(i1.ref); if (i_eq((&raw), (&r))) break; diff --git a/include/stc/clist.h b/include/stc/clist.h index 4d05a3d1..0785a6af 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -82,77 +82,77 @@ #include "priv/template.h" #ifndef i_is_forward - _cx_deftypes(_c_clist_types, _cx_self, i_key); + _cx_DEFTYPES(_c_clist_types, _cx_Self, i_key); #endif -_cx_deftypes(_c_clist_complete_types, _cx_self, dummy); +_cx_DEFTYPES(_c_clist_complete_types, _cx_Self, dummy); typedef i_keyraw _cx_raw; -STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value); -STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value); -STC_API _cx_iter _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value); -STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it); -STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2); +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API _cx_value* _cx_MEMB(_push_back)(_cx_Self* self, i_key value); +STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value); +STC_API _cx_iter _cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, i_key value); +STC_API _cx_iter _cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it); +STC_API _cx_iter _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2); #if !defined i_no_cmp || defined _i_has_eq -STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val); -STC_API intptr_t _cx_memb(_remove)(_cx_self* self, _cx_raw val); +STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val); +STC_API intptr_t _cx_MEMB(_remove)(_cx_Self* self, _cx_raw val); #endif #ifndef i_no_cmp -STC_API bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, const _cx_value*)); -STC_API int _cx_memb(_sort_cmp_)(const _cx_value*, const _cx_value*); -STC_INLINE bool _cx_memb(_sort)(_cx_self* self) - { return _cx_memb(_sort_with)(self, _cx_memb(_sort_cmp_)); } +STC_API bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*)); +STC_API int _cx_MEMB(_sort_cmp_)(const _cx_value*, const _cx_value*); +STC_INLINE bool _cx_MEMB(_sort)(_cx_Self* self) + { return _cx_MEMB(_sort_with)(self, _cx_MEMB(_sort_cmp_)); } #endif -STC_API void _cx_memb(_reverse)(_cx_self* self); -STC_API _cx_iter _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other); -STC_API _cx_self _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2); -STC_API _cx_value* _cx_memb(_push_back_node)(_cx_self* self, _cx_node* node); -STC_API _cx_value* _cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node); -STC_API _cx_node* _cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref); -STC_API void _cx_memb(_erase_after_node)(_cx_self* self, _cx_node* ref); -STC_INLINE _cx_node* _cx_memb(_get_node)(_cx_value* pval) { return _clist_tonode(pval); } -STC_INLINE _cx_node* _cx_memb(_unlink_front_node)(_cx_self* self) - { return _cx_memb(_unlink_after_node)(self, self->last); } +STC_API void _cx_MEMB(_reverse)(_cx_Self* self); +STC_API _cx_iter _cx_MEMB(_splice)(_cx_Self* self, _cx_iter it, _cx_Self* other); +STC_API _cx_Self _cx_MEMB(_split_off)(_cx_Self* self, _cx_iter it1, _cx_iter it2); +STC_API _cx_value* _cx_MEMB(_push_back_node)(_cx_Self* self, _cx_node* node); +STC_API _cx_value* _cx_MEMB(_insert_after_node)(_cx_Self* self, _cx_node* ref, _cx_node* node); +STC_API _cx_node* _cx_MEMB(_unlink_after_node)(_cx_Self* self, _cx_node* ref); +STC_API void _cx_MEMB(_erase_after_node)(_cx_Self* self, _cx_node* ref); +STC_INLINE _cx_node* _cx_MEMB(_get_node)(_cx_value* pval) { return _clist_tonode(pval); } +STC_INLINE _cx_node* _cx_MEMB(_unlink_front_node)(_cx_Self* self) + { return _cx_MEMB(_unlink_after_node)(self, self->last); } #if !defined i_no_clone -STC_API _cx_self _cx_memb(_clone)(_cx_self cx); -STC_INLINE i_key _cx_memb(_value_clone)(i_key val) { return i_keyclone(val); } +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); +STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val) { return i_keyclone(val); } STC_INLINE void -_cx_memb(_copy)(_cx_self *self, const _cx_self* other) { +_cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { if (self->last == other->last) return; - _cx_memb(_drop)(self); *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); *self = _cx_MEMB(_clone)(*other); } #endif // !i_no_clone #if !defined i_no_emplace -STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push_back)(self, i_keyfrom(raw)); } -STC_INLINE _cx_value* _cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push_front)(self, i_keyfrom(raw)); } -STC_INLINE _cx_iter _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) - { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); } -STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push_back)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_MEMB(_emplace_back)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push_back)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_MEMB(_emplace_front)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push_front)(self, i_keyfrom(raw)); } +STC_INLINE _cx_iter _cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, _cx_raw raw) + { return _cx_MEMB(_insert_at)(self, it, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push_back)(self, i_keyfrom(raw)); } #endif // !i_no_emplace -STC_INLINE _cx_self _cx_memb(_init)(void) { return c_LITERAL(_cx_self){NULL}; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_memb(_push_back)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } -STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) { (void)(self + n); return true; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return self->last == NULL; } -STC_INLINE void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_drop)(self); } -STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, i_key value) - { return _cx_memb(_push_back)(self, value); } -STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) - { assert(!_cx_memb(_empty)(self)); _cx_memb(_erase_after_node)(self, self->last); } -STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return &self->last->next->value; } -STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) { return &self->last->value; } -STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* pval) { return i_keyto(pval); } -STC_INLINE void _cx_memb(_value_drop)(_cx_value* pval) { i_keydrop(pval); } +STC_INLINE _cx_Self _cx_MEMB(_init)(void) { return c_LITERAL(_cx_Self){NULL}; } +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push_back)(self, i_keyfrom(*raw++)); } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } +STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t n) { (void)(self + n); return true; } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return self->last == NULL; } +STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) { _cx_MEMB(_drop)(self); } +STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value) + { return _cx_MEMB(_push_back)(self, value); } +STC_INLINE void _cx_MEMB(_pop_front)(_cx_Self* self) + { assert(!_cx_MEMB(_empty)(self)); _cx_MEMB(_erase_after_node)(self, self->last); } +STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return &self->last->next->value; } +STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return &self->last->value; } +STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval) { return i_keyto(pval); } +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* pval) { i_keydrop(pval); } STC_INLINE intptr_t -_cx_memb(_count)(const _cx_self* self) { +_cx_MEMB(_count)(const _cx_Self* self) { intptr_t n = 1; const _cx_node *node = self->last; if (!node) return 0; while ((node = node->next) != self->last) ++n; @@ -160,53 +160,53 @@ _cx_memb(_count)(const _cx_self* self) { } STC_INLINE _cx_iter -_cx_memb(_begin)(const _cx_self* self) { +_cx_MEMB(_begin)(const _cx_Self* self) { _cx_value* head = self->last ? &self->last->next->value : NULL; return c_LITERAL(_cx_iter){head, &self->last, self->last}; } STC_INLINE _cx_iter -_cx_memb(_end)(const _cx_self* self) +_cx_MEMB(_end)(const _cx_Self* self) { return c_LITERAL(_cx_iter){NULL}; } STC_INLINE void -_cx_memb(_next)(_cx_iter* it) { +_cx_MEMB(_next)(_cx_iter* it) { _cx_node* node = it->prev = _clist_tonode(it->ref); it->ref = (node == *it->_last ? NULL : &node->next->value); } STC_INLINE _cx_iter -_cx_memb(_advance)(_cx_iter it, size_t n) { - while (n-- && it.ref) _cx_memb(_next)(&it); +_cx_MEMB(_advance)(_cx_iter it, size_t n) { + while (n-- && it.ref) _cx_MEMB(_next)(&it); return it; } STC_INLINE _cx_iter -_cx_memb(_splice_range)(_cx_self* self, _cx_iter it, - _cx_self* other, _cx_iter it1, _cx_iter it2) { - _cx_self tmp = _cx_memb(_split_off)(other, it1, it2); - return _cx_memb(_splice)(self, it, &tmp); +_cx_MEMB(_splice_range)(_cx_Self* self, _cx_iter it, + _cx_Self* other, _cx_iter it1, _cx_iter it2) { + _cx_Self tmp = _cx_MEMB(_split_off)(other, it1, it2); + return _cx_MEMB(_splice)(self, it, &tmp); } #if !defined i_no_cmp || defined _i_has_eq STC_INLINE _cx_iter -_cx_memb(_find)(const _cx_self* self, _cx_raw val) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val); +_cx_MEMB(_find)(const _cx_Self* self, _cx_raw val) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val); } STC_INLINE const _cx_value* -_cx_memb(_get)(const _cx_self* self, _cx_raw val) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref; +_cx_MEMB(_get)(const _cx_Self* self, _cx_raw val) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val).ref; } STC_INLINE _cx_value* -_cx_memb(_get_mut)(_cx_self* self, _cx_raw val) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref; +_cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw val) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val).ref; } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - _cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other); - for (; i.ref && j.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) { +STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other); + for (; i.ref && j.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) { const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); if (!(i_eq((&_rx), (&_ry)))) return false; } @@ -218,29 +218,29 @@ STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { #if defined(i_implement) || defined(i_static) #if !defined i_no_clone -STC_DEF _cx_self -_cx_memb(_clone)(_cx_self cx) { - _cx_self out = _cx_memb(_init)(); - c_foreach (it, _cx_self, cx) - _cx_memb(_push_back)(&out, i_keyclone((*it.ref))); +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self cx) { + _cx_Self out = _cx_MEMB(_init)(); + c_foreach (it, _cx_Self, cx) + _cx_MEMB(_push_back)(&out, i_keyclone((*it.ref))); return out; } #endif STC_DEF void -_cx_memb(_drop)(_cx_self* self) { - while (self->last) _cx_memb(_erase_after_node)(self, self->last); +_cx_MEMB(_drop)(_cx_Self* self) { + while (self->last) _cx_MEMB(_erase_after_node)(self, self->last); } STC_DEF _cx_value* -_cx_memb(_push_back)(_cx_self* self, i_key value) { +_cx_MEMB(_push_back)(_cx_Self* self, i_key value) { _c_clist_insert_entry_after(self->last, value); self->last = entry; return &entry->value; } STC_DEF _cx_value* -_cx_memb(_push_front)(_cx_self* self, i_key value) { +_cx_MEMB(_push_front)(_cx_Self* self, i_key value) { _c_clist_insert_entry_after(self->last, value); if (!self->last) self->last = entry; @@ -248,14 +248,14 @@ _cx_memb(_push_front)(_cx_self* self, i_key value) { } STC_DEF _cx_value* -_cx_memb(_push_back_node)(_cx_self* self, _cx_node* node) { +_cx_MEMB(_push_back_node)(_cx_Self* self, _cx_node* node) { _c_clist_insert_after_node(self->last, node); self->last = node; return &node->value; } STC_DEF _cx_value* -_cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node) { +_cx_MEMB(_insert_after_node)(_cx_Self* self, _cx_node* ref, _cx_node* node) { _c_clist_insert_after_node(ref, node); if (!self->last) self->last = node; @@ -263,7 +263,7 @@ _cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node) { } STC_DEF _cx_iter -_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) { +_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, i_key value) { _cx_node* node = it.ref ? it.prev : self->last; _c_clist_insert_entry_after(node, value); if (!self->last || !it.ref) { @@ -275,32 +275,32 @@ _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) { } STC_DEF _cx_iter -_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { +_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) { _cx_node *node = _clist_tonode(it.ref); it.ref = (node == self->last) ? NULL : &node->next->value; - _cx_memb(_erase_after_node)(self, it.prev); + _cx_MEMB(_erase_after_node)(self, it.prev); return it; } STC_DEF _cx_iter -_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { +_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) { _cx_node *end = it2.ref ? _clist_tonode(it2.ref) : self->last->next; if (it1.ref != it2.ref) do { - _cx_memb(_erase_after_node)(self, it1.prev); + _cx_MEMB(_erase_after_node)(self, it1.prev); if (!self->last) break; } while (it1.prev->next != end); return it2; } STC_DEF void -_cx_memb(_erase_after_node)(_cx_self* self, _cx_node* ref) { - _cx_node* node = _cx_memb(_unlink_after_node)(self, ref); +_cx_MEMB(_erase_after_node)(_cx_Self* self, _cx_node* ref) { + _cx_node* node = _cx_MEMB(_unlink_after_node)(self, ref); i_keydrop((&node->value)); i_free(node); } STC_DEF _cx_node* -_cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref) { +_cx_MEMB(_unlink_after_node)(_cx_Self* self, _cx_node* ref) { _cx_node* node = ref->next, *next = node->next; ref->next = next; if (node == next) @@ -311,17 +311,17 @@ _cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref) { } STC_DEF void -_cx_memb(_reverse)(_cx_self* self) { - _cx_self rev = {NULL}; +_cx_MEMB(_reverse)(_cx_Self* self) { + _cx_Self rev = {NULL}; while (self->last) { - _cx_node* node = _cx_memb(_unlink_after_node)(self, self->last); - _cx_memb(_insert_after_node)(&rev, rev.last, node); + _cx_node* node = _cx_MEMB(_unlink_after_node)(self, self->last); + _cx_MEMB(_insert_after_node)(&rev, rev.last, node); } *self = rev; } STC_DEF _cx_iter -_cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) { +_cx_MEMB(_splice)(_cx_Self* self, _cx_iter it, _cx_Self* other) { if (!self->last) self->last = other->last; else if (other->last) { @@ -335,9 +335,9 @@ _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) { return it; } -STC_DEF _cx_self -_cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) { - _cx_self lst = {NULL}; +STC_DEF _cx_Self +_cx_MEMB(_split_off)(_cx_Self* self, _cx_iter it1, _cx_iter it2) { + _cx_Self lst = {NULL}; if (it1.ref == it2.ref) return lst; _cx_node *p1 = it1.prev, @@ -353,8 +353,8 @@ _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) { #if !defined i_no_cmp || defined _i_has_eq STC_DEF _cx_iter -_cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) { - c_foreach (it, _cx_self, it1, it2) { +_cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) { + c_foreach (it, _cx_Self, it1, it2) { _cx_raw r = i_keyto(it.ref); if (i_eq((&r), (&val))) return it; @@ -363,14 +363,14 @@ _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) { } STC_DEF intptr_t -_cx_memb(_remove)(_cx_self* self, _cx_raw val) { +_cx_MEMB(_remove)(_cx_Self* self, _cx_raw val) { intptr_t n = 0; _cx_node *prev = self->last, *node; if (prev) do { node = prev->next; _cx_raw r = i_keyto((&node->value)); if (i_eq((&r), (&val))) { - _cx_memb(_erase_after_node)(self, prev), ++n; + _cx_MEMB(_erase_after_node)(self, prev), ++n; if (!self->last) break; } else prev = node; @@ -380,16 +380,16 @@ _cx_memb(_remove)(_cx_self* self, _cx_raw val) { #endif #ifndef i_no_cmp -STC_DEF int _cx_memb(_sort_cmp_)(const _cx_value* x, const _cx_value* y) { +STC_DEF int _cx_MEMB(_sort_cmp_)(const _cx_value* x, const _cx_value* y) { const _cx_raw a = i_keyto(x), b = i_keyto(y); return i_cmp((&a), (&b)); } -STC_DEF bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, const _cx_value*)) { +STC_DEF bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*)) { size_t len = 0, cap = 0; _cx_value *a = NULL, *p = NULL; _cx_iter i; - for (i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i)) { + for (i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i)) { if (len == cap) { if ((p = (_cx_value *)i_realloc(a, (cap += cap/2 + 4)*sizeof *a))) a = p; else { i_free(a); return false; } @@ -397,7 +397,7 @@ STC_DEF bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, co a[len++] = *i.ref; } qsort(a, len, sizeof *a, (int(*)(const void*, const void*))cmp); - for (i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i), ++p) + for (i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i), ++p) *i.ref = *p; i_free(a); return true; } diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 2e234fb5..21e7b933 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -72,7 +72,7 @@ typedef struct { intptr_t idx; uint8_t hashx, found; } chash_bucket; #endif #include "priv/template.h" #ifndef i_is_forward - _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); + _cx_DEFTYPES(_c_chash_types, _cx_Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); #endif _i_MAP_ONLY( struct _cx_value { @@ -81,60 +81,60 @@ _i_MAP_ONLY( struct _cx_value { }; ) typedef i_keyraw _cx_keyraw; -typedef i_valraw _cx_memb(_rmapped); +typedef i_valraw _cx_MEMB(_rmapped); typedef _i_SET_ONLY( i_keyraw ) _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } ) _cx_raw; -STC_API _cx_self _cx_memb(_with_capacity)(intptr_t cap); +STC_API _cx_Self _cx_MEMB(_with_capacity)(intptr_t cap); #if !defined i_no_clone -STC_API _cx_self _cx_memb(_clone)(_cx_self map); +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self map); #endif -STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API void _cx_memb(_clear)(_cx_self* self); -STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t capacity); -STC_API chash_bucket _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr); -STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey); -STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val); -STC_API float _cx_memb(_max_load_factor)(const _cx_self* self); -STC_API intptr_t _cx_memb(_capacity)(const _cx_self* map); - -STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self map = {0}; return map; } -STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, (intptr_t)self->size); } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* map) { return !map->size; } -STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* map) { return (intptr_t)map->size; } -STC_INLINE intptr_t _cx_memb(_bucket_count)(_cx_self* map) { return map->bucket_count; } -STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) - { return self->size && _cx_memb(_bucket_)(self, &rkey).found; } +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API void _cx_MEMB(_clear)(_cx_Self* self); +STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t capacity); +STC_API chash_bucket _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr); +STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey); +STC_API void _cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* val); +STC_API float _cx_MEMB(_max_load_factor)(const _cx_Self* self); +STC_API intptr_t _cx_MEMB(_capacity)(const _cx_Self* map); + +STC_INLINE _cx_Self _cx_MEMB(_init)(void) { _cx_Self map = {0}; return map; } +STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self) { _cx_MEMB(_reserve)(self, (intptr_t)self->size); } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* map) { return !map->size; } +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* map) { return (intptr_t)map->size; } +STC_INLINE intptr_t _cx_MEMB(_bucket_count)(_cx_Self* map) { return map->bucket_count; } +STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey) + { return self->size && _cx_MEMB(_bucket_)(self, &rkey).found; } #ifndef _i_isset - STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped); + STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped); #if !defined i_no_emplace - STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped); + STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped); #endif STC_INLINE const _cx_mapped* - _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey) { - chash_bucket b = _cx_memb(_bucket_)(self, &rkey); + _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) { + chash_bucket b = _cx_MEMB(_bucket_)(self, &rkey); assert(b.found); return &self->data[b.idx].second; } STC_INLINE _cx_mapped* - _cx_memb(_at_mut)(_cx_self* self, _cx_keyraw rkey) - { return (_cx_mapped*)_cx_memb(_at)(self, rkey); } + _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey) + { return (_cx_mapped*)_cx_MEMB(_at)(self, rkey); } #endif // !_i_isset #if !defined i_no_clone -STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) { +STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { if (self->data == other->data) return; - _cx_memb(_drop)(self); - *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); } STC_INLINE _cx_value -_cx_memb(_value_clone)(_cx_value _val) { +_cx_MEMB(_value_clone)(_cx_value _val) { *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val))); _i_MAP_ONLY( _val.second = i_valclone(_val.second); ) return _val; @@ -143,8 +143,8 @@ _cx_memb(_value_clone)(_cx_value _val) { #if !defined i_no_emplace STC_INLINE _cx_result -_cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { - _cx_result _res = _cx_memb(_insert_entry_)(self, rkey); +_cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey); if (_res.inserted) { *_i_keyref(_res.ref) = i_keyfrom(rkey); _i_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); ) @@ -153,19 +153,19 @@ _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe } #endif // !i_no_emplace -STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* val) { +STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) { return _i_SET_ONLY( i_keyto(val) ) _i_MAP_ONLY( c_LITERAL(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} ); } -STC_INLINE void _cx_memb(_value_drop)(_cx_value* _val) { +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* _val) { i_keydrop(_i_keyref(_val)); _i_MAP_ONLY( i_valdrop((&_val->second)); ) } STC_INLINE _cx_result -_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); +_cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); if (_res.inserted) { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} else @@ -173,90 +173,90 @@ _cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { return _res; } -STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value _val) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); +STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value _val) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); if (_res.inserted) *_res.ref = _val; else - _cx_memb(_value_drop)(&_val); + _cx_MEMB(_value_drop)(&_val); return _res.ref; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) { +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) { while (n--) #if defined _i_isset && defined i_no_emplace - _cx_memb(_insert)(self, *raw++); + _cx_MEMB(_insert)(self, *raw++); #elif defined _i_isset - _cx_memb(_emplace)(self, *raw++); + _cx_MEMB(_emplace)(self, *raw++); #elif defined i_no_emplace - _cx_memb(_insert_or_assign)(self, raw->first, raw->second), ++raw; + _cx_MEMB(_insert_or_assign)(self, raw->first, raw->second), ++raw; #else - _cx_memb(_emplace_or_assign)(self, raw->first, raw->second), ++raw; + _cx_MEMB(_emplace_or_assign)(self, raw->first, raw->second), ++raw; #endif } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } -STC_API _cx_iter _cx_memb(_begin)(const _cx_self* self); +STC_API _cx_iter _cx_MEMB(_begin)(const _cx_Self* self); -STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) { return c_LITERAL(_cx_iter){NULL}; } -STC_INLINE void _cx_memb(_next)(_cx_iter* it) { +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { while ((++it->ref, (++it->sref)->hashx == 0)) ; if (it->ref == it->_end) it->ref = NULL; } -STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) { - while (n-- && it.ref) _cx_memb(_next)(&it); +STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) { + while (n-- && it.ref) _cx_MEMB(_next)(&it); return it; } STC_INLINE _cx_iter -_cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey) { chash_bucket b; - if (self->size && (b = _cx_memb(_bucket_)(self, &rkey)).found) + if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found) return c_LITERAL(_cx_iter){self->data + b.idx, self->data + self->bucket_count, self->slot + b.idx}; - return _cx_memb(_end)(self); + return _cx_MEMB(_end)(self); } STC_INLINE const _cx_value* -_cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey) { chash_bucket b; - if (self->size && (b = _cx_memb(_bucket_)(self, &rkey)).found) + if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found) return self->data + b.idx; return NULL; } STC_INLINE _cx_value* -_cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey) - { return (_cx_value*)_cx_memb(_get)(self, rkey); } +_cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey) + { return (_cx_value*)_cx_MEMB(_get)(self, rkey); } STC_INLINE int -_cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) { chash_bucket b = {0}; - if (self->size && (b = _cx_memb(_bucket_)(self, &rkey)).found) - _cx_memb(_erase_entry)(self, self->data + b.idx); + if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found) + _cx_MEMB(_erase_entry)(self, self->data + b.idx); return b.found; } STC_INLINE _cx_iter -_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { - _cx_memb(_erase_entry)(self, it.ref); +_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) { + _cx_MEMB(_erase_entry)(self, it.ref); if (it.sref->hashx == 0) - _cx_memb(_next)(&it); + _cx_MEMB(_next)(&it); return it; } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; - for (_cx_iter i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i)) { +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; + for (_cx_iter i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i)) { const _cx_keyraw _raw = i_keyto(_i_keyref(i.ref)); - if (!_cx_memb(_contains)(other, _raw)) return false; + if (!_cx_MEMB(_contains)(other, _raw)) return false; } return true; } @@ -268,7 +268,7 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { #endif #define fastrange_2(x, n) (intptr_t)((x) & (size_t)((n) - 1)) // n power of 2. -STC_DEF _cx_iter _cx_memb(_begin)(const _cx_self* self) { +STC_DEF _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { _cx_iter it = {self->data, self->data+self->bucket_count, self->slot}; if (it.sref) while (it.sref->hashx == 0) @@ -277,46 +277,46 @@ STC_DEF _cx_iter _cx_memb(_begin)(const _cx_self* self) { return it; } -STC_DEF float _cx_memb(_max_load_factor)(const _cx_self* self) { +STC_DEF float _cx_MEMB(_max_load_factor)(const _cx_Self* self) { return (float)(i_max_load_factor); } -STC_DEF intptr_t _cx_memb(_capacity)(const _cx_self* map) { +STC_DEF intptr_t _cx_MEMB(_capacity)(const _cx_Self* map) { return (intptr_t)((float)map->bucket_count * (i_max_load_factor)); } -STC_DEF _cx_self _cx_memb(_with_capacity)(const intptr_t cap) { - _cx_self map = {0}; - _cx_memb(_reserve)(&map, cap); +STC_DEF _cx_Self _cx_MEMB(_with_capacity)(const intptr_t cap) { + _cx_Self map = {0}; + _cx_MEMB(_reserve)(&map, cap); return map; } -STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_wipe_)(_cx_Self* self) { if (self->size == 0) return; _cx_value* d = self->data, *_end = d + self->bucket_count; chash_slot* s = self->slot; for (; d != _end; ++d) if ((s++)->hashx) - _cx_memb(_value_drop)(d); + _cx_MEMB(_value_drop)(d); } -STC_DEF void _cx_memb(_drop)(_cx_self* self) { - _cx_memb(_wipe_)(self); +STC_DEF void _cx_MEMB(_drop)(_cx_Self* self) { + _cx_MEMB(_wipe_)(self); i_free(self->slot); i_free(self->data); } -STC_DEF void _cx_memb(_clear)(_cx_self* self) { - _cx_memb(_wipe_)(self); +STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) { + _cx_MEMB(_wipe_)(self); self->size = 0; c_memset(self->slot, 0, c_sizeof(chash_slot)*self->bucket_count); } #ifndef _i_isset STC_DEF _cx_result - _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); + _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); _cx_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped; if (_res.inserted) _res.ref->first = _key; @@ -328,8 +328,8 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) { #if !defined i_no_emplace STC_DEF _cx_result - _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped) { - _cx_result _res = _cx_memb(_insert_entry_)(self, rkey); + _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey); if (_res.inserted) _res.ref->first = i_keyfrom(rkey); else { @@ -343,7 +343,7 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) { #endif // !_i_isset STC_DEF chash_bucket -_cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { +_cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); intptr_t _cap = self->bucket_count; chash_bucket b = {fastrange_2(_hash, _cap), (uint8_t)(_hash | 0x80)}; @@ -362,13 +362,13 @@ _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { } STC_DEF _cx_result -_cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { _cx_result res = {NULL}; if (self->size >= (intptr_t)((float)self->bucket_count * (i_max_load_factor))) - if (!_cx_memb(_reserve)(self, (intptr_t)(self->size*3/2 + 2))) + if (!_cx_MEMB(_reserve)(self, (intptr_t)(self->size*3/2 + 2))) return res; - chash_bucket b = _cx_memb(_bucket_)(self, &rkey); + chash_bucket b = _cx_MEMB(_bucket_)(self, &rkey); res.ref = &self->data[b.idx]; if (!b.found) { self->slot[b.idx].hashx = b.hashx; @@ -379,8 +379,8 @@ _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { } #if !defined i_no_clone -STC_DEF _cx_self -_cx_memb(_clone)(_cx_self m) { +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self m) { if (m.data) { _cx_value *d = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count), *_dst = d, *_end = m.data + m.bucket_count; @@ -391,7 +391,7 @@ _cx_memb(_clone)(_cx_self m) { else for (; m.data != _end; ++m.data, ++m.slot, ++_dst) if (m.slot->hashx) - *_dst = _cx_memb(_value_clone)(*m.data); + *_dst = _cx_MEMB(_value_clone)(*m.data); m.data = d, m.slot = s; } return m; @@ -399,13 +399,13 @@ _cx_memb(_clone)(_cx_self m) { #endif STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) { const intptr_t _oldbucks = self->bucket_count; if (_newcap != self->size && _newcap <= _oldbucks) return true; intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4; _newbucks = cnextpow2(_newbucks); - _cx_self m = { + _cx_Self m = { (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), (chash_slot *)i_calloc(_newbucks + 1, sizeof(chash_slot)), self->size, _newbucks @@ -417,11 +417,11 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { const chash_slot* s = self->slot; for (intptr_t i = 0; i < _oldbucks; ++i, ++d) if ((s++)->hashx) { _cx_keyraw r = i_keyto(_i_keyref(d)); - chash_bucket b = _cx_memb(_bucket_)(&m, &r); + chash_bucket b = _cx_MEMB(_bucket_)(&m, &r); m.slot[b.idx].hashx = b.hashx; m.data[b.idx] = *d; // move } - c_swap(_cx_self, self, &m); + c_swap(_cx_Self, self, &m); } i_free(m.slot); i_free(m.data); @@ -429,12 +429,12 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t _newcap) { } STC_DEF void -_cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { +_cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* _val) { _cx_value* d = self->data; chash_slot* s = self->slot; intptr_t i = _val - d, j = i, k; const intptr_t _cap = self->bucket_count; - _cx_memb(_value_drop)(_val); + _cx_MEMB(_value_drop)(_val); for (;;) { // delete without leaving tombstone if (++j == _cap) j = 0; if (! s[j].hashx) diff --git a/include/stc/cpque.h b/include/stc/cpque.h index b66c7735..cfe027cc 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -31,88 +31,88 @@ #define _i_prefix cpque_ #include "priv/template.h" #ifndef i_is_forward - _cx_deftypes(_c_cpque_types, _cx_self, i_key); + _cx_DEFTYPES(_c_cpque_types, _cx_Self, i_key); #endif typedef i_keyraw _cx_raw; -STC_API void _cx_memb(_make_heap)(_cx_self* self); -STC_API void _cx_memb(_erase_at)(_cx_self* self, intptr_t idx); -STC_API _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value value); +STC_API void _cx_MEMB(_make_heap)(_cx_Self* self); +STC_API void _cx_MEMB(_erase_at)(_cx_Self* self, intptr_t idx); +STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value value); -STC_INLINE _cx_self _cx_memb(_init)(void) - { return c_LITERAL(_cx_self){NULL}; } +STC_INLINE _cx_Self _cx_MEMB(_init)(void) + { return c_LITERAL(_cx_Self){NULL}; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } -STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { +STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) { if (cap != self->_len && cap <= self->_cap) return true; _cx_value *d = (_cx_value *)i_realloc(self->data, cap*c_sizeof *d); return d ? (self->data = d, self->_cap = cap, true) : false; } -STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) - { _cx_memb(_reserve)(self, self->_len); } +STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self) + { _cx_MEMB(_reserve)(self, self->_len); } -STC_INLINE _cx_self _cx_memb(_with_capacity)(const intptr_t cap) { - _cx_self out = {NULL}; _cx_memb(_reserve)(&out, cap); +STC_INLINE _cx_Self _cx_MEMB(_with_capacity)(const intptr_t cap) { + _cx_Self out = {NULL}; _cx_MEMB(_reserve)(&out, cap); return out; } -STC_INLINE _cx_self _cx_memb(_with_size)(const intptr_t size, i_key null) { - _cx_self out = {NULL}; _cx_memb(_reserve)(&out, size); +STC_INLINE _cx_Self _cx_MEMB(_with_size)(const intptr_t size, i_key null) { + _cx_Self out = {NULL}; _cx_MEMB(_reserve)(&out, size); while (out._len < size) out.data[out._len++] = null; return out; } -STC_INLINE void _cx_memb(_clear)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) { intptr_t i = self->_len; self->_len = 0; while (i--) { i_keydrop((self->data + i)); } } -STC_INLINE void _cx_memb(_drop)(_cx_self* self) - { _cx_memb(_clear)(self); i_free(self->data); } +STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) + { _cx_MEMB(_clear)(self); i_free(self->data); } -STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* q) +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* q) { return q->_len; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* q) +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* q) { return !q->_len; } -STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* q) +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* q) { return q->_cap; } -STC_INLINE const _cx_value* _cx_memb(_top)(const _cx_self* self) +STC_INLINE const _cx_value* _cx_MEMB(_top)(const _cx_Self* self) { return &self->data[0]; } -STC_INLINE void _cx_memb(_pop)(_cx_self* self) - { assert(!_cx_memb(_empty)(self)); _cx_memb(_erase_at)(self, 0); } +STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) + { assert(!_cx_MEMB(_empty)(self)); _cx_MEMB(_erase_at)(self, 0); } #if !defined i_no_clone -STC_API _cx_self _cx_memb(_clone)(_cx_self q); +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self q); -STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) { +STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { if (self->data == other->data) return; - _cx_memb(_drop)(self); - *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); } -STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val) +STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val) { return i_keyclone(val); } #endif // !i_no_clone #if !defined i_no_emplace -STC_INLINE void _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) - { _cx_memb(_push)(self, i_keyfrom(raw)); } +STC_INLINE void _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) + { _cx_MEMB(_push)(self, i_keyfrom(raw)); } #endif // !i_no_emplace /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) STC_DEF void -_cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) { +_cx_MEMB(_sift_down_)(_cx_Self* self, const intptr_t idx, const intptr_t n) { _cx_value t, *arr = self->data - 1; for (intptr_t r = idx, c = idx*2; c <= n; c *= 2) { c += i_less((&arr[c]), (&arr[c + (c < n)])); @@ -122,15 +122,15 @@ _cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) { } STC_DEF void -_cx_memb(_make_heap)(_cx_self* self) { +_cx_MEMB(_make_heap)(_cx_Self* self) { intptr_t n = self->_len; for (intptr_t k = n/2; k != 0; --k) - _cx_memb(_sift_down_)(self, k, n); + _cx_MEMB(_sift_down_)(self, k, n); } #if !defined i_no_clone -STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) { - _cx_self out = _cx_memb(_with_capacity)(q._len); +STC_DEF _cx_Self _cx_MEMB(_clone)(_cx_Self q) { + _cx_Self out = _cx_MEMB(_with_capacity)(q._len); for (; out._len < out._cap; ++q.data) out.data[out._len++] = i_keyclone((*q.data)); return out; @@ -138,17 +138,17 @@ STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) { #endif STC_DEF void -_cx_memb(_erase_at)(_cx_self* self, const intptr_t idx) { +_cx_MEMB(_erase_at)(_cx_Self* self, const intptr_t idx) { i_keydrop((self->data + idx)); const intptr_t n = --self->_len; self->data[idx] = self->data[n]; - _cx_memb(_sift_down_)(self, idx + 1, n); + _cx_MEMB(_sift_down_)(self, idx + 1, n); } STC_DEF _cx_value* -_cx_memb(_push)(_cx_self* self, _cx_value value) { +_cx_MEMB(_push)(_cx_Self* self, _cx_value value) { if (self->_len == self->_cap) - _cx_memb(_reserve)(self, self->_len*3/2 + 4); + _cx_MEMB(_reserve)(self, self->_len*3/2 + 4); _cx_value *arr = self->data - 1; /* base 1 */ intptr_t c = ++self->_len; for (; c > 1 && (i_less((&arr[c/2]), (&value))); c /= 2) diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 2f709172..6eee712b 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -35,104 +35,104 @@ #include "priv/template.h" #ifndef i_is_forward -_cx_deftypes(_c_cdeq_types, _cx_self, i_key); +_cx_DEFTYPES(_c_cdeq_types, _cx_Self, i_key); #endif typedef i_keyraw _cx_raw; -STC_API _cx_self _cx_memb(_with_capacity)(const intptr_t n); -STC_API bool _cx_memb(_reserve)(_cx_self* self, const intptr_t n); -STC_API void _cx_memb(_clear)(_cx_self* self); -STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value); // push_back -STC_API void _cx_memb(_shrink_to_fit)(_cx_self *self); -STC_API _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t n); +STC_API _cx_Self _cx_MEMB(_with_capacity)(const intptr_t n); +STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n); +STC_API void _cx_MEMB(_clear)(_cx_Self* self); +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); // push_back +STC_API void _cx_MEMB(_shrink_to_fit)(_cx_Self *self); +STC_API _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n); #define _cdeq_toidx(self, pos) (((pos) - (self)->start) & (self)->capmask) #define _cdeq_topos(self, idx) (((self)->start + (idx)) & (self)->capmask) -STC_INLINE _cx_self _cx_memb(_init)(void) - { _cx_self cx = {0}; return cx; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } -STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); } +STC_INLINE _cx_Self _cx_MEMB(_init)(void) + { _cx_Self cx = {0}; return cx; } +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } #if !defined i_no_emplace -STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push)(self, i_keyfrom(raw)); } #endif #if defined _i_has_cmp || defined _i_has_eq -STC_API bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other); +STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other); #endif #if !defined i_no_clone -STC_API _cx_self _cx_memb(_clone)(_cx_self cx); -STC_INLINE i_key _cx_memb(_value_clone)(i_key val) +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); +STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val) { return i_keyclone(val); } #endif // !i_no_clone -STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) { return _cdeq_toidx(self, self->end); } -STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) { return self->capmask; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return self->start == self->end; } -STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* pval) +STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval) { return i_keyto(pval); } -STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) +STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return self->data + self->start; } -STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) +STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return self->data + ((self->end - 1) & self->capmask); } -STC_INLINE void _cx_memb(_pop)(_cx_self* self) { // pop_front - assert(!_cx_memb(_empty)(self)); +STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { // pop_front + assert(!_cx_MEMB(_empty)(self)); i_keydrop((self->data + self->start)); self->start = (self->start + 1) & self->capmask; } -STC_INLINE _cx_value _cx_memb(_pull)(_cx_self* self) { // move front out of queue - assert(!_cx_memb(_empty)(self)); +STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { // move front out of queue + assert(!_cx_MEMB(_empty)(self)); intptr_t s = self->start; self->start = (s + 1) & self->capmask; return self->data[s]; } -STC_INLINE void _cx_memb(_copy)(_cx_self* self, const _cx_self* other) { +STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { if (self->data == other->data) return; - _cx_memb(_drop)(self); - *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); } -STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { +STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { return c_LITERAL(_cx_iter){ - _cx_memb(_empty)(self) ? NULL : self->data + self->start, + _cx_MEMB(_empty)(self) ? NULL : self->data + self->start, self->start, self }; } -STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) { return c_LITERAL(_cx_iter){.pos=self->end, ._s=self}; } -STC_INLINE void _cx_memb(_next)(_cx_iter* it) { +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; } else { it->ref -= it->pos; it->pos = 0; } if (it->pos == it->_s->end) it->ref = NULL; } -STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it) +STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) { return _cdeq_toidx(self, it.pos); } -STC_INLINE void _cx_memb(_adjust_end_)(_cx_self* self, intptr_t n) +STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) { self->end = (self->end + n) & self->capmask; } /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) -STC_DEF _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t n) { - intptr_t len = _cx_memb(_size)(it._s); +STC_DEF _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n) { + intptr_t len = _cx_MEMB(_size)(it._s); intptr_t pos = it.pos, idx = _cdeq_toidx(it._s, pos); it.pos = (pos + n) & it._s->capmask; it.ref += it.pos - pos; @@ -141,27 +141,27 @@ STC_DEF _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t n) { } STC_DEF void -_cx_memb(_clear)(_cx_self* self) { - c_foreach (i, _cx_self, *self) +_cx_MEMB(_clear)(_cx_Self* self) { + c_foreach (i, _cx_Self, *self) { i_keydrop(i.ref); } self->start = 0, self->end = 0; } STC_DEF void -_cx_memb(_drop)(_cx_self* self) { - _cx_memb(_clear)(self); +_cx_MEMB(_drop)(_cx_Self* self) { + _cx_MEMB(_clear)(self); i_free(self->data); } -STC_DEF _cx_self -_cx_memb(_with_capacity)(const intptr_t n) { - _cx_self cx = {0}; - _cx_memb(_reserve)(&cx, n); +STC_DEF _cx_Self +_cx_MEMB(_with_capacity)(const intptr_t n) { + _cx_Self cx = {0}; + _cx_MEMB(_reserve)(&cx, n); return cx; } STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const intptr_t n) { +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n) { if (n <= self->capmask) return true; intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1); @@ -184,10 +184,10 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t n) { } STC_DEF _cx_value* -_cx_memb(_push)(_cx_self* self, i_key value) { // push_back +_cx_MEMB(_push)(_cx_Self* self, i_key value) { // push_back intptr_t end = (self->end + 1) & self->capmask; if (end == self->start) { // full - _cx_memb(_reserve)(self, self->capmask + 3); // => 2x expand + _cx_MEMB(_reserve)(self, self->capmask + 3); // => 2x expand end = (self->end + 1) & self->capmask; } _cx_value *v = self->data + self->end; @@ -197,14 +197,14 @@ _cx_memb(_push)(_cx_self* self, i_key value) { // push_back } STC_DEF void -_cx_memb(_shrink_to_fit)(_cx_self *self) { - intptr_t sz = _cx_memb(_size)(self), j = 0; +_cx_MEMB(_shrink_to_fit)(_cx_Self *self) { + intptr_t sz = _cx_MEMB(_size)(self), j = 0; if (sz > self->capmask/2) return; - _cx_self out = _cx_memb(_with_capacity)(sz); + _cx_Self out = _cx_MEMB(_with_capacity)(sz); if (!out.data) return; - c_foreach (i, _cx_self, *self) + c_foreach (i, _cx_Self, *self) out.data[j++] = *i.ref; out.end = sz; i_free(self->data); @@ -212,12 +212,12 @@ _cx_memb(_shrink_to_fit)(_cx_self *self) { } #if !defined i_no_clone -STC_DEF _cx_self -_cx_memb(_clone)(_cx_self cx) { - intptr_t sz = _cx_memb(_size)(&cx), j = 0; - _cx_self out = _cx_memb(_with_capacity)(sz); +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self cx) { + intptr_t sz = _cx_MEMB(_size)(&cx), j = 0; + _cx_Self out = _cx_MEMB(_with_capacity)(sz); if (out.data) - c_foreach (i, _cx_self, cx) + c_foreach (i, _cx_Self, cx) out.data[j++] = i_keyclone((*i.ref)); out.end = sz; return out; @@ -226,10 +226,10 @@ _cx_memb(_clone)(_cx_self cx) { #if defined _i_has_cmp || defined _i_has_eq STC_DEF bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; - for (_cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other); - i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; + for (_cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other); + i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) { const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); if (!(i_eq((&_rx), (&_ry)))) return false; diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 28598f0a..f4d33a4d 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -73,7 +73,7 @@ int main(void) { #endif #include "priv/template.h" #ifndef i_is_forward - _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); + _cx_DEFTYPES(_c_aatree_types, _cx_Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); #endif _i_MAP_ONLY( struct _cx_value { @@ -87,133 +87,133 @@ struct _cx_node { }; typedef i_keyraw _cx_keyraw; -typedef i_valraw _cx_memb(_rmapped); +typedef i_valraw _cx_MEMB(_rmapped); typedef _i_SET_ONLY( i_keyraw ) _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } ) _cx_raw; #if !defined i_no_emplace -STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)); +STC_API _cx_result _cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)); #endif // !i_no_emplace #if !defined i_no_clone -STC_API _cx_self _cx_memb(_clone)(_cx_self tree); +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self tree); #endif // !i_no_clone -STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t cap); -STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out); -STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey); -STC_API _cx_value* _cx_memb(_front)(const _cx_self* self); -STC_API _cx_value* _cx_memb(_back)(const _cx_self* self); -STC_API int _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey); -STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it); -STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2); -STC_API _cx_iter _cx_memb(_begin)(const _cx_self* self); -STC_API void _cx_memb(_next)(_cx_iter* it); - -STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self tree = {0}; return tree; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* cx) { return cx->size == 0; } -STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* cx) { return cx->size; } -STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* cx) { return cx->cap; } -STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) - { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; } -STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) - { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; } -STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey) - { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); } -STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey) - { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); } - -STC_INLINE _cx_self -_cx_memb(_with_capacity)(const intptr_t cap) { - _cx_self tree = _cx_memb(_init)(); - _cx_memb(_reserve)(&tree, cap); +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t cap); +STC_API _cx_value* _cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out); +STC_API _cx_iter _cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_keyraw rkey); +STC_API _cx_value* _cx_MEMB(_front)(const _cx_Self* self); +STC_API _cx_value* _cx_MEMB(_back)(const _cx_Self* self); +STC_API int _cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey); +STC_API _cx_iter _cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it); +STC_API _cx_iter _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2); +STC_API _cx_iter _cx_MEMB(_begin)(const _cx_Self* self); +STC_API void _cx_MEMB(_next)(_cx_iter* it); + +STC_INLINE _cx_Self _cx_MEMB(_init)(void) { _cx_Self tree = {0}; return tree; } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* cx) { return cx->size == 0; } +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* cx) { return cx->size; } +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* cx) { return cx->cap; } +STC_INLINE _cx_iter _cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; _cx_MEMB(_find_it)(self, rkey, &it); return it; } +STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it) != NULL; } +STC_INLINE const _cx_value* _cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it); } +STC_INLINE _cx_value* _cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it); } + +STC_INLINE _cx_Self +_cx_MEMB(_with_capacity)(const intptr_t cap) { + _cx_Self tree = _cx_MEMB(_init)(); + _cx_MEMB(_reserve)(&tree, cap); return tree; } STC_INLINE void -_cx_memb(_clear)(_cx_self* self) - { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); } +_cx_MEMB(_clear)(_cx_Self* self) + { _cx_MEMB(_drop)(self); *self = _cx_MEMB(_init)(); } STC_INLINE _cx_raw -_cx_memb(_value_toraw)(const _cx_value* val) { +_cx_MEMB(_value_toraw)(const _cx_value* val) { return _i_SET_ONLY( i_keyto(val) ) _i_MAP_ONLY( c_LITERAL(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} ); } STC_INLINE void -_cx_memb(_value_drop)(_cx_value* val) { +_cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(_i_keyref(val)); _i_MAP_ONLY( i_valdrop((&val->second)); ) } #if !defined i_no_clone STC_INLINE _cx_value -_cx_memb(_value_clone)(_cx_value _val) { +_cx_MEMB(_value_clone)(_cx_value _val) { *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val))); _i_MAP_ONLY( _val.second = i_valclone(_val.second); ) return _val; } STC_INLINE void -_cx_memb(_copy)(_cx_self *self, const _cx_self* other) { +_cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { if (self->nodes == other->nodes) return; - _cx_memb(_drop)(self); - *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); } STC_INLINE void -_cx_memb(_shrink_to_fit)(_cx_self *self) { - _cx_self tmp = _cx_memb(_clone)(*self); - _cx_memb(_drop)(self); *self = tmp; +_cx_MEMB(_shrink_to_fit)(_cx_Self *self) { + _cx_Self tmp = _cx_MEMB(_clone)(*self); + _cx_MEMB(_drop)(self); *self = tmp; } #endif // !i_no_clone #ifndef _i_isset - STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped); + STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped); #if !defined i_no_emplace - STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped); + STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped); #endif STC_INLINE const _cx_mapped* - _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey) - { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; } + _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; } STC_INLINE _cx_mapped* - _cx_memb(_at_mut)(_cx_self* self, _cx_keyraw rkey) - { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; } + _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; } #endif // !_i_isset STC_INLINE _cx_iter -_cx_memb(_end)(const _cx_self* self) { +_cx_MEMB(_end)(const _cx_Self* self) { (void)self; _cx_iter it; it.ref = NULL, it._top = 0, it._tn = 0; return it; } STC_INLINE _cx_iter -_cx_memb(_advance)(_cx_iter it, size_t n) { +_cx_MEMB(_advance)(_cx_iter it, size_t n) { while (n-- && it.ref) - _cx_memb(_next)(&it); + _cx_MEMB(_next)(&it); return it; } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; - _cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other); - for (; i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) { +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; + _cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other); + for (; i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) { const _cx_keyraw _rx = i_keyto(_i_keyref(i.ref)), _ry = i_keyto(_i_keyref(j.ref)); if (!(i_eq((&_rx), (&_ry)))) return false; } return true; } -static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey); +static _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey); STC_INLINE _cx_result -_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); +_cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); if (_res.inserted) { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} else @@ -222,38 +222,38 @@ _cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { } STC_INLINE _cx_value* -_cx_memb(_push)(_cx_self* self, _cx_value _val) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); +_cx_MEMB(_push)(_cx_Self* self, _cx_value _val) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); if (_res.inserted) *_res.ref = _val; else - _cx_memb(_value_drop)(&_val); + _cx_MEMB(_value_drop)(&_val); return _res.ref; } STC_INLINE void -_cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) { +_cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) { while (n--) #if defined _i_isset && defined i_no_emplace - _cx_memb(_insert)(self, *raw++); + _cx_MEMB(_insert)(self, *raw++); #elif defined _i_isset - _cx_memb(_emplace)(self, *raw++); + _cx_MEMB(_emplace)(self, *raw++); #elif defined i_no_emplace - _cx_memb(_insert_or_assign)(self, raw->first, raw->second), ++raw; + _cx_MEMB(_insert_or_assign)(self, raw->first, raw->second), ++raw; #else - _cx_memb(_emplace_or_assign)(self, raw->first, raw->second), ++raw; + _cx_MEMB(_emplace_or_assign)(self, raw->first, raw->second), ++raw; #endif } -STC_INLINE _cx_self -_cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } +STC_INLINE _cx_Self +_cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) STC_DEF void -_cx_memb(_next)(_cx_iter *it) { +_cx_MEMB(_next)(_cx_iter *it) { int32_t tn = it->_tn; if (it->_top || tn) { while (tn) { @@ -268,18 +268,18 @@ _cx_memb(_next)(_cx_iter *it) { } STC_DEF _cx_iter -_cx_memb(_begin)(const _cx_self* self) { +_cx_MEMB(_begin)(const _cx_Self* self) { _cx_iter it; it.ref = NULL; it._d = self->nodes, it._top = 0; it._tn = self->root; if (it._tn) - _cx_memb(_next)(&it); + _cx_MEMB(_next)(&it); return it; } STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) { if (cap <= self->cap) return false; _cx_node* nodes = (_cx_node*)i_realloc(self->nodes, (cap + 1)*c_sizeof(_cx_node)); @@ -292,7 +292,7 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { } STC_DEF _cx_value* -_cx_memb(_front)(const _cx_self* self) { +_cx_MEMB(_front)(const _cx_Self* self) { _cx_node *d = self->nodes; int32_t tn = self->root; while (d[tn].link[0]) @@ -301,7 +301,7 @@ _cx_memb(_front)(const _cx_self* self) { } STC_DEF _cx_value* -_cx_memb(_back)(const _cx_self* self) { +_cx_MEMB(_back)(const _cx_Self* self) { _cx_node *d = self->nodes; int32_t tn = self->root; while (d[tn].link[1]) @@ -310,14 +310,14 @@ _cx_memb(_back)(const _cx_self* self) { } static int32_t -_cx_memb(_new_node_)(_cx_self* self, int level) { +_cx_MEMB(_new_node_)(_cx_Self* self, int level) { int32_t tn; if (self->disp) { tn = self->disp; self->disp = self->nodes[tn].link[1]; } else { if (self->head == self->cap) - if (!_cx_memb(_reserve)(self, self->head*3/2 + 4)) + if (!_cx_MEMB(_reserve)(self, self->head*3/2 + 4)) return 0; tn = ++self->head; /* start with 1, 0 is nullnode. */ } @@ -328,8 +328,8 @@ _cx_memb(_new_node_)(_cx_self* self, int level) { #ifndef _i_isset STC_DEF _cx_result - _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); + _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); _cx_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped; if (_res.inserted) _res.ref->first = _key; @@ -341,8 +341,8 @@ _cx_memb(_new_node_)(_cx_self* self, int level) { #if !defined i_no_emplace STC_DEF _cx_result - _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped) { - _cx_result _res = _cx_memb(_insert_entry_)(self, rkey); + _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey); if (_res.inserted) _res.ref->first = i_keyfrom(rkey); else { @@ -356,7 +356,7 @@ _cx_memb(_new_node_)(_cx_self* self, int level) { #endif // !_i_isset STC_DEF _cx_value* -_cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out) { +_cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out) { int32_t tn = self->root; _cx_node *d = out->_d = self->nodes; out->_top = 0; @@ -373,9 +373,9 @@ _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out) { } STC_DEF _cx_iter -_cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_keyraw rkey) { _cx_iter it; - _cx_memb(_find_it)(self, rkey, &it); + _cx_MEMB(_find_it)(self, rkey, &it); if (!it.ref && it._top) { int32_t tn = it._st[--it._top]; it._tn = it._d[tn].link[1]; @@ -385,7 +385,7 @@ _cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey) { } STC_DEF int32_t -_cx_memb(_skew_)(_cx_node *d, int32_t tn) { +_cx_MEMB(_skew_)(_cx_node *d, int32_t tn) { if (tn && d[d[tn].link[0]].level == d[tn].level) { int32_t tmp = d[tn].link[0]; d[tn].link[0] = d[tmp].link[1]; @@ -396,7 +396,7 @@ _cx_memb(_skew_)(_cx_node *d, int32_t tn) { } STC_DEF int32_t -_cx_memb(_split_)(_cx_node *d, int32_t tn) { +_cx_MEMB(_split_)(_cx_node *d, int32_t tn) { if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) { int32_t tmp = d[tn].link[1]; d[tn].link[1] = d[tmp].link[0]; @@ -408,7 +408,7 @@ _cx_memb(_split_)(_cx_node *d, int32_t tn) { } static int32_t -_cx_memb(_insert_entry_i_)(_cx_self* self, int32_t tn, const _cx_keyraw* rkey, _cx_result* _res) { +_cx_MEMB(_insert_entry_i_)(_cx_Self* self, int32_t tn, const _cx_keyraw* rkey, _cx_result* _res) { int32_t up[64], tx = tn; _cx_node* d = self->nodes; int c, top = 0, dir = 0; @@ -420,7 +420,7 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, int32_t tn, const _cx_keyraw* rkey, _ dir = (c < 0); tx = d[tx].link[dir]; } - if ((tx = _cx_memb(_new_node_)(self, 1)) == 0) + if ((tx = _cx_MEMB(_new_node_)(self, 1)) == 0) return 0; d = self->nodes; _res->ref = &d[tx].value; @@ -431,8 +431,8 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, int32_t tn, const _cx_keyraw* rkey, _ while (top--) { if (top) dir = (d[up[top - 1]].link[1] == up[top]); - up[top] = _cx_memb(_skew_)(d, up[top]); - up[top] = _cx_memb(_split_)(d, up[top]); + up[top] = _cx_MEMB(_skew_)(d, up[top]); + up[top] = _cx_MEMB(_split_)(d, up[top]); if (top) d[up[top - 1]].link[dir] = up[top]; } @@ -440,33 +440,33 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, int32_t tn, const _cx_keyraw* rkey, _ } static _cx_result -_cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { _cx_result res = {NULL}; - int32_t tn = _cx_memb(_insert_entry_i_)(self, self->root, &rkey, &res); + int32_t tn = _cx_MEMB(_insert_entry_i_)(self, self->root, &rkey, &res); self->root = tn; self->size += res.inserted; return res; } static int32_t -_cx_memb(_erase_r_)(_cx_self *self, int32_t tn, const _cx_keyraw* rkey, int *erased) { +_cx_MEMB(_erase_r_)(_cx_Self *self, int32_t tn, const _cx_keyraw* rkey, int *erased) { _cx_node *d = self->nodes; if (tn == 0) return 0; _cx_keyraw raw = i_keyto(_i_keyref(&d[tn].value)); int32_t tx; int c = i_cmp((&raw), rkey); if (c != 0) - d[tn].link[c < 0] = _cx_memb(_erase_r_)(self, d[tn].link[c < 0], rkey, erased); + d[tn].link[c < 0] = _cx_MEMB(_erase_r_)(self, d[tn].link[c < 0], rkey, erased); else { if (!(*erased)++) - _cx_memb(_value_drop)(&d[tn].value); + _cx_MEMB(_value_drop)(&d[tn].value); if (d[tn].link[0] && d[tn].link[1]) { tx = d[tn].link[0]; while (d[tx].link[1]) tx = d[tx].link[1]; d[tn].value = d[tx].value; /* move */ raw = i_keyto(_i_keyref(&d[tn].value)); - d[tn].link[0] = _cx_memb(_erase_r_)(self, d[tn].link[0], &raw, erased); + d[tn].link[0] = _cx_MEMB(_erase_r_)(self, d[tn].link[0], &raw, erased); } else { /* unlink node */ tx = tn; tn = d[tn].link[ d[tn].link[0] == 0 ]; @@ -479,19 +479,19 @@ _cx_memb(_erase_r_)(_cx_self *self, int32_t tn, const _cx_keyraw* rkey, int *era if (d[d[tn].link[0]].level < d[tn].level - 1 || d[tx].level < d[tn].level - 1) { if (d[tx].level > --d[tn].level) d[tx].level = d[tn].level; - tn = _cx_memb(_skew_)(d, tn); - tx = d[tn].link[1] = _cx_memb(_skew_)(d, d[tn].link[1]); - d[tx].link[1] = _cx_memb(_skew_)(d, d[tx].link[1]); - tn = _cx_memb(_split_)(d, tn); - d[tn].link[1] = _cx_memb(_split_)(d, d[tn].link[1]); + tn = _cx_MEMB(_skew_)(d, tn); + tx = d[tn].link[1] = _cx_MEMB(_skew_)(d, d[tn].link[1]); + d[tx].link[1] = _cx_MEMB(_skew_)(d, d[tx].link[1]); + tn = _cx_MEMB(_split_)(d, tn); + d[tn].link[1] = _cx_MEMB(_split_)(d, d[tn].link[1]); } return tn; } STC_DEF int -_cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) { int erased = 0; - int32_t root = _cx_memb(_erase_r_)(self, self->root, &rkey, &erased); + int32_t root = _cx_MEMB(_erase_r_)(self, self->root, &rkey, &erased); if (!erased) return 0; self->root = root; @@ -500,23 +500,23 @@ _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { } STC_DEF _cx_iter -_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { +_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) { _cx_keyraw raw = i_keyto(_i_keyref(it.ref)); - _cx_memb(_next)(&it); + _cx_MEMB(_next)(&it); if (it.ref) { _cx_keyraw nxt = i_keyto(_i_keyref(it.ref)); - _cx_memb(_erase)(self, raw); - _cx_memb(_find_it)(self, nxt, &it); + _cx_MEMB(_erase)(self, raw); + _cx_MEMB(_find_it)(self, nxt, &it); } else - _cx_memb(_erase)(self, raw); + _cx_MEMB(_erase)(self, raw); return it; } STC_DEF _cx_iter -_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { +_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) { if (!it2.ref) { while (it1.ref) - it1 = _cx_memb(_erase_at)(self, it1); + it1 = _cx_MEMB(_erase_at)(self, it1); return it1; } _cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref); @@ -524,30 +524,30 @@ _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { for (;;) { if (memcmp(&k1, &k2, sizeof k1) == 0) return it1; - _cx_memb(_next)(&it1); + _cx_MEMB(_next)(&it1); k1 = *_i_keyref(it1.ref); - _cx_memb(_erase)(self, r1); + _cx_MEMB(_erase)(self, r1); r1 = i_keyto((&k1)); - _cx_memb(_find_it)(self, r1, &it1); + _cx_MEMB(_find_it)(self, r1, &it1); } } #if !defined i_no_clone static int32_t -_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, int32_t sn) { +_cx_MEMB(_clone_r_)(_cx_Self* self, _cx_node* src, int32_t sn) { if (sn == 0) return 0; - int32_t tx, tn = _cx_memb(_new_node_)(self, src[sn].level); - self->nodes[tn].value = _cx_memb(_value_clone)(src[sn].value); - tx = _cx_memb(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx; - tx = _cx_memb(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx; + int32_t tx, tn = _cx_MEMB(_new_node_)(self, src[sn].level); + self->nodes[tn].value = _cx_MEMB(_value_clone)(src[sn].value); + tx = _cx_MEMB(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx; + tx = _cx_MEMB(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx; return tn; } -STC_DEF _cx_self -_cx_memb(_clone)(_cx_self tree) { - _cx_self clone = _cx_memb(_with_capacity)(tree.size); - int32_t root = _cx_memb(_clone_r_)(&clone, tree.nodes, tree.root); +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self tree) { + _cx_Self clone = _cx_MEMB(_with_capacity)(tree.size); + int32_t root = _cx_MEMB(_clone_r_)(&clone, tree.nodes, tree.root); clone.root = root; clone.size = tree.size; return clone; @@ -556,8 +556,8 @@ _cx_memb(_clone)(_cx_self tree) { #if !defined i_no_emplace STC_DEF _cx_result -_cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { - _cx_result res = _cx_memb(_insert_entry_)(self, rkey); +_cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { + _cx_result res = _cx_MEMB(_insert_entry_)(self, rkey); if (res.inserted) { *_i_keyref(res.ref) = i_keyfrom(rkey); _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);) @@ -567,18 +567,18 @@ _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe #endif // i_no_emplace static void -_cx_memb(_drop_r_)(_cx_node* d, int32_t tn) { +_cx_MEMB(_drop_r_)(_cx_node* d, int32_t tn) { if (tn) { - _cx_memb(_drop_r_)(d, d[tn].link[0]); - _cx_memb(_drop_r_)(d, d[tn].link[1]); - _cx_memb(_value_drop)(&d[tn].value); + _cx_MEMB(_drop_r_)(d, d[tn].link[0]); + _cx_MEMB(_drop_r_)(d, d[tn].link[1]); + _cx_MEMB(_value_drop)(&d[tn].value); } } STC_DEF void -_cx_memb(_drop)(_cx_self* self) { +_cx_MEMB(_drop)(_cx_Self* self) { if (self->cap) { - _cx_memb(_drop_r_)(self->nodes, self->root); + _cx_MEMB(_drop_r_)(self->nodes, self->root); i_free(self->nodes); } } diff --git a/include/stc/cstack.h b/include/stc/cstack.h index 5f0ffe2b..24ec2d5f 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -35,64 +35,64 @@ #ifndef i_is_forward #ifdef i_capacity #define i_no_clone - _cx_deftypes(_c_cstack_fixed, _cx_self, i_key, i_capacity); + _cx_DEFTYPES(_c_cstack_fixed, _cx_Self, i_key, i_capacity); #else - _cx_deftypes(_c_cstack_types, _cx_self, i_key); + _cx_DEFTYPES(_c_cstack_types, _cx_Self, i_key); #endif #endif typedef i_keyraw _cx_raw; #ifdef i_capacity -STC_INLINE void _cx_memb(_init)(_cx_self* self) +STC_INLINE void _cx_MEMB(_init)(_cx_Self* self) { self->_len = 0; } #else -STC_INLINE _cx_self _cx_memb(_init)(void) { - _cx_self out = {0}; +STC_INLINE _cx_Self _cx_MEMB(_init)(void) { + _cx_Self out = {0}; return out; } -STC_INLINE _cx_self _cx_memb(_with_capacity)(intptr_t cap) { - _cx_self out = {(_cx_value *) i_malloc(cap*c_sizeof(i_key)), 0, cap}; +STC_INLINE _cx_Self _cx_MEMB(_with_capacity)(intptr_t cap) { + _cx_Self out = {(_cx_value *) i_malloc(cap*c_sizeof(i_key)), 0, cap}; return out; } -STC_INLINE _cx_self _cx_memb(_with_size)(intptr_t size, i_key null) { - _cx_self out = {(_cx_value *) i_malloc(size*c_sizeof null), size, size}; +STC_INLINE _cx_Self _cx_MEMB(_with_size)(intptr_t size, i_key null) { + _cx_Self out = {(_cx_value *) i_malloc(size*c_sizeof null), size, size}; while (size) out.data[--size] = null; return out; } #endif // i_capacity -STC_INLINE void _cx_memb(_clear)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) { _cx_value *p = self->data + self->_len; while (p-- != self->data) { i_keydrop(p); } self->_len = 0; } -STC_INLINE void _cx_memb(_drop)(_cx_self* self) { - _cx_memb(_clear)(self); +STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) { + _cx_MEMB(_clear)(self); #ifndef i_capacity i_free(self->data); #endif } -STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) { return self->_len; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return !self->_len; } -STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) { +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) { #ifndef i_capacity return self->_cap; #else return i_capacity; #endif } -STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } -STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) { +STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t n) { if (n < self->_len) return true; #ifndef i_capacity _cx_value *t = (_cx_value *)i_realloc(self->data, n*c_sizeof *t); @@ -101,100 +101,100 @@ STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) { return false; } -STC_INLINE _cx_value* _cx_memb(_append_uninit)(_cx_self *self, intptr_t n) { +STC_INLINE _cx_value* _cx_MEMB(_append_uninit)(_cx_Self *self, intptr_t n) { intptr_t len = self->_len; - if (!_cx_memb(_reserve)(self, len + n)) return NULL; + if (!_cx_MEMB(_reserve)(self, len + n)) return NULL; self->_len += n; return self->data + len; } -STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) - { _cx_memb(_reserve)(self, self->_len); } +STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self) + { _cx_MEMB(_reserve)(self, self->_len); } -STC_INLINE const _cx_value* _cx_memb(_top)(const _cx_self* self) +STC_INLINE const _cx_value* _cx_MEMB(_top)(const _cx_Self* self) { return &self->data[self->_len - 1]; } -STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) +STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return (_cx_value*) &self->data[self->_len - 1]; } -STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) +STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return (_cx_value*) &self->data[0]; } -STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value val) { - if (self->_len == _cx_memb(_capacity)(self)) - if (!_cx_memb(_reserve)(self, self->_len*3/2 + 4)) +STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value val) { + if (self->_len == _cx_MEMB(_capacity)(self)) + if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + 4)) return NULL; _cx_value* vp = self->data + self->_len++; *vp = val; return vp; } -STC_INLINE void _cx_memb(_pop)(_cx_self* self) +STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } -STC_INLINE _cx_value _cx_memb(_pull)(_cx_self* self) +STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { assert(self->_len); return self->data[--self->_len]; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } -STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, intptr_t idx) +STC_INLINE const _cx_value* _cx_MEMB(_at)(const _cx_Self* self, intptr_t idx) { assert(idx < self->_len); return self->data + idx; } -STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, intptr_t idx) +STC_INLINE _cx_value* _cx_MEMB(_at_mut)(_cx_Self* self, intptr_t idx) { assert(idx < self->_len); return self->data + idx; } #if !defined i_no_emplace -STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push)(self, i_keyfrom(raw)); } #endif // !i_no_emplace #if !defined i_no_clone -STC_INLINE _cx_self _cx_memb(_clone)(_cx_self v) { - _cx_self out = {(_cx_value *)i_malloc(v._len*c_sizeof(_cx_value)), v._len, v._len}; +STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self v) { + _cx_Self out = {(_cx_value *)i_malloc(v._len*c_sizeof(_cx_value)), v._len, v._len}; if (!out.data) out._cap = 0; else for (intptr_t i = 0; i < v._len; ++v.data) out.data[i++] = i_keyclone((*v.data)); return out; } -STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) { +STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { if (self->data == other->data) return; - _cx_memb(_drop)(self); - *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); } -STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val) +STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val) { return i_keyclone(val); } -STC_INLINE i_keyraw _cx_memb(_value_toraw)(const _cx_value* val) +STC_INLINE i_keyraw _cx_MEMB(_value_toraw)(const _cx_value* val) { return i_keyto(val); } #endif // !i_no_clone -STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { +STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { return c_LITERAL(_cx_iter){self->_len ? (_cx_value*)self->data : NULL, (_cx_value*)self->data + self->_len}; } -STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) { return c_LITERAL(_cx_iter){NULL, (_cx_value*)self->data + self->_len}; } -STC_INLINE void _cx_memb(_next)(_cx_iter* it) +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { if (++it->ref == it->end) it->ref = NULL; } -STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) +STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) { if ((it.ref += n) >= it.end) it.ref = NULL ; return it; } -STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it) +STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) { return (it.ref - self->data); } -STC_INLINE void _cx_memb(_adjust_end_)(_cx_self* self, intptr_t n) +STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) { self->_len += n; } #if defined _i_has_eq || defined _i_has_cmp STC_INLINE bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { if (self->_len != other->_len) return false; for (intptr_t i = 0; i < self->_len; ++i) { const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i); diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 71787733..3213dd1c 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -74,164 +74,164 @@ int main() { #include "priv/template.h" #ifndef i_is_forward - _cx_deftypes(_c_cvec_types, _cx_self, i_key); + _cx_DEFTYPES(_c_cvec_types, _cx_Self, i_key); #endif typedef i_keyraw _cx_raw; -STC_API _cx_self _cx_memb(_init)(void); -STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API void _cx_memb(_clear)(_cx_self* self); -STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t cap); -STC_API bool _cx_memb(_resize)(_cx_self* self, intptr_t size, i_key null); -STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value); -STC_API _cx_iter _cx_memb(_erase_n)(_cx_self* self, intptr_t idx, intptr_t n); -STC_API _cx_iter _cx_memb(_insert_uninit)(_cx_self* self, intptr_t idx, intptr_t n); +STC_API _cx_Self _cx_MEMB(_init)(void); +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API void _cx_MEMB(_clear)(_cx_Self* self); +STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t cap); +STC_API bool _cx_MEMB(_resize)(_cx_Self* self, intptr_t size, i_key null); +STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); +STC_API _cx_iter _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n); +STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n); #if !defined i_no_cmp || defined _i_has_eq -STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw); +STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw); #endif #ifndef i_no_cmp -STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y); -STC_API _cx_iter _cx_memb(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound); +STC_API int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y); +STC_API _cx_iter _cx_MEMB(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound); #endif -STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); } +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } #if !defined i_no_emplace STC_API _cx_iter -_cx_memb(_emplace_n)(_cx_self* self, intptr_t idx, const _cx_raw raw[], intptr_t n); +_cx_MEMB(_emplace_n)(_cx_Self* self, intptr_t idx, const _cx_raw raw[], intptr_t n); -STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) { - return _cx_memb(_push)(self, i_keyfrom(raw)); +STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) { + return _cx_MEMB(_push)(self, i_keyfrom(raw)); } -STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) { - return _cx_memb(_push)(self, i_keyfrom(raw)); +STC_INLINE _cx_value* _cx_MEMB(_emplace_back)(_cx_Self* self, _cx_raw raw) { + return _cx_MEMB(_push)(self, i_keyfrom(raw)); } -STC_INLINE _cx_iter _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) { - return _cx_memb(_emplace_n)(self, _it_ptr(it) - self->data, &raw, 1); +STC_INLINE _cx_iter _cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, _cx_raw raw) { + return _cx_MEMB(_emplace_n)(self, _it_ptr(it) - self->data, &raw, 1); } #endif // !i_no_emplace #if !defined i_no_clone -STC_API _cx_self _cx_memb(_clone)(_cx_self cx); -STC_API _cx_iter _cx_memb(_copy_n)(_cx_self* self, intptr_t idx, const _cx_value arr[], intptr_t n); -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } -STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val) +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); +STC_API _cx_iter _cx_MEMB(_copy_n)(_cx_Self* self, intptr_t idx, const _cx_value arr[], intptr_t n); +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } +STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val) { return i_keyclone(val); } -STC_INLINE void _cx_memb(_copy)(_cx_self* self, const _cx_self* other) { +STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { if (self->data == other->data) return; - _cx_memb(_clear)(self); - _cx_memb(_copy_n)(self, 0, other->data, other->_len); + _cx_MEMB(_clear)(self); + _cx_MEMB(_copy_n)(self, 0, other->data, other->_len); } #endif // !i_no_clone -STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) { return self->_len; } -STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) { return self->_cap; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return !self->_len; } -STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* val) { return i_keyto(val); } -STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; } -STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) { return self->_len; } +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) { return self->_cap; } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return !self->_len; } +STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) { return i_keyto(val); } +STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return self->data; } +STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return self->data + self->_len - 1; } -STC_INLINE void _cx_memb(_pop)(_cx_self* self) +STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } -STC_INLINE _cx_value _cx_memb(_pull)(_cx_self* self) +STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { assert(self->_len); return self->data[--self->_len]; } -STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) - { return _cx_memb(_push)(self, value); } -STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) { _cx_memb(_pop)(self); } - -STC_INLINE _cx_self -_cx_memb(_with_size)(const intptr_t size, i_key null) { - _cx_self cx = _cx_memb(_init)(); - _cx_memb(_resize)(&cx, size, null); +STC_INLINE _cx_value* _cx_MEMB(_push_back)(_cx_Self* self, i_key value) + { return _cx_MEMB(_push)(self, value); } +STC_INLINE void _cx_MEMB(_pop_back)(_cx_Self* self) { _cx_MEMB(_pop)(self); } + +STC_INLINE _cx_Self +_cx_MEMB(_with_size)(const intptr_t size, i_key null) { + _cx_Self cx = _cx_MEMB(_init)(); + _cx_MEMB(_resize)(&cx, size, null); return cx; } -STC_INLINE _cx_self -_cx_memb(_with_capacity)(const intptr_t cap) { - _cx_self cx = _cx_memb(_init)(); - _cx_memb(_reserve)(&cx, cap); +STC_INLINE _cx_Self +_cx_MEMB(_with_capacity)(const intptr_t cap) { + _cx_Self cx = _cx_MEMB(_init)(); + _cx_MEMB(_reserve)(&cx, cap); return cx; } STC_INLINE void -_cx_memb(_shrink_to_fit)(_cx_self* self) { - _cx_memb(_reserve)(self, _cx_memb(_size)(self)); +_cx_MEMB(_shrink_to_fit)(_cx_Self* self) { + _cx_MEMB(_reserve)(self, _cx_MEMB(_size)(self)); } STC_INLINE _cx_iter -_cx_memb(_insert_n)(_cx_self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) { - _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); +_cx_MEMB(_insert_n)(_cx_Self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) { + _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n); if (it.ref) c_memcpy(it.ref, arr, n*c_sizeof *arr); return it; } STC_INLINE _cx_iter -_cx_memb(_insert)(_cx_self* self, const intptr_t idx, const i_key value) { - return _cx_memb(_insert_n)(self, idx, &value, 1); +_cx_MEMB(_insert)(_cx_Self* self, const intptr_t idx, const i_key value) { + return _cx_MEMB(_insert_n)(self, idx, &value, 1); } STC_INLINE _cx_iter -_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, const i_key value) { - return _cx_memb(_insert_n)(self, _it_ptr(it) - self->data, &value, 1); +_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, const i_key value) { + return _cx_MEMB(_insert_n)(self, _it_ptr(it) - self->data, &value, 1); } STC_INLINE _cx_iter -_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { - return _cx_memb(_erase_n)(self, it.ref - self->data, 1); +_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) { + return _cx_MEMB(_erase_n)(self, it.ref - self->data, 1); } STC_INLINE _cx_iter -_cx_memb(_erase_range)(_cx_self* self, _cx_iter i1, _cx_iter i2) { - return _cx_memb(_erase_n)(self, i1.ref - self->data, _it2_ptr(i1, i2) - i1.ref); +_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter i1, _cx_iter i2) { + return _cx_MEMB(_erase_n)(self, i1.ref - self->data, _it2_ptr(i1, i2) - i1.ref); } STC_INLINE const _cx_value* -_cx_memb(_at)(const _cx_self* self, const intptr_t idx) { +_cx_MEMB(_at)(const _cx_Self* self, const intptr_t idx) { assert(idx < self->_len); return self->data + idx; } STC_INLINE _cx_value* -_cx_memb(_at_mut)(_cx_self* self, const intptr_t idx) { +_cx_MEMB(_at_mut)(_cx_Self* self, const intptr_t idx) { assert(idx < self->_len); return self->data + idx; } -STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { +STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { intptr_t n = self->_len; return c_LITERAL(_cx_iter){n ? self->data : NULL, self->data + n}; } -STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) { return c_LITERAL(_cx_iter){NULL, self->data + self->_len}; } -STC_INLINE void _cx_memb(_next)(_cx_iter* it) +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { if (++it->ref == it->end) it->ref = NULL; } -STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) +STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) { if ((it.ref += n) >= it.end) it.ref = NULL; return it; } -STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it) +STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) { return (it.ref - self->data); } -STC_INLINE void _cx_memb(_adjust_end_)(_cx_self* self, intptr_t n) +STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) { self->_len += n; } #if !defined i_no_cmp || defined _i_has_eq STC_INLINE _cx_iter -_cx_memb(_find)(const _cx_self* self, _cx_raw raw) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw); +_cx_MEMB(_find)(const _cx_Self* self, _cx_raw raw) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw); } STC_INLINE const _cx_value* -_cx_memb(_get)(const _cx_self* self, _cx_raw raw) { - return _cx_memb(_find)(self, raw).ref; +_cx_MEMB(_get)(const _cx_Self* self, _cx_raw raw) { + return _cx_MEMB(_find)(self, raw).ref; } STC_INLINE _cx_value* -_cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw) - { return (_cx_value*) _cx_memb(_get)(self, raw); } +_cx_MEMB(_get_mut)(const _cx_Self* self, _cx_raw raw) + { return (_cx_value*) _cx_MEMB(_get)(self, raw); } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { if (self->_len != other->_len) return false; for (intptr_t i = 0; i < self->_len; ++i) { const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i); @@ -243,39 +243,39 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { #ifndef i_no_cmp STC_INLINE _cx_iter -_cx_memb(_binary_search)(const _cx_self* self, _cx_raw raw) { +_cx_MEMB(_binary_search)(const _cx_Self* self, _cx_raw raw) { _cx_iter lower; - return _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower); + return _cx_MEMB(_binary_search_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw, &lower); } STC_INLINE _cx_iter -_cx_memb(_lower_bound)(const _cx_self* self, _cx_raw raw) { +_cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_raw raw) { _cx_iter lower; - _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower); + _cx_MEMB(_binary_search_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw, &lower); return lower; } STC_INLINE void -_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) { +_cx_MEMB(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) { qsort(i1.ref, (size_t)(_it2_ptr(i1, i2) - i1.ref), sizeof(_cx_value), (int(*)(const void*, const void*)) cmp); } STC_INLINE void -_cx_memb(_sort)(_cx_self* self) { - _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp)); +_cx_MEMB(_sort)(_cx_Self* self) { + _cx_MEMB(_sort_range)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), _cx_MEMB(_value_cmp)); } #endif // !c_no_cmp /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) -STC_DEF _cx_self -_cx_memb(_init)(void) { - return c_LITERAL(_cx_self){NULL}; +STC_DEF _cx_Self +_cx_MEMB(_init)(void) { + return c_LITERAL(_cx_Self){NULL}; } STC_DEF void -_cx_memb(_clear)(_cx_self* self) { +_cx_MEMB(_clear)(_cx_Self* self) { if (self->_cap) { for (_cx_value *p = self->data, *q = p + self->_len; p != q; ) { --q; i_keydrop(q); @@ -285,15 +285,15 @@ _cx_memb(_clear)(_cx_self* self) { } STC_DEF void -_cx_memb(_drop)(_cx_self* self) { +_cx_MEMB(_drop)(_cx_Self* self) { if (self->_cap == 0) return; - _cx_memb(_clear)(self); + _cx_MEMB(_clear)(self); i_free(self->data); } STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) { if (cap > self->_cap || (cap && cap == self->_len)) { _cx_value* d = (_cx_value*)i_realloc(self->data, cap*c_sizeof(i_key)); if (!d) @@ -305,8 +305,8 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { } STC_DEF bool -_cx_memb(_resize)(_cx_self* self, const intptr_t len, i_key null) { - if (!_cx_memb(_reserve)(self, len)) +_cx_MEMB(_resize)(_cx_Self* self, const intptr_t len, i_key null) { + if (!_cx_MEMB(_reserve)(self, len)) return false; const intptr_t n = self->_len; for (intptr_t i = len; i < n; ++i) @@ -318,9 +318,9 @@ _cx_memb(_resize)(_cx_self* self, const intptr_t len, i_key null) { } STC_DEF _cx_value* -_cx_memb(_push)(_cx_self* self, i_key value) { +_cx_MEMB(_push)(_cx_Self* self, i_key value) { if (self->_len == self->_cap) - if (!_cx_memb(_reserve)(self, self->_len*3/2 + 4)) + if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + 4)) return NULL; _cx_value *v = self->data + self->_len++; *v = value; @@ -328,10 +328,10 @@ _cx_memb(_push)(_cx_self* self, i_key value) { } STC_DEF _cx_iter -_cx_memb(_insert_uninit)(_cx_self* self, const intptr_t idx, const intptr_t n) { +_cx_MEMB(_insert_uninit)(_cx_Self* self, const intptr_t idx, const intptr_t n) { if (self->_len + n > self->_cap) - if (!_cx_memb(_reserve)(self, self->_len*3/2 + n)) - return _cx_memb(_end)(self); + if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + n)) + return _cx_MEMB(_end)(self); _cx_value* pos = self->data + idx; c_memmove(pos + n, pos, (self->_len - idx)*c_sizeof *pos); @@ -340,7 +340,7 @@ _cx_memb(_insert_uninit)(_cx_self* self, const intptr_t idx, const intptr_t n) { } STC_DEF _cx_iter -_cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t len) { +_cx_MEMB(_erase_n)(_cx_Self* self, const intptr_t idx, const intptr_t len) { _cx_value* d = self->data + idx, *p = d, *end = self->data + self->_len; for (intptr_t i = 0; i < len; ++i, ++p) { i_keydrop(p); } @@ -350,17 +350,17 @@ _cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t len) { } #if !defined i_no_clone -STC_DEF _cx_self -_cx_memb(_clone)(_cx_self cx) { - _cx_self out = _cx_memb(_init)(); - _cx_memb(_copy_n)(&out, 0, cx.data, cx._len); +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self cx) { + _cx_Self out = _cx_MEMB(_init)(); + _cx_MEMB(_copy_n)(&out, 0, cx.data, cx._len); return out; } STC_DEF _cx_iter -_cx_memb(_copy_n)(_cx_self* self, const intptr_t idx, +_cx_MEMB(_copy_n)(_cx_Self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) { - _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); + _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n); if (it.ref) for (_cx_value* p = it.ref, *q = p + n; p != q; ++arr) *p++ = i_keyclone((*arr)); @@ -370,8 +370,8 @@ _cx_memb(_copy_n)(_cx_self* self, const intptr_t idx, #if !defined i_no_emplace STC_DEF _cx_iter -_cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw raw[], intptr_t n) { - _cx_iter it = _cx_memb(_insert_uninit)(self, idx, n); +_cx_MEMB(_emplace_n)(_cx_Self* self, const intptr_t idx, const _cx_raw raw[], intptr_t n) { + _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n); if (it.ref) for (_cx_value* p = it.ref; n--; ++raw, ++p) *p = i_keyfrom((*raw)); @@ -381,7 +381,7 @@ _cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw raw[], in #if !defined i_no_cmp || defined _i_has_eq STC_DEF _cx_iter -_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { +_cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { const _cx_value* p2 = _it2_ptr(i1, i2); for (; i1.ref != p2; ++i1.ref) { const _cx_raw r = i_keyto(i1.ref); @@ -395,7 +395,7 @@ _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { #ifndef i_no_cmp STC_DEF _cx_iter -_cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw, +_cx_MEMB(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw, _cx_iter* lower_bound) { _cx_value* w[2] = {i1.ref, _it2_ptr(i1, i2)}; _cx_iter mid = i1; @@ -412,7 +412,7 @@ _cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw, i1.ref = NULL; return i1; } -STC_DEF int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { +STC_DEF int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y) { const _cx_raw rx = i_keyto(x); const _cx_raw ry = i_keyto(y); return i_cmp((&rx), (&ry)); diff --git a/include/stc/extend.h b/include/stc/extend.h index f697d2b3..f9ac92bf 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -54,7 +54,7 @@ typedef struct { i_type get; } c_PASTE(i_type, _ext); -#define c_extend(self) c_container_of(self, _cx_memb(_ext), get) +#define c_extend(self) c_container_of(self, _cx_MEMB(_ext), get) #define i_is_forward #define _i_inc diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index b3f3eabe..c1b7c1e7 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -25,17 +25,17 @@ #ifndef STC_TEMPLATE_H_INCLUDED #define STC_TEMPLATE_H_INCLUDED - #define _cx_self i_type - #define _cx_memb(name) c_PASTE(_cx_self, name) - #define _cx_deftypes(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__)) - #define _cx_value _cx_memb(_value) - #define _cx_key _cx_memb(_key) - #define _cx_mapped _cx_memb(_mapped) - #define _cx_raw _cx_memb(_raw) - #define _cx_keyraw _cx_memb(_keyraw) - #define _cx_iter _cx_memb(_iter) - #define _cx_result _cx_memb(_result) - #define _cx_node _cx_memb(_node) + #define _cx_Self i_type + #define _cx_MEMB(name) c_PASTE(_cx_Self, name) + #define _cx_DEFTYPES(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__)) + #define _cx_value _cx_MEMB(_value) + #define _cx_key _cx_MEMB(_key) + #define _cx_mapped _cx_MEMB(_mapped) + #define _cx_raw _cx_MEMB(_raw) + #define _cx_keyraw _cx_MEMB(_keyraw) + #define _cx_iter _cx_MEMB(_iter) + #define _cx_result _cx_MEMB(_result) + #define _cx_node _cx_MEMB(_node) #endif #ifndef i_type -- cgit v1.2.3 From 3fed66750bed9c82a8bb12fd86b963d2f5ec0eb5 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 20 Jun 2023 16:32:32 +0200 Subject: Renamed `i_more` => `i_retain` (avoids undef of template parameters on next STC container inclusion). --- docs/ccommon_api.md | 4 ++-- include/stc/algo/sort.h | 23 +++++++++++++++++++++-- include/stc/cdeq.h | 6 +++--- include/stc/priv/template2.h | 4 ++-- misc/benchmarks/various/csort_bench.c | 2 +- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 89a98cbb..c9c65156 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -222,11 +222,11 @@ int main() { } ``` Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is -possible and very fast. Note that `i_more` must be defined to pick up template parameters from the container: +possible and very fast. Note that `i_retain` must be defined to retain specified template parameters for use by sort: ```c #define i_type MyDeq #define i_val int -#define i_more +#define i_retain #include // deque #include #include diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h index 291d90a6..002e6499 100644 --- a/include/stc/algo/sort.h +++ b/include/stc/algo/sort.h @@ -26,7 +26,7 @@ template params: #define i_less - less function. default: *x < *y #define i_type name - define {{name}}_sort_n(), else {{i_val}}array_sort_n(). -// test: +// ex1: #include #define i_val int #include @@ -34,12 +34,31 @@ template params: int main() { int nums[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21}; - intarray_sort_n(nums, c_arraylen(arr)); + intarray_sort_n(nums, c_arraylen(nums)); for (int i = 0; i < c_arraylen(nums); i++) printf(" %d", nums[i]); puts(""); } + +// ex2: +#define i_val int +#define i_type IDeq +#define i_retain // retain input template params to be reused by sort.h +#include +#include + +int main() { + IDeq nums = c_init(IDeq, {5434, 25, 245, 1, 654, 33, 543, 21}); + IDeq_push_front(&nums, 23); + IDeq_push_front(&nums, 321); + + IDeq_sort_n(&nums, IDeq_size(&nums)); + + c_foreach (i, IDeq, nums) + printf(" %d", *i.ref); + IDeq_drop(&nums); +} */ #include "../ccommon.h" diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 0eac5a1d..06dfdb82 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -23,11 +23,11 @@ #define _i_prefix cdeq_ #define _pop _pop_front #define _pull _pull_front -#ifdef i_more +#ifdef i_retain #include "cqueue.h" - #define i_more + #define i_retain #else - #define i_more + #define i_retain #include "cqueue.h" #endif #undef _pop diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 4604e610..47b82937 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -20,8 +20,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifdef i_more -#undef i_more +#ifdef i_retain +#undef i_retain #else #undef i_type #undef i_tag diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c index d434693f..93034dde 100644 --- a/misc/benchmarks/various/csort_bench.c +++ b/misc/benchmarks/various/csort_bench.c @@ -8,7 +8,7 @@ #define NDEBUG #define i_type Ints #define i_val int -#define i_more +#define i_retain #include #include -- cgit v1.2.3 From d1a1ed75ee08ed1100748bdbdc6fb1c3136c4c6b Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 20 Jun 2023 18:26:35 +0200 Subject: Added some more to coroutine.h --- README.md | 4 +++- include/stc/algo/coroutine.h | 14 +++++++++++--- misc/examples/scheduler.c | 4 ++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f14858e7..3628ecd1 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ STC - Smart Template Containers =============================== -### [Version 4.3 RC](#version-history) +### [Version 4.3 RC2](#version-history) --- Description @@ -613,6 +613,8 @@ STC is generally very memory efficient. Memory usage for the different container # Version History ## Version 4.3 +- algo/coroutine.h much improved with new API and more features. +- New cdeq and cqueue implementation(s), using circular buffer. - Removed deprecated uppercase flow-control macro names. - Removed deprecated crandom.h. Use crand.h with new API. - Improved default string hash function. diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index e0952e1f..b92507b8 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -86,12 +86,20 @@ enum { #define cco_closure(Ret, Closure, ...) \ struct Closure { \ - Ret (*coroutine)(struct Closure*); \ - __VA_ARGS__ \ + Ret (*cco_fn)(struct Closure*); \ int cco_state; \ + __VA_ARGS__ \ } -#define cco_resume(closure) (closure)->coroutine(closure) +typedef struct cco_base { + void (*cco_fn)(struct cco_base*); + int cco_state; +} cco_base; + +#define cco_cast(closure) \ + ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state))) + +#define cco_resume(closure) (closure)->cco_fn(closure) #define cco_await_on(...) c_MACRO_OVERLOAD(cco_await_on, __VA_ARGS__) #define cco_await_on_1(closure) cco_await_2((cco_resume(closure), cco_done(closure)), ) #define cco_await_on_2(co, func) cco_await_2((func(co), cco_done(co)), ) diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index 54fefc47..59101b4e 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -58,8 +58,8 @@ static bool taskB(struct Task* task) void Use(void) { Scheduler scheduler = c_init(Scheduler, { - {taskA, &scheduler}, - {taskB, &scheduler}, + {.cco_fn=taskA, .sched=&scheduler}, + {.cco_fn=taskB, .sched=&scheduler}, }); while (schedule(&scheduler)) {} -- cgit v1.2.3 From 3aa8a04f4fe38d828006b4713beb390ef526cea7 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Wed, 21 Jun 2023 00:31:59 +0200 Subject: Added cco_switch(x) {}, cco_case(val) {}, and cco_default {} to use inside coroutines. --- include/stc/algo/coroutine.h | 5 +++++ misc/examples/regex2.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index b92507b8..727ce2a8 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -66,6 +66,11 @@ enum { #define cco_initial(co) ((co)->cco_state == 0) #define cco_done(co) ((co)->cco_state == cco_state_done) +/* Always use { } after cco_switch(x), cco_case(val), and cco_default. */ +#define cco_switch(x) for (intmax_t _sw = (intmax_t)(x), _once=1; _once; _once=0) +#define cco_case(val) if (_sw == (intmax_t)(val)) +#define cco_default else + #define cco_routine(co) \ for (int *_state = &(co)->cco_state; *_state != cco_state_done; *_state = cco_state_done) \ _resume: switch (*_state) case 0: // thanks, @liigo! diff --git a/misc/examples/regex2.c b/misc/examples/regex2.c index 5718a1d8..734190cb 100644 --- a/misc/examples/regex2.c +++ b/misc/examples/regex2.c @@ -26,7 +26,7 @@ int main() printf("\ninput: %s\n", s[i].input); c_formatch (j, &re, s[i].input) { - c_forrange (k, cregex_captures(&re)) + c_forrange (k, cregex_captures(&re) + 1) printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); } } -- cgit v1.2.3 From bc6b781548c10935ec6e72e42ece905f46105ec3 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Wed, 21 Jun 2023 00:35:30 +0200 Subject: Minor fix. --- include/stc/algo/coroutine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 727ce2a8..a2496d25 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -69,7 +69,7 @@ enum { /* Always use { } after cco_switch(x), cco_case(val), and cco_default. */ #define cco_switch(x) for (intmax_t _sw = (intmax_t)(x), _once=1; _once; _once=0) #define cco_case(val) if (_sw == (intmax_t)(val)) -#define cco_default else +#define cco_default #define cco_routine(co) \ for (int *_state = &(co)->cco_state; *_state != cco_state_done; *_state = cco_state_done) \ -- cgit v1.2.3 From 08f75cf88252a3a95ee8eb8464295bcd177ec74f Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Wed, 21 Jun 2023 09:11:49 +0200 Subject: Fixed cco_switch: emulation of switch inside coroutines. --- include/stc/algo/coroutine.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index a2496d25..e0cf5488 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -66,9 +66,9 @@ enum { #define cco_initial(co) ((co)->cco_state == 0) #define cco_done(co) ((co)->cco_state == cco_state_done) -/* Always use { } after cco_switch(x), cco_case(val), and cco_default. */ -#define cco_switch(x) for (intmax_t _sw = (intmax_t)(x), _once=1; _once; _once=0) -#define cco_case(val) if (_sw == (intmax_t)(val)) +/* Emulate switch in coro: always use { } after cco_case(val) and cco_default. */ +#define cco_switch(x) for (long long _sw = (long long)(x), _b=0; !_b; _b=1) +#define cco_case(val) if (_b |= _sw == (val)) #define cco_default #define cco_routine(co) \ -- cgit v1.2.3 From e27a51708bf1ee4b22842b4a0924b3ded26f630c Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 21 Jun 2023 13:10:18 +0200 Subject: Update of cstr_append_uninit(). --- include/stc/algo/coroutine.h | 2 +- include/stc/cstr.h | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index e0cf5488..e20fd8ad 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -101,7 +101,7 @@ typedef struct cco_base { int cco_state; } cco_base; -#define cco_cast(closure) \ +#define cco_base_cast(closure) \ ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state))) #define cco_resume(closure) (closure)->cco_fn(closure) diff --git a/include/stc/cstr.h b/include/stc/cstr.h index b9b066ad..ce42cf8d 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -77,6 +77,7 @@ extern intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* sea extern intptr_t cstr_find_sv(const cstr* self, csview search); extern char* cstr_assign_n(cstr* self, const char* str, intptr_t len); extern char* cstr_append_n(cstr* self, const char* str, intptr_t len); +extern char* cstr_append_uninit(cstr *self, intptr_t len); extern bool cstr_getdelim(cstr *self, int delim, FILE *fp); extern void cstr_erase(cstr* self, intptr_t pos, intptr_t len); extern void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); @@ -244,14 +245,6 @@ STC_INLINE cstr_iter cstr_advance(cstr_iter it, intptr_t pos) { STC_INLINE void cstr_clear(cstr* self) { _cstr_set_size(self, 0); } -STC_INLINE char* cstr_append_uninit(cstr *self, intptr_t len) { - intptr_t sz = cstr_size(self); - char* d = cstr_reserve(self, sz + len); - if (!d) return NULL; - _cstr_set_size(self, sz + len); - return d + sz; -} - STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2) { return strcmp(cstr_str(s1), cstr_str(s2)); } @@ -551,6 +544,14 @@ char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { return r.data; } +char* cstr_append_uninit(cstr *self, intptr_t len) { + cstr_buf r = cstr_buffer(self); + if (r.size + len > r.cap && !(r.data = cstr_reserve(self, r.size*3/2 + len))) + return NULL; + _cstr_set_size(self, r.size + len); + return r.data + r.size; +} + bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { int c = fgetc(fp); if (c == EOF) -- cgit v1.2.3 From 5096c3c951f6b99e9d6ee04a21531e226153cca9 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 21 Jun 2023 19:48:05 +0200 Subject: Fix cbox carc default cmp and eq. --- include/stc/carc.h | 18 +++++++----------- include/stc/cbox.h | 18 +++++++----------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/include/stc/carc.h b/include/stc/carc.h index 3b60fe78..2096b968 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -77,8 +77,13 @@ int main() { #endif // CARC_H_INCLUDED #define _i_prefix carc_ -#ifdef i_eq -#define _i_eq +#if !defined i_cmp && !defined i_less && \ + !defined i_valclass && !defined i_valboxed && \ + !defined i_val_str && !defined i_val_ssv + #if !defined i_eq + #define i_eq(x, y) x == y + #endif + #define i_less(x, y) x < y #endif #include "priv/template.h" typedef i_keyraw _cx_raw; @@ -181,9 +186,7 @@ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_cmp((&rx), (&ry)); } -#endif -#ifdef _i_eq STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } @@ -191,12 +194,6 @@ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_eq((&rx), (&ry)); } -#elif !defined i_no_cmp -STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return i_cmp(rx, ry) == 0; } - -STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) - { return _cx_MEMB(_cmp)(self, other) == 0; } #endif #ifndef i_no_hash @@ -207,7 +204,6 @@ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } #endif -#undef _i_eq #undef _i_atomic_inc #undef _i_atomic_dec_and_test #include "priv/template2.h" diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 86283ad7..24de71d4 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -70,8 +70,13 @@ int main() { #endif // CBOX_H_INCLUDED #define _i_prefix cbox_ -#ifdef i_eq -#define _i_eq +#if !defined i_cmp && !defined i_less && \ + !defined i_valclass && !defined i_valboxed && \ + !defined i_val_str && !defined i_val_ssv + #if !defined i_eq + #define i_eq(x, y) x == y + #endif + #define i_less(x, y) x < y #endif #include "priv/template.h" typedef i_keyraw _cx_raw; @@ -167,9 +172,7 @@ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_cmp((&rx), (&ry)); } -#endif -#ifdef _i_eq STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } @@ -177,12 +180,6 @@ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_eq((&rx), (&ry)); } -#elif !defined i_no_cmp -STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return i_cmp(rx, ry) == 0; } - -STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) - { return _cx_MEMB(_cmp)(self, other) == 0; } #endif #ifndef i_no_hash @@ -193,5 +190,4 @@ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } #endif -#undef _i_eq #include "priv/template2.h" -- cgit v1.2.3 From 764d6b5a831c4ff58fb717a1360fe80f691a424d Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Thu, 29 Jun 2023 09:32:39 +0200 Subject: Usage change: comparison is no longer enabled when specifying i_val for cvec, cdeq and clist (like cstack and cqueue). Comparison functions are still required when specifying i_valclass. For fundamental/native types like integers, floats etc., define i_native_cmp along with i_val instead of i_less/i_cmp/i_eq. --- include/stc/carc.h | 75 ++++++++++++++++++++++++++---------------- include/stc/cbox.h | 71 +++++++++++++++++++++++---------------- include/stc/ccommon.h | 4 +-- include/stc/cdeq.h | 4 +-- include/stc/clist.h | 13 ++++---- include/stc/cqueue.h | 6 ++-- include/stc/cstr.h | 2 +- include/stc/csview.h | 2 +- include/stc/cvec.h | 18 +++++----- include/stc/priv/template.h | 53 +++++++++++++++-------------- include/stc/priv/template2.h | 5 +-- misc/examples/arc_containers.c | 4 +-- misc/examples/arc_demo.c | 14 +++++--- misc/examples/arcvec_erase.c | 2 +- misc/examples/box2.c | 4 +-- misc/examples/complex.c | 4 +-- misc/examples/csmap_find.c | 1 - misc/examples/demos.c | 1 + misc/examples/intrusive.c | 5 +-- misc/examples/list.c | 1 + misc/examples/lower_bound.c | 1 + misc/examples/music_arc.c | 6 ++-- misc/examples/new_list.c | 5 +-- misc/examples/new_sptr.c | 6 ++-- misc/examples/new_vec.c | 5 +-- misc/examples/scheduler.c | 1 - 26 files changed, 176 insertions(+), 137 deletions(-) diff --git a/include/stc/carc.h b/include/stc/carc.h index 2096b968..db0cdcec 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -30,6 +30,11 @@ typedef struct { cstr name, last; } Person; Person Person_make(const char* name, const char* last) { return (Person){.name = cstr_from(name), .last = cstr_from(last)}; } +Person Person_clone(Person p) { + p.name = cstr_clone(p.name); + p.last = cstr_clone(p.last); + return p; +} void Person_drop(Person* p) { printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); cstr_drop(&p->name); @@ -37,8 +42,8 @@ void Person_drop(Person* p) { } #define i_type ArcPers -#define i_key Person -#define i_keydrop Person_drop +#define i_valclass Person // clone, drop, cmp, hash +#define i_opt c_no_cmp|c_no_hash // exclude cmp, hash #include int main() { @@ -77,14 +82,7 @@ int main() { #endif // CARC_H_INCLUDED #define _i_prefix carc_ -#if !defined i_cmp && !defined i_less && \ - !defined i_valclass && !defined i_valboxed && \ - !defined i_val_str && !defined i_val_ssv - #if !defined i_eq - #define i_eq(x, y) x == y - #endif - #define i_less(x, y) x < y -#endif +#define _i_carc #include "priv/template.h" typedef i_keyraw _cx_raw; @@ -178,32 +176,53 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { *self = ptr; } -#ifndef i_no_cmp -STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) - { return i_cmp(rx, ry); } +#if defined _i_has_cmp + STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) + { return i_cmp(rx, ry); } -STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); -} + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_cmp((&rx), (&ry)); + } +#else + STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) + { return c_default_cmp(&rx, &ry); } -STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return i_eq(rx, ry); } + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } +#endif +#if defined _i_has_eq || defined _i_has_cmp + STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) + { return i_eq(rx, ry); } -STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); -} + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_eq((&rx), (&ry)); + } +#else + STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) + { return rx == ry; } + + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } #endif +#if defined i_hash + STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) + { return i_hash(rx); } -#ifndef i_no_hash -STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) - { return i_hash(rx); } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return i_hash(self->get); } +#else + STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) + { return c_default_hash(&rx); } -STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } #endif #undef _i_atomic_inc #undef _i_atomic_dec_and_test #include "priv/template2.h" +#undef _i_carc \ No newline at end of file diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 24de71d4..c8d919b2 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -25,6 +25,7 @@ /* cbox: heap allocated boxed type #define i_implement #include +#include // c_auto typedef struct { cstr name, email; } Person; @@ -41,8 +42,9 @@ void Person_drop(Person* p) { c_drop(cstr, &p->name, &p->email); } -#define i_keyclass Person // bind Person clone+drop fn's #define i_type PBox +#define i_valclass Person // bind Person clone+drop fn's +#define i_no_cmp // no cmp/hash is defined #include int main() { @@ -70,14 +72,7 @@ int main() { #endif // CBOX_H_INCLUDED #define _i_prefix cbox_ -#if !defined i_cmp && !defined i_less && \ - !defined i_valclass && !defined i_valboxed && \ - !defined i_val_str && !defined i_val_ssv - #if !defined i_eq - #define i_eq(x, y) x == y - #endif - #define i_less(x, y) x < y -#endif +#define _i_cbox #include "priv/template.h" typedef i_keyraw _cx_raw; @@ -164,30 +159,50 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) { moved->get = NULL; } -#ifndef i_no_cmp -STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) - { return i_cmp(rx, ry); } - -STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); -} +#if defined _i_has_cmp + STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) + { return i_cmp(rx, ry); } -STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return i_eq(rx, ry); } + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_cmp((&rx), (&ry)); + } +#else + STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) + { return c_default_cmp(&rx, &ry); } -STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); -} + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } #endif +#if defined _i_has_eq || defined _i_has_cmp + STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) + { return i_eq(rx, ry); } -#ifndef i_no_hash -STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) - { return i_hash(rx); } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_eq((&rx), (&ry)); + } +#else + STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) + { return rx == ry; } -STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } #endif +#if defined i_hash + STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) + { return i_hash(rx); } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return i_hash(self->get); } +#else + STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) + { return c_default_hash(&rx); } + + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } +#endif #include "priv/template2.h" +#undef _i_cbox \ No newline at end of file diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 5f280218..bbf1579b 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -113,8 +113,8 @@ #define c_no_clone (1<<2) #define c_no_emplace (1<<3) #define c_no_cmp (1<<4) -#define c_no_hash (1<<5) - +#define c_native_cmp (1<<5) +#define c_no_hash (1<<6) /* Function macros and others */ #define c_litstrlen(literal) (c_sizeof("" literal) - 1) diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 06dfdb82..2db040f1 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -101,7 +101,7 @@ _cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, const _cx_raw raw) { return _cx_MEMB(_insert_at)(self, it, i_keyfrom(raw)); } #endif -#if defined _i_has_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw); STC_INLINE _cx_iter @@ -179,7 +179,7 @@ _cx_MEMB(_emplace_n)(_cx_Self* self, const intptr_t idx, const _cx_raw* raw, con } #endif -#if defined _i_has_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp STC_DEF _cx_iter _cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { for (; i1.pos != i2.pos; _cx_MEMB(_next)(&i1)) { diff --git a/include/stc/clist.h b/include/stc/clist.h index 0785a6af..38358d73 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -93,11 +93,11 @@ STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value); STC_API _cx_iter _cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, i_key value); STC_API _cx_iter _cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it); STC_API _cx_iter _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2); -#if !defined i_no_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val); STC_API intptr_t _cx_MEMB(_remove)(_cx_Self* self, _cx_raw val); #endif -#ifndef i_no_cmp +#if defined _i_has_cmp STC_API bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*)); STC_API int _cx_MEMB(_sort_cmp_)(const _cx_value*, const _cx_value*); STC_INLINE bool _cx_MEMB(_sort)(_cx_Self* self) @@ -188,7 +188,7 @@ _cx_MEMB(_splice_range)(_cx_Self* self, _cx_iter it, return _cx_MEMB(_splice)(self, it, &tmp); } -#if !defined i_no_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp STC_INLINE _cx_iter _cx_MEMB(_find)(const _cx_Self* self, _cx_raw val) { return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val); @@ -350,8 +350,7 @@ _cx_MEMB(_split_off)(_cx_Self* self, _cx_iter it1, _cx_iter it2) { return lst; } -#if !defined i_no_cmp || defined _i_has_eq - +#if defined _i_has_eq || defined _i_has_cmp STC_DEF _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) { c_foreach (it, _cx_Self, it1, it2) { @@ -379,7 +378,7 @@ _cx_MEMB(_remove)(_cx_Self* self, _cx_raw val) { } #endif -#ifndef i_no_cmp +#if defined _i_has_cmp STC_DEF int _cx_MEMB(_sort_cmp_)(const _cx_value* x, const _cx_value* y) { const _cx_raw a = i_keyto(x), b = i_keyto(y); return i_cmp((&a), (&b)); @@ -401,7 +400,7 @@ STC_DEF bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, co *i.ref = *p; i_free(a); return true; } -#endif // !c_no_cmp +#endif // _i_has_cmp #endif // i_implement #define CLIST_H_INCLUDED #include "priv/template2.h" diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 6eee712b..e9f1b877 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -63,8 +63,8 @@ STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) { return _cx_MEMB(_push)(self, i_keyfrom(raw)); } #endif -#if defined _i_has_cmp || defined _i_has_eq -STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other); +#if defined _i_has_eq || defined _i_has_cmp +STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other); #endif #if !defined i_no_clone @@ -224,7 +224,7 @@ _cx_MEMB(_clone)(_cx_Self cx) { } #endif // i_no_clone -#if defined _i_has_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp STC_DEF bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; diff --git a/include/stc/cstr.h b/include/stc/cstr.h index ce42cf8d..0f217f53 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -433,7 +433,7 @@ cstr cstr_tocase(csview sv, int k) { #endif // i_import /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_import || defined i_implement +#if defined i_implement #ifndef CSTR_C_INCLUDED #define CSTR_C_INCLUDED diff --git a/include/stc/csview.h b/include/stc/csview.h index 07ab4059..f960968c 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -150,7 +150,7 @@ STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u #endif /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_import || defined i_implement +#if defined i_implement #ifndef CSVIEW_C_INCLUDED #define CSVIEW_C_INCLUDED diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 3213dd1c..6806e2bc 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -40,7 +40,7 @@ struct MyStruct { #include #define i_key int -#define i_is_forward // forward declared +#define i_is_forward #define i_tag i32 #include @@ -85,10 +85,10 @@ STC_API bool _cx_MEMB(_resize)(_cx_Self* self, intptr_t size, i_key n STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); STC_API _cx_iter _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n); STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n); -#if !defined i_no_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw); #endif -#ifndef i_no_cmp +#if defined _i_has_cmp STC_API int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y); STC_API _cx_iter _cx_MEMB(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound); #endif @@ -214,7 +214,7 @@ STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) { self->_len += n; } -#if !defined i_no_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp STC_INLINE _cx_iter _cx_MEMB(_find)(const _cx_Self* self, _cx_raw raw) { @@ -240,7 +240,7 @@ _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { return true; } #endif -#ifndef i_no_cmp +#if defined _i_has_cmp STC_INLINE _cx_iter _cx_MEMB(_binary_search)(const _cx_Self* self, _cx_raw raw) { @@ -265,7 +265,7 @@ STC_INLINE void _cx_MEMB(_sort)(_cx_Self* self) { _cx_MEMB(_sort_range)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), _cx_MEMB(_value_cmp)); } -#endif // !c_no_cmp +#endif // _i_has_cmp /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) @@ -378,7 +378,7 @@ _cx_MEMB(_emplace_n)(_cx_Self* self, const intptr_t idx, const _cx_raw raw[], in return it; } #endif // !i_no_emplace -#if !defined i_no_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp STC_DEF _cx_iter _cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { @@ -392,7 +392,7 @@ _cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { return i2; } #endif -#ifndef i_no_cmp +#if defined _i_has_cmp STC_DEF _cx_iter _cx_MEMB(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw, @@ -417,7 +417,7 @@ STC_DEF int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y) { const _cx_raw ry = i_keyto(y); return i_cmp((&rx), (&ry)); } -#endif // !c_no_cmp +#endif // _i_has_cmp #endif // i_implement #define CVEC_H_INCLUDED #include "priv/template2.h" diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index c1b7c1e7..03c27bdb 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -102,12 +102,6 @@ #if c_option(c_no_emplace) #define i_no_emplace #endif -#ifdef i_eq - #define _i_has_eq -#endif -#if defined i_cmp || defined i_less - #define _i_has_cmp -#endif #if defined i_key_str #define i_keyclass cstr @@ -155,10 +149,10 @@ #endif #ifdef i_rawclass - #if !defined i_cmp && !defined i_no_cmp + #if !(defined i_cmp || defined i_no_cmp) #define i_cmp c_PASTE(i_keyraw, _cmp) #endif - #if !defined i_hash && !defined i_no_hash + #if !(defined i_hash || defined i_no_hash || defined i_no_cmp) #define i_hash c_PASTE(i_keyraw, _hash) #endif #endif @@ -176,7 +170,7 @@ #ifndef i_tag #define i_tag i_key #endif -#if c_option(c_no_clone) +#if c_option(c_no_clone) || defined _i_carc #define i_no_clone #elif !(defined i_keyclone || defined i_no_clone) && (defined i_keydrop || defined i_keyraw) #error i_keyclone/valclone should be defined when i_keydrop/valdrop or i_keyraw/valraw is defined @@ -199,24 +193,33 @@ #define i_keydrop c_default_drop #endif -// i_eq, i_less, i_cmp -#if !defined i_eq && (defined i_cmp || defined i_less) - #define i_eq(x, y) !(i_cmp(x, y)) -#elif !defined i_eq - #define i_eq c_default_eq -#endif -#if defined i_less && defined i_cmp - #error "Only one of i_less and i_cmp may be defined" -#elif !defined i_less && !defined i_cmp - #define i_less c_default_less -#elif !defined i_less - #define i_less(x, y) (i_cmp(x, y)) < 0 -#endif -#ifndef i_cmp - #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y)) +#ifndef i_no_cmp + #if c_option(c_native_cmp) || defined i_native_cmp || defined i_cmp || defined i_less + #define _i_has_cmp + #endif + #if defined i_eq + #define _i_has_eq + #endif + + // i_eq, i_less, i_cmp + #if !defined i_eq && (defined i_cmp || defined i_less) + #define i_eq(x, y) !(i_cmp(x, y)) + #elif !defined i_eq + #define i_eq(x, y) *x == *y + #endif + #if defined i_cmp && defined i_less + #error "Only one of i_cmp and i_less may be defined" + #elif defined i_cmp + #define i_less(x, y) (i_cmp(x, y)) < 0 + #elif !defined i_less + #define i_less(x, y) *x < *y + #endif + #ifndef i_cmp + #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y)) + #endif #endif -#ifndef i_hash +#if !(defined i_hash || defined _i_cbox || defined _i_carc) #define i_hash c_default_hash #endif diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 47b82937..bd8bc5fc 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -67,6 +67,7 @@ #undef i_realloc #undef i_free +#undef i_native_cmp #undef i_no_cmp #undef i_no_hash #undef i_no_clone @@ -74,9 +75,9 @@ #undef i_is_forward #undef i_has_emplace +#undef _i_has_cmp +#undef _i_has_eq #undef _i_prefix #undef _i_expandby -#undef _i_has_eq -#undef _i_has_cmp #undef _i_template #endif diff --git a/misc/examples/arc_containers.c b/misc/examples/arc_containers.c index 7038734e..b05bbea6 100644 --- a/misc/examples/arc_containers.c +++ b/misc/examples/arc_containers.c @@ -13,17 +13,15 @@ #define i_val Map #define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p)) // no need for atomic ref. count in single thread: -#define i_opt c_no_atomic|c_no_cmp|c_no_clone +#define i_opt c_no_atomic #include #define i_type Stack #define i_valboxed Arc // define i_valboxed for carc/cbox value (not i_val) -#define i_opt c_no_cmp #include #define i_type List #define i_valboxed Arc // as above -#define i_opt c_no_cmp #include int main() diff --git a/misc/examples/arc_demo.c b/misc/examples/arc_demo.c index 2339adbb..4cda1c8b 100644 --- a/misc/examples/arc_demo.c +++ b/misc/examples/arc_demo.c @@ -11,13 +11,13 @@ void int_drop(int* x) { #define i_type Arc // set type name to be defined (instead of 'carc_int') #define i_val int #define i_valdrop int_drop // optional, just to display the elements destroyed -#define i_no_clone // required because of valdrop +#define i_native_cmp // use int comparison (x < y, x == y). #include // Arc -#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements +#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements #include // csset_Arc (like: std::set>) -#define i_valboxed Arc // note: as above. +#define i_valboxed Arc // note: as above. #include // cvec_Arc (like: std::vector>) int main() @@ -25,8 +25,12 @@ int main() const int years[] = {2021, 2012, 2022, 2015}; cvec_Arc vec = {0}; - c_forrange (i, c_arraylen(years)) - cvec_Arc_push(&vec, Arc_from(years[i])); + c_forrange (i, c_arraylen(years)) { + cvec_Arc_emplace(&vec, years[i]); + // cvec_Arc_push(&vec, Arc_from(years[i])); // alt. + } + + cvec_Arc_sort(&vec); printf("vec:"); c_foreach (i, cvec_Arc, vec) diff --git a/misc/examples/arcvec_erase.c b/misc/examples/arcvec_erase.c index 28160c1c..0b9252d9 100644 --- a/misc/examples/arcvec_erase.c +++ b/misc/examples/arcvec_erase.c @@ -5,7 +5,7 @@ void show_drop(int* x) { printf("drop: %d\n", *x); } #define i_type Arc #define i_val int #define i_valdrop show_drop -#define i_no_clone // required because of valdrop +#define i_native_cmp // enable sort/search for int type #include // Shared pointer to int #define i_type Vec diff --git a/misc/examples/box2.c b/misc/examples/box2.c index 963a3815..d3762462 100644 --- a/misc/examples/box2.c +++ b/misc/examples/box2.c @@ -15,16 +15,14 @@ typedef struct { } Rectangle; #define i_val Point -#define i_no_cmp #include // cbox_Point #define i_val Rectangle -#define i_no_cmp #include // cbox_Rectangle // Box in box: -#define i_valboxed cbox_Point // NB: use i_valboxed when value is a cbox or carc! #define i_type BoxBoxPoint +#define i_valboxed cbox_Point // NB: use i_valboxed when value is a cbox or carc! #define i_no_cmp #include // BoxBoxPoint diff --git a/misc/examples/complex.c b/misc/examples/complex.c index 2d8dbf62..b5ea847a 100644 --- a/misc/examples/complex.c +++ b/misc/examples/complex.c @@ -13,8 +13,8 @@ #include #define i_type StackList -#define i_valclass FloatStack // "class" picks up _clone, _drop -#define i_opt c_no_cmp // no FloatStack_cmp() +#define i_valclass FloatStack // "class" picks up _clone, _drop, _cmp +#define i_opt c_no_cmp // exclude FloatStack_cmp(): not defined #include #define i_type ListMap diff --git a/misc/examples/csmap_find.c b/misc/examples/csmap_find.c index c123e398..645828a3 100644 --- a/misc/examples/csmap_find.c +++ b/misc/examples/csmap_find.c @@ -9,7 +9,6 @@ #include #define i_val csmap_istr_raw -#define i_opt c_no_cmp #define i_tag istr #include diff --git a/misc/examples/demos.c b/misc/examples/demos.c index 8488dfb9..b2f50ebf 100644 --- a/misc/examples/demos.c +++ b/misc/examples/demos.c @@ -74,6 +74,7 @@ void vectordemo2() #define i_val int #define i_tag ix +#define i_native_cmp #include void listdemo1() diff --git a/misc/examples/intrusive.c b/misc/examples/intrusive.c index 0d503575..0d59c5ab 100644 --- a/misc/examples/intrusive.c +++ b/misc/examples/intrusive.c @@ -4,7 +4,8 @@ #define i_type List #define i_val int -#include +#define i_native_cmp +#include void printList(List list) { printf("list:"); @@ -16,7 +17,7 @@ void printList(List list) { int main() { List list = {0}; c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8}) - List_push_back_node(&list, c_new(List_node, {0, *i.ref})); + List_push_back_node(&list, c_new(List_node, {.value=*i.ref})); printList(list); diff --git a/misc/examples/list.c b/misc/examples/list.c index ed27aa50..08fe837f 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -5,6 +5,7 @@ #define i_type DList #define i_val double +#define i_native_cmp #include int main() { diff --git a/misc/examples/lower_bound.c b/misc/examples/lower_bound.c index d146c4d9..5b395e45 100644 --- a/misc/examples/lower_bound.c +++ b/misc/examples/lower_bound.c @@ -1,6 +1,7 @@ #include #define i_val int +#define i_native_cmp #include #define i_val int diff --git a/misc/examples/music_arc.c b/misc/examples/music_arc.c index 18ea30c0..4efc35c8 100644 --- a/misc/examples/music_arc.c +++ b/misc/examples/music_arc.c @@ -23,13 +23,13 @@ void Song_drop(Song* s) { // Define the shared pointer: #define i_type SongArc #define i_valclass Song -#define i_opt c_no_hash // arc require hash fn, disable as we don't need it. +#define i_no_hash // no hash fn for Song, fallback hash pointer to Song. #include // ... and a vector of them #define i_type SongVec -#define i_valboxed SongArc // use i_valboxed on carc / cbox instead of i_val -#include +#define i_valboxed SongArc // use i_valboxed on carc / cbox (instead of i_val) +#include void example3() { diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index 382943bb..b5ff847e 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -27,12 +27,13 @@ int point_cmp(const Point* a, const Point* b) { #include #define i_val float +#define i_native_cmp // use < and == operators for comparison #include void MyStruct_drop(MyStruct* s); #define i_type MyList -#define i_valclass MyStruct // i_valclass uses MyStruct_drop -#define i_opt c_no_clone|c_no_cmp +#define i_valclass MyStruct // MyStruct contains "class"-types, so define as "class" +#define i_opt c_no_clone|c_no_cmp // exclude cloning and comparison support #include void MyStruct_drop(MyStruct* s) { diff --git a/misc/examples/new_sptr.c b/misc/examples/new_sptr.c index 36a61f9c..2eff41a5 100644 --- a/misc/examples/new_sptr.c +++ b/misc/examples/new_sptr.c @@ -9,15 +9,13 @@ int Person_cmp(const Person* a, const Person* b); uint64_t Person_hash(const Person* p); #define i_type PersonArc -#define i_valclass Person // "class" ensure Person_drop will be called -#define i_cmp Person_cmp // enable carc object comparisons (not ptr to obj) -#define i_hash Person_hash // enable carc object hash (not ptr to obj) +#define i_valclass Person // "class" assume _clone, _drop, _cmp, _hash is defined. #include #define i_type IPtr #define i_val int #define i_valdrop(x) printf("drop: %d\n", *x) -#define i_no_clone +#define i_native_cmp #include #define i_type IPStack diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c index e10910d9..6329b185 100644 --- a/misc/examples/new_vec.c +++ b/misc/examples/new_vec.c @@ -10,16 +10,17 @@ typedef struct MyStruct { } MyStruct; #define i_val int -#define i_is_forward #define i_tag i32 +#define i_is_forward #include typedef struct Point { int x, y; } Point; #define i_val Point +#define i_tag pnt #define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) +#define i_eq(a, b) a->x == b->x && a->y == b->y #define i_is_forward -#define i_tag pnt #include int main() diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index 59101b4e..04f7ba4a 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -8,7 +8,6 @@ cco_closure(bool, Task, #define i_type Scheduler #define i_val struct Task -#define i_no_cmp #include static bool schedule(Scheduler* sched) -- cgit v1.2.3 From fc43b14f706f22e3933b3d225819ea68f7ce2679 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Thu, 29 Jun 2023 10:59:05 +0200 Subject: better variable names in list example. --- misc/examples/new_list.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index b5ff847e..8083c315 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -5,8 +5,8 @@ forward_clist(clist_i32, int); forward_clist(clist_pnt, struct Point); typedef struct { - clist_i32 intlst; - clist_pnt pntlst; + clist_i32 intlist; + clist_pnt pntlist; } MyStruct; #define i_val int @@ -37,33 +37,33 @@ void MyStruct_drop(MyStruct* s); #include void MyStruct_drop(MyStruct* s) { - clist_i32_drop(&s->intlst); - clist_pnt_drop(&s->pntlst); + clist_i32_drop(&s->intlist); + clist_pnt_drop(&s->pntlist); } int main() { MyStruct my = {0}; - clist_i32_push_back(&my.intlst, 123); - clist_pnt_push_back(&my.pntlst, c_LITERAL(Point){123, 456}); + clist_i32_push_back(&my.intlist, 123); + clist_pnt_push_back(&my.pntlist, c_LITERAL(Point){123, 456}); MyStruct_drop(&my); - clist_pnt plst = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); - clist_pnt_sort(&plst); + clist_pnt plist = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); + clist_pnt_sort(&plist); - c_foreach (i, clist_pnt, plst) + c_foreach (i, clist_pnt, plist) printf(" (%d %d)", i.ref->x, i.ref->y); puts(""); - clist_pnt_drop(&plst); + clist_pnt_drop(&plist); - clist_float flst = c_init(clist_float, {123.3f, 321.2f, -32.2f, 78.2f}); - clist_float_sort(&flst); + clist_float flist = c_init(clist_float, {123.3f, 321.2f, -32.2f, 78.2f}); + clist_float_sort(&flist); - c_foreach (i, clist_float, flst) + c_foreach (i, clist_float, flist) printf(" %g", (double)*i.ref); puts(""); - clist_float_drop(&flst); + clist_float_drop(&flist); } -- cgit v1.2.3 From e25dec033773ab713a7593a923e2c83745be0b9a Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 2 Jul 2023 22:01:46 +0200 Subject: Update in coroutine API. cco_yield, cco_await, cco_await_on, cco_block_on has changed. cco_final: renamed => cco_cleanup: Reverted i_retain template param back to => i_more. --- docs/ccommon_api.md | 62 +++++++++++------- include/stc/algo/coroutine.h | 120 ++++++++++++++++++++-------------- include/stc/algo/sort.h | 2 +- include/stc/cdeq.h | 6 +- include/stc/priv/template2.h | 4 +- misc/benchmarks/various/csort_bench.c | 2 +- misc/examples/cointerleave.c | 11 ++-- misc/examples/coread.c | 7 +- misc/examples/coroutines.c | 54 +++++++-------- misc/examples/dining_philosophers.c | 16 +++-- misc/examples/generator.c | 5 +- misc/examples/scheduler.c | 34 +++++----- misc/examples/triples.c | 10 +-- 13 files changed, 189 insertions(+), 144 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index c9c65156..b30bdda6 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -222,11 +222,11 @@ int main() { } ``` Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is -possible and very fast. Note that `i_retain` must be defined to retain specified template parameters for use by sort: +possible and very fast. Note that `i_more` must be defined to retain specified template parameters for use by sort: ```c #define i_type MyDeq #define i_val int -#define i_retain +#define i_more #include // deque #include #include @@ -313,6 +313,7 @@ the gcd() function. It also ensures that it stops when the diagonal size >= 100: [ [Run this code](https://godbolt.org/z/coqqrfbd5) ] ```c #include +#include struct triples { int n; // input: max number of triples to be generated. @@ -320,22 +321,23 @@ struct triples { int cco_state; // required member }; -bool triples(struct triples* i) { // coroutine +int triples(struct triples* i) { // coroutine cco_routine(i) { for (i->c = 5; i->n; ++i->c) { for (i->a = 1; i->a < i->c; ++i->a) { for (i->b = i->a + 1; i->b < i->c; ++i->b) { if ((int64_t)i->a*i->a + (int64_t)i->b*i->b == (int64_t)i->c*i->c) { - cco_yield(false); - if (--i->n == 0) cco_return; + cco_yield(); + if (--i->n == 0) + cco_return; } } } } - cco_final: + cco_cleanup: puts("done"); } - return true; + return 0; } int gcd(int a, int b) { // greatest common denominator @@ -352,7 +354,7 @@ int main() struct triples t = {.n=INT32_MAX}; int n = 0; - while (!triples(&t)) { + while (triples(&t)) { // Skip triples with GCD(a,b) > 1 if (gcd(t.a, t.b) > 1) continue; @@ -366,28 +368,36 @@ int main() } ``` ### Coroutine API -**Note**: *cco_yield()* may not be called inside a `switch` statement. Use `if-else-if` constructs instead. -To resume the coroutine from where it was suspended with *cco_yield()*, simply call the coroutine again. +To resume the coroutine from where it was suspended with *cco_yield()*: call the coroutine again. + +**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement; either use +`if-else-if` constructs, or `cco_switch / cco_case / cco_default` for switch-emulation instead. | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| -| | `cco_final:` | Label for cleanup in coroutine | +| | Function / 'keywords': | | +|`cco_result` | Enum `CCO_DONE=0`, `CCO_YIELD`, `CCO_AWAIT` | Recommended return values in coroutines | +| | Function / 'keywords': | | +| | `cco_cleanup:` | Label for cleanup position in coroutine | | `bool` | `cco_done(co)` | Is coroutine done? | -| | `cco_routine(co) { ... }` | The coroutine closure | -| | `cco_yield()` | Yield/suspend execution | -| | `cco_yield(ret)` | Yield/suspend execution and return ret | -| | `cco_await(promise)` | Await/suspend until promise is true | -| | `cco_await(promise, ret)` | Await/suspend with ret value | -| | `cco_return` | Replaces return. Jump to cco_final: if exist| -| | `cco_return_v(val)` | Yield final value, enter final-state | -| | `cco_closure(Ret, Closure, ...)` | Define coroutine closure struct. | -| `void` | `cco_await_on(closure) { }` | Await on closure to finish | -| `void` | `cco_await_on(co, func) { }` | Await on func(co) to finish | +| | `cco_routine(co) { }` | The coroutine scope | +| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)| +| | `cco_yield_v();` | Yield/suspend execution (return void) | +| | `cco_yield_v(ret);` | Yield/suspend execution (return ret) | +| | `cco_yield_final();` | Yield final time, enables cleanup-state | +| | `cco_yield_final(val);` | Yield a final value (e.g. CCO_ERROR) | +| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| +| | `cco_await_v(condition);` | Suspend until condition is true (return void) | +| | `cco_await_v(condition, ret);` | Suspend until condition is true (return ret)| +| | `cco_await_on(cocall);` | Await on sub-coroutine to finish | +| | `cco_return;` | Return from coroutine (inside cco_routine) | +| | `cco_closure(Closure, ...);` | Define a coroutine closure struct (optional) | | | Semaphores: | | | | `cco_sem` | Semaphore type | +| `cco_sem` | `cco_sem_from(long value)` | Create semaphore | +| | `cco_sem_set(sem, long value)` | Set semaphore value | | | `cco_sem_await(sem)` | Await for the semaphore count > 0 | | | `cco_sem_await(sem, ret)` | Await with ret on the semaphore | -| `cco_sem` | `cco_sem_init(long value)` | Set semaphore value | | | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | | | Timers: | | | | `cco_timer` | Timer type | @@ -401,11 +411,15 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_block_on(closure) { }` | Run blocking until closure is finished | -| `void` | `cco_block_on(co, func) { }` | Run blocking until func is finished | +| `void` | `cco_block_on(cocall) { }` | Run blocking until cocall is finished | +| `void` | `cco_block_on(cocall, int *result) { }`| Run blocking until cocall is finished | | | Time functions: | | | `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | | | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | +| | Emulate switch: | | +| | `cco_switch(x) { }` | Like switch syntax | +| | `cco_case(val) { }` | Braces are required. Fall-through if no break; | +| | `cco_default { }` | Default action | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index e20fd8ad..198b0439 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -32,22 +32,22 @@ struct iterpair { int cco_state; // required member }; -bool iterpair(struct iterpair* I) { +int iterpair(struct iterpair* I) { cco_routine(I) { for (I->x = 0; I->x < I->max_x; I->x++) for (I->y = 0; I->y < I->max_y; I->y++) - cco_yield(false); + cco_yield(); - cco_final: // required if there is cleanup code + cco_cleanup: // required if there is cleanup code puts("final"); } - return true; // finished + return 0; // CCO_DONE } int main(void) { struct iterpair it = {.max_x=3, .max_y=3}; int n = 0; - while (!iterpair(&it)) + while (iterpair(&it)) { printf("%d %d\n", it.x, it.y); // example of early stop: @@ -59,12 +59,19 @@ int main(void) { #include "../ccommon.h" enum { - cco_state_final = -1, - cco_state_done = -2, + CCO_STATE_CLEANUP = -1, + CCO_STATE_DONE = -2, }; +typedef enum { + CCO_DONE = 0, + CCO_YIELD = 1, + CCO_AWAIT = 2, + CCO_ERROR = -1, +} cco_result; #define cco_initial(co) ((co)->cco_state == 0) -#define cco_done(co) ((co)->cco_state == cco_state_done) +#define cco_suspended(co) ((co)->cco_state > 0) +#define cco_done(co) ((co)->cco_state == CCO_STATE_DONE) /* Emulate switch in coro: always use { } after cco_case(val) and cco_default. */ #define cco_switch(x) for (long long _sw = (long long)(x), _b=0; !_b; _b=1) @@ -72,83 +79,97 @@ enum { #define cco_default #define cco_routine(co) \ - for (int *_state = &(co)->cco_state; *_state != cco_state_done; *_state = cco_state_done) \ + for (int *_state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ _resume: switch (*_state) case 0: // thanks, @liigo! -#define cco_yield(ret) \ +#define cco_yield() cco_yield_v(CCO_YIELD) +#define cco_yield_v(ret) \ do { \ *_state = __LINE__; return ret; goto _resume; \ case __LINE__:; \ } while (0) -#define cco_await(...) c_MACRO_OVERLOAD(cco_await, __VA_ARGS__) -#define cco_await_1(promise) cco_await_2(promise, ) -#define cco_await_2(promise, ret) \ +#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT) +#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__) +#define cco_await_v_1(promise) cco_await_v_2(promise, ) +#define cco_await_v_2(promise, ret) \ do { \ *_state = __LINE__; \ case __LINE__: if (!(promise)) {return ret; goto _resume;} \ } while (0) -#define cco_closure(Ret, Closure, ...) \ - struct Closure { \ - Ret (*cco_fn)(struct Closure*); \ - int cco_state; \ - __VA_ARGS__ \ - } - -typedef struct cco_base { - void (*cco_fn)(struct cco_base*); - int cco_state; -} cco_base; - -#define cco_base_cast(closure) \ - ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state))) - -#define cco_resume(closure) (closure)->cco_fn(closure) -#define cco_await_on(...) c_MACRO_OVERLOAD(cco_await_on, __VA_ARGS__) -#define cco_await_on_1(closure) cco_await_2((cco_resume(closure), cco_done(closure)), ) -#define cco_await_on_2(co, func) cco_await_2((func(co), cco_done(co)), ) +/* cco_await_on(): assumes coroutine returns a cco_result value (int) */ +#define cco_await_on(corocall) \ + do { \ + *_state = __LINE__; \ + case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \ + } while (0) +/* cco_block_on(): assumes coroutine returns a cco_result value (int) */ #define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) -#define cco_block_on_1(closure) while (cco_resume(closure), !cco_done(closure)) -#define cco_block_on_2(co, func) while (func(co), !cco_done(co)) +#define cco_block_on_1(corocall) while (corocall != CCO_DONE) +#define cco_block_on_2(corocall, res) while ((*(res) = (corocall)) != CCO_DONE) -#define cco_final \ - *_state = cco_state_final; case cco_state_final +#define cco_cleanup \ + *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP #define cco_return \ do { \ - *_state = *_state >= 0 ? cco_state_final : cco_state_done; \ + *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ goto _resume; \ } while (0) -#define cco_return_v(value) \ +#define cco_yield_final() cco_yield_final_v(CCO_YIELD) +#define cco_yield_final_v(value) \ do { \ - *_state = *_state >= 0 ? cco_state_final : cco_state_done; \ + *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ return value; \ } while (0) #define cco_stop(co) \ do { \ int* _s = &(co)->cco_state; \ - if (*_s > 0) *_s = cco_state_final; \ - else if (*_s == 0) *_s = cco_state_done; \ + if (*_s > 0) *_s = CCO_STATE_CLEANUP; \ + else if (*_s == 0) *_s = CCO_STATE_DONE; \ } while (0) #define cco_reset(co) \ (void)((co)->cco_state = 0) +/* + * Closure (optional) + */ + +#define cco_closure(Name, ...) \ + struct Name { \ + int (*cco_fn)(struct Name*); \ + int cco_state; \ + __VA_ARGS__ \ + } + +typedef struct cco_base { + int (*cco_fn)(struct cco_base*); + int cco_state; +} cco_base; + +#define cco_resume(closure) \ + (closure)->cco_fn(closure) + +#define cco_cast(closure) \ + ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state))) + /* * Semaphore */ typedef struct { intptr_t count; } cco_sem; -#define cco_sem_await(...) c_MACRO_OVERLOAD(cco_sem_await, __VA_ARGS__) -#define cco_sem_await_1(sem) cco_sem_await_2(sem, ) -#define cco_sem_await_2(sem, ret) \ +#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT) +#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__) +#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, ) +#define cco_sem_await_v_2(sem, ret) \ do { \ - cco_await_2((sem)->count > 0, ret); \ + cco_await_v_2((sem)->count > 0, ret); \ --(sem)->count; \ } while (0) @@ -197,12 +218,13 @@ typedef struct { intptr_t count; } cco_sem; typedef struct { double interval, start; } cco_timer; -#define cco_timer_await(...) c_MACRO_OVERLOAD(cco_timer_await, __VA_ARGS__) -#define cco_timer_await_2(tm, sec) cco_timer_await_3(tm, sec, ) -#define cco_timer_await_3(tm, sec, ret) \ +#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT) +#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__) +#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, ) +#define cco_timer_await_v_3(tm, sec, ret) \ do { \ cco_timer_start(tm, sec); \ - cco_await_2(cco_timer_expired(tm), ret); \ + cco_await_v_2(cco_timer_expired(tm), ret); \ } while (0) static inline void cco_timer_start(cco_timer* tm, double sec) { diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h index 002e6499..8365ccc5 100644 --- a/include/stc/algo/sort.h +++ b/include/stc/algo/sort.h @@ -44,7 +44,7 @@ int main() { // ex2: #define i_val int #define i_type IDeq -#define i_retain // retain input template params to be reused by sort.h +#define i_more // retain input template params to be reused by sort.h #include #include diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 2db040f1..bac40f90 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -23,11 +23,11 @@ #define _i_prefix cdeq_ #define _pop _pop_front #define _pull _pull_front -#ifdef i_retain +#ifdef i_more #include "cqueue.h" - #define i_retain + #define i_more #else - #define i_retain + #define i_more #include "cqueue.h" #endif #undef _pop diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index bd8bc5fc..def5d01e 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -20,8 +20,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifdef i_retain -#undef i_retain +#ifdef i_more +#undef i_more #else #undef i_type #undef i_tag diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c index 93034dde..d434693f 100644 --- a/misc/benchmarks/various/csort_bench.c +++ b/misc/benchmarks/various/csort_bench.c @@ -8,7 +8,7 @@ #define NDEBUG #define i_type Ints #define i_val int -#define i_retain +#define i_more #include #include diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 1ba7b861..61562a5f 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -15,7 +15,7 @@ static int get_value(struct GenValue* g) { cco_routine(g) { for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) - cco_yield(*g->it.ref); + cco_yield_v(*g->it.ref); } return -1; } @@ -26,10 +26,10 @@ struct Generator { int value; }; -void interleaved(struct Generator* g) +cco_result interleaved(struct Generator* g) { cco_routine(g) { - do { + while (!(cco_done(&g->x) & cco_done(&g->y))) { g->value = get_value(&g->x); if (!cco_done(&g->x)) cco_yield(); @@ -37,8 +37,9 @@ void interleaved(struct Generator* g) g->value = get_value(&g->y); if (!cco_done(&g->y)) cco_yield(); - } while (!(cco_done(&g->x) & cco_done(&g->y))); + } } + return CCO_DONE; } void Use(void) @@ -48,7 +49,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - cco_block_on(&g, interleaved) { + cco_block_on(interleaved(&g)) { printf("%d ", g.value); } puts(""); diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 622228c0..a13f6be5 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -12,7 +12,7 @@ struct file_read { cstr line; }; -void file_read(struct file_read* g) +int file_read(struct file_read* g) { cco_routine(g) { g->fp = fopen(g->filename, "r"); @@ -21,18 +21,19 @@ void file_read(struct file_read* g) cco_await(!cstr_getline(&g->line, g->fp)); - cco_final: + cco_cleanup: printf("finish\n"); cstr_drop(&g->line); if (g->fp) fclose(g->fp); } + return 0; } int main(void) { struct file_read g = {__FILE__}; int n = 0; - cco_block_on(&g, file_read) + cco_block_on(file_read(&g)) { printf("%3d %s\n", ++n, cstr_str(&g.line)); //if (n == 10) cco_stop(&g); diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 1e900fa1..b8dfaa13 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -4,27 +4,26 @@ // Demonstrate to call another coroutine from a coroutine: // First create prime generator, then call fibonacci sequence: -typedef long long llong; -bool is_prime(int64_t i) { - for (llong j=2; j*j <= i; ++j) +bool is_prime(long long i) { + for (long long j=2; j*j <= i; ++j) if (i % j == 0) return false; return true; } struct prime { int count, idx; - llong result, pos; + long long result, pos; int cco_state; }; -bool prime(struct prime* g) { +int prime(struct prime* g) { cco_routine(g) { if (g->result < 2) g->result = 2; if (g->result == 2) { if (g->count-- == 0) cco_return; ++g->idx; - cco_yield(false); + cco_yield(); } g->result += !(g->result & 1); for (g->pos = g->result; g->count > 0; g->pos += 2) { @@ -32,13 +31,13 @@ bool prime(struct prime* g) { --g->count; ++g->idx; g->result = g->pos; - cco_yield(false); + cco_yield(); } } - cco_final: + cco_cleanup: printf("final prm\n"); } - return true; + return 0; } @@ -46,13 +45,14 @@ bool prime(struct prime* g) { struct fibonacci { int count, idx; - llong result, b; + long long result, b; int cco_state; }; -bool fibonacci(struct fibonacci* g) { +int fibonacci(struct fibonacci* g) { assert(g->count < 94); + long long sum; cco_routine(g) { g->idx = 0; g->result = 0; @@ -61,17 +61,17 @@ bool fibonacci(struct fibonacci* g) { if (g->count-- == 0) cco_return; if (++g->idx > 1) { - // NB! locals lasts only until next cco_yield/cco_await! - llong sum = g->result + g->b; + // NB! locals lasts only until next yield/await! + sum = g->result + g->b; g->result = g->b; g->b = sum; } - cco_yield(false); + cco_yield(); } - cco_final: + cco_cleanup: printf("final fib\n"); } - return true; + return 0; } // Combine @@ -82,29 +82,31 @@ struct combined { int cco_state; }; - -void combined(struct combined* g) { +int combined(struct combined* g) { cco_routine(g) { - cco_await(prime(&g->prm)); - cco_await(fibonacci(&g->fib)); + cco_await_on(prime(&g->prm)); + cco_await_on(fibonacci(&g->fib)); // Reuse the g->prm context and extend the count: g->prm.count = 8, g->prm.result += 2; cco_reset(&g->prm); - cco_await(prime(&g->prm)); + cco_await_on(prime(&g->prm)); - cco_final: + cco_cleanup: puts("final combined"); } + return 0; } int main(void) { struct combined c = {.prm={.count=8}, .fib={14}}; + int res; - cco_block_on(&c, combined) { - printf("Prime(%d)=%lld, Fib(%d)=%lld\n", - c.prm.idx, c.prm.result, - c.fib.idx, c.fib.result); + cco_block_on(combined(&c), &res) { + if (res == CCO_YIELD) + printf("Prime(%d)=%lld, Fib(%d)=%lld\n", + c.prm.idx, c.prm.result, + c.fib.idx, c.fib.result); } } diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c index e13eb055..61fe67fb 100644 --- a/misc/examples/dining_philosophers.c +++ b/misc/examples/dining_philosophers.c @@ -27,7 +27,7 @@ struct Dining { // Philosopher coroutine -void philosopher(struct Philosopher* p) +int philosopher(struct Philosopher* p) { double duration; cco_routine(p) { @@ -48,14 +48,15 @@ void philosopher(struct Philosopher* p) cco_sem_release(p->right_fork); } - cco_final: + cco_cleanup: printf("Philosopher %d finished\n", p->id); } + return 0; } // Dining coroutine -void dining(struct Dining* d) +int dining(struct Dining* d) { cco_routine(d) { for (int i = 0; i < num_forks; ++i) @@ -68,20 +69,21 @@ void dining(struct Dining* d) } while (1) { - // per-"frame" logic update of all philosophers states + // per-"frame" logic resume each philosopher for (int i = 0; i < num_philosophers; ++i) { philosopher(&d->ph[i]); } cco_yield(); // suspend, return control back to main } - cco_final: + cco_cleanup: for (int i = 0; i < num_philosophers; ++i) { cco_stop(&d->ph[i]); philosopher(&d->ph[i]); } puts("Dining finished"); } + return 0; } int main() @@ -89,13 +91,13 @@ int main() struct Dining dine; cco_reset(&dine); int n=0; - cco_timer tm = cco_timer_from(10.0); // seconds + cco_timer tm = cco_timer_from(15.0); // seconds csrand((uint64_t)time(NULL)); while (!cco_done(&dine)) { if (cco_timer_expired(&tm)) cco_stop(&dine); - dining(&dine); + dining(&dine); // resume cco_sleep(0.001); ++n; } diff --git a/misc/examples/generator.c b/misc/examples/generator.c index 6b4b8407..3ff7a645 100644 --- a/misc/examples/generator.c +++ b/misc/examples/generator.c @@ -14,7 +14,7 @@ typedef struct { int cco_state; } Triple_iter; -void Triple_next(Triple_iter* it) { +int Triple_next(Triple_iter* it) { Triple_value* g = it->ref; cco_routine(it) { @@ -29,9 +29,10 @@ void Triple_next(Triple_iter* it) { } } } - cco_final: + cco_cleanup: it->ref = NULL; } + return 0; } Triple_iter Triple_begin(Triple* g) { diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index 04f7ba4a..c1168850 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -2,9 +2,11 @@ #include #include -cco_closure(bool, Task, +struct Task { + int (*fn)(struct Task*); + int cco_state; struct Scheduler* sched; -); +}; #define i_type Scheduler #define i_val struct Task @@ -16,49 +18,49 @@ static bool schedule(Scheduler* sched) Scheduler_pop(sched); if (!cco_done(&task)) - cco_resume(&task); + task.fn(&task); return !Scheduler_empty(sched); } -static bool push_task(const struct Task* task) +static int push_task(const struct Task* task) { Scheduler_push(task->sched, *task); - return false; + return CCO_YIELD; } -static bool taskA(struct Task* task) +static int taskA(struct Task* task) { cco_routine(task) { puts("Hello, from task A"); - cco_yield(push_task(task)); + cco_yield_v(push_task(task)); puts("A is back doing work"); - cco_yield(push_task(task)); + cco_yield_v(push_task(task)); puts("A is back doing more work"); - cco_yield(push_task(task)); + cco_yield_v(push_task(task)); puts("A is back doing even more work"); } - return true; + return 0; } -static bool taskB(struct Task* task) +static int taskB(struct Task* task) { cco_routine(task) { puts("Hello, from task B"); - cco_yield(push_task(task)); + cco_yield_v(push_task(task)); puts("B is back doing work"); - cco_yield(push_task(task)); + cco_yield_v(push_task(task)); puts("B is back doing more work"); } - return true; + return 0; } void Use(void) { Scheduler scheduler = c_init(Scheduler, { - {.cco_fn=taskA, .sched=&scheduler}, - {.cco_fn=taskB, .sched=&scheduler}, + {.fn=taskA, .sched=&scheduler}, + {.fn=taskB, .sched=&scheduler}, }); while (schedule(&scheduler)) {} diff --git a/misc/examples/triples.c b/misc/examples/triples.c index 17e3d40b..a8ca6b47 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -32,7 +32,7 @@ struct triples { int cco_state; }; -void triples_coro(struct triples* t) { +int triples_coro(struct triples* t) { cco_routine(t) { t->count = 0; for (t->c = 5; t->size; ++t->c) { @@ -46,9 +46,10 @@ void triples_coro(struct triples* t) { } } } - cco_final: + cco_cleanup: puts("done"); } + return 0; } int main() @@ -57,11 +58,10 @@ int main() triples_vanilla(5); puts("\nCoroutine triples:"); - struct triples t = {INT32_MAX}; + struct triples t = {.size=INT32_MAX}; int n = 0; - while (!cco_done(&t)) { - triples_coro(&t); + while (triples_coro(&t)) { if (gcd(t.a, t.b) > 1) continue; if (t.c < 100) -- cgit v1.2.3 From 433e6fd36912d1c584fbf206f99a3a982b29e9dc Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 3 Jul 2023 07:22:25 +0200 Subject: Simplified extend.h a bit. --- include/stc/extend.h | 5 ++++- misc/examples/functor.c | 33 ++++++++++++++++----------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/include/stc/extend.h b/include/stc/extend.h index f9ac92bf..c0a00ff8 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -54,7 +54,10 @@ typedef struct { i_type get; } c_PASTE(i_type, _ext); -#define c_extend(self) c_container_of(self, _cx_MEMB(_ext), get) +#define c_extend() c_container_of(self, _cx_MEMB(_ext), get) +// Note: i_less: c_extend() accessible for cpque types +// i_cmp: c_extend() accessible for csmap and csset types +// i_hash/i_eq: c_extend() accessible for cmap and cset types #define i_is_forward #define _i_inc diff --git a/misc/examples/functor.c b/misc/examples/functor.c index d6adfcb1..a233a874 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -1,22 +1,22 @@ // Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue // Example of per-instance less-function on a single priority queue type // -// Note: i_less: has self for cpque types only -// i_cmp: has self for csmap and csset types only -// i_hash/i_eq: has self for cmap and cset types only #include #define i_type IPQue #define i_base cpque #define i_val int -#define i_extend bool (*less)(const int*, const int*); -#define i_less(x, y) c_extend(self)->less(x, y) +#define i_extend bool(*less)(const int*, const int*); +#define i_less(x, y) c_extend()->less(x, y) +// Note: i_less: c_extend() accessible for cpque types +// i_cmp: c_extend() accessible for csmap and csset types +// i_hash/i_eq: c_extend() accessible for cmap and cset types #include void print_queue(const char* name, IPQue_ext q) { // NB: make a clone because there is no way to traverse - // priority_queue's content without erasing the queue. + // priority queue's content without erasing the queue. IPQue_ext copy = {q.less, IPQue_clone(q.get)}; for (printf("%s: \t", name); !IPQue_empty(©.get); IPQue_pop(©.get)) @@ -34,24 +34,23 @@ int main() { const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_arraylen(data); printf("data: \t"); - c_forrange (i, n) - printf("%d ", data[i]); + c_forrange (i, n) printf("%d ", data[i]); puts(""); - IPQue_ext q1 = {int_less}; // Max priority queue - IPQue_ext minq1 = {int_greater}; // Min priority queue - IPQue_ext q5 = {int_lambda}; // Using lambda to compare elements. - c_forrange (i, n) - IPQue_push(&q1.get, data[i]); + // Max priority queue + IPQue_ext q1 = {.less=int_less}; + IPQue_put_n(&q1.get, data, n); print_queue("q1", q1); - c_forrange (i, n) - IPQue_push(&minq1.get, data[i]); + // Min priority queue + IPQue_ext minq1 = {.less=int_greater}; + IPQue_put_n(&minq1.get, data, n); print_queue("minq1", minq1); - c_forrange (i, n) - IPQue_push(&q5.get, data[i]); + // Using lambda to compare elements. + IPQue_ext q5 = {.less=int_lambda}; + IPQue_put_n(&q5.get, data, n); print_queue("q5", q5); c_drop(IPQue, &q1.get, &minq1.get, &q5.get); -- cgit v1.2.3 From e63a3dd6545261f5236a3d7e1c2be6571871b689 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 4 Jul 2023 09:35:00 +0200 Subject: Removed cco_switch; won't work without state. --- docs/ccommon_api.md | 8 ++------ include/stc/algo/coroutine.h | 9 ++------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index b30bdda6..d39f6de6 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -370,8 +370,8 @@ int main() ### Coroutine API To resume the coroutine from where it was suspended with *cco_yield()*: call the coroutine again. -**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement; either use -`if-else-if` constructs, or `cco_switch / cco_case / cco_default` for switch-emulation instead. +**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement; use +`if-else-if` constructs instead. | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| @@ -416,10 +416,6 @@ To resume the coroutine from where it was suspended with *cco_yield()*: call the | | Time functions: | | | `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | | | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | -| | Emulate switch: | | -| | `cco_switch(x) { }` | Like switch syntax | -| | `cco_case(val) { }` | Braces are required. Fall-through if no break; | -| | `cco_default { }` | Default action | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 198b0439..3a5382f3 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -73,11 +73,6 @@ typedef enum { #define cco_suspended(co) ((co)->cco_state > 0) #define cco_done(co) ((co)->cco_state == CCO_STATE_DONE) -/* Emulate switch in coro: always use { } after cco_case(val) and cco_default. */ -#define cco_switch(x) for (long long _sw = (long long)(x), _b=0; !_b; _b=1) -#define cco_case(val) if (_b |= _sw == (val)) -#define cco_default - #define cco_routine(co) \ for (int *_state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ _resume: switch (*_state) case 0: // thanks, @liigo! @@ -107,8 +102,8 @@ typedef enum { /* cco_block_on(): assumes coroutine returns a cco_result value (int) */ #define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) -#define cco_block_on_1(corocall) while (corocall != CCO_DONE) -#define cco_block_on_2(corocall, res) while ((*(res) = (corocall)) != CCO_DONE) +#define cco_block_on_1(corocall) while ((corocall) != CCO_DONE) +#define cco_block_on_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) #define cco_cleanup \ *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP -- cgit v1.2.3 From d8c1a999cc566b8943003ad5281abc6eefcda519 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 7 Jul 2023 16:23:35 +0200 Subject: Issue #60: fixed compiler compability. --- include/stc/ccommon.h | 4 ++-- misc/examples/intrusive.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index bbf1579b..63ce5b09 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -69,8 +69,8 @@ #define c_LITERAL(T) T #else #define _i_alloc(T) ((T*)i_malloc(c_sizeof(T))) - #define _i_new(T, ...) ((T*)memcpy(_i_alloc(T), (T[]){__VA_ARGS__}, sizeof(T))) - #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), (T[]){__VA_ARGS__}, sizeof(T))) + #define _i_new(T, ...) ((T*)memcpy(_i_alloc(T), ((T[]){__VA_ARGS__}), sizeof(T))) + #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T))) #define c_LITERAL(T) (T) #endif #define c_malloc(sz) malloc(c_i2u(sz)) diff --git a/misc/examples/intrusive.c b/misc/examples/intrusive.c index 0d59c5ab..e3939f4e 100644 --- a/misc/examples/intrusive.c +++ b/misc/examples/intrusive.c @@ -17,7 +17,7 @@ void printList(List list) { int main() { List list = {0}; c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8}) - List_push_back_node(&list, c_new(List_node, {.value=*i.ref})); + List_push_back_node(&list, c_new(List_node, {0, *i.ref})); printList(list); -- cgit v1.2.3 From 3a26c8fe4bce8a3af62042dd0fca5f36221359a9 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 7 Jul 2023 17:21:22 +0200 Subject: Issue #62: Fixed wrong printf format specifiers. Changed cbits.h to use long long (guaranteed at least 64-bit) instead of int64_t for easier print. Second part of #62 is due to a clang compiler bug, can be avoided by using c_foreach instead of c_forpair. --- include/stc/cbits.h | 76 +++++++++++++++++++++++++-------------------------- include/stc/ccommon.h | 5 ++-- misc/examples/bits.c | 12 ++++---- misc/examples/bits2.c | 4 +-- 4 files changed, 49 insertions(+), 48 deletions(-) diff --git a/include/stc/cbits.h b/include/stc/cbits.h index 8a6558bf..9463c82c 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -31,7 +31,7 @@ int main() { cbits_reset(&bset, 9); cbits_resize(&bset, 43, false); - printf("%4zu: ", cbits_size(&bset)); + printf("%4lld: ", cbits_size(&bset)); c_forrange (i, cbits_size(&bset)) printf("%d", cbits_at(&bset, i)); puts(""); @@ -41,7 +41,7 @@ int main() { cbits_resize(&bset, 102, true); cbits_set_value(&bset, 99, false); - printf("%4zu: ", cbits_size(&bset)); + printf("%4lld: ", cbits_size(&bset)); c_forrange (i, cbits_size(&bset)) printf("%d", cbits_at(&bset, i)); puts(""); @@ -55,7 +55,7 @@ int main() { #include #define _cbits_bit(i) ((uint64_t)1 << ((i) & 63)) -#define _cbits_words(n) (int64_t)(((n) + 63)>>6) +#define _cbits_words(n) (_llong)(((n) + 63)>>6) #define _cbits_bytes(n) (_cbits_words(n) * c_sizeof(uint64_t)) #if defined(__GNUC__) @@ -77,23 +77,23 @@ int main() { } #endif -STC_INLINE int64_t _cbits_count(const uint64_t* set, const int64_t sz) { - const int64_t n = sz>>6; - int64_t count = 0; - for (int64_t i = 0; i < n; ++i) +STC_INLINE _llong _cbits_count(const uint64_t* set, const _llong sz) { + const _llong n = sz>>6; + _llong count = 0; + for (_llong i = 0; i < n; ++i) count += cpopcount64(set[i]); if (sz & 63) count += cpopcount64(set[n] & (_cbits_bit(sz) - 1)); return count; } -STC_INLINE char* _cbits_to_str(const uint64_t* set, const int64_t sz, - char* out, int64_t start, int64_t stop) { +STC_INLINE char* _cbits_to_str(const uint64_t* set, const _llong sz, + char* out, _llong start, _llong stop) { if (stop > sz) stop = sz; assert(start <= stop); c_memset(out, '0', stop - start); - for (int64_t i = start; i < stop; ++i) + for (_llong i = start; i < stop; ++i) if ((set[i>>6] & _cbits_bit(i)) != 0) out[i - start] = '1'; out[stop - start] = '\0'; @@ -101,8 +101,8 @@ STC_INLINE char* _cbits_to_str(const uint64_t* set, const int64_t sz, } #define _cbits_OPR(OPR, VAL) \ - const int64_t n = sz>>6; \ - for (int64_t i = 0; i < n; ++i) \ + const _llong n = sz>>6; \ + for (_llong i = 0; i < n; ++i) \ if ((set[i] OPR other[i]) != VAL) \ return false; \ if (!(sz & 63)) \ @@ -110,10 +110,10 @@ STC_INLINE char* _cbits_to_str(const uint64_t* set, const int64_t sz, const uint64_t i = (uint64_t)n, m = _cbits_bit(sz) - 1; \ return ((set[i] OPR other[i]) & m) == (VAL & m) -STC_INLINE bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const int64_t sz) +STC_INLINE bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const _llong sz) { _cbits_OPR(|, set[i]); } -STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const int64_t sz) +STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const _llong sz) { _cbits_OPR(&, 0); } #endif // CBITS_H_INCLUDED @@ -125,11 +125,11 @@ STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, cons #define _i_assert(x) assert(x) #define i_type cbits -typedef struct { uint64_t *data64; int64_t _size; } i_type; +typedef struct { uint64_t *data64; _llong _size; } i_type; STC_INLINE cbits cbits_init(void) { return c_LITERAL(cbits){NULL}; } STC_INLINE void cbits_drop(cbits* self) { c_free(self->data64); } -STC_INLINE int64_t cbits_size(const cbits* self) { return self->_size; } +STC_INLINE _llong cbits_size(const cbits* self) { return self->_size; } STC_INLINE cbits* cbits_take(cbits* self, cbits other) { if (self->data64 != other.data64) { @@ -140,7 +140,7 @@ STC_INLINE cbits* cbits_take(cbits* self, cbits other) { } STC_INLINE cbits cbits_clone(cbits other) { - const int64_t bytes = _cbits_bytes(other._size); + const _llong bytes = _cbits_bytes(other._size); cbits set = {(uint64_t *)c_memcpy(c_malloc(bytes), other.data64, bytes), other._size}; return set; } @@ -154,8 +154,8 @@ STC_INLINE cbits* cbits_copy(cbits* self, const cbits* other) { return self; } -STC_INLINE void cbits_resize(cbits* self, const int64_t size, const bool value) { - const int64_t new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize); +STC_INLINE void cbits_resize(cbits* self, const _llong size, const bool value) { + const _llong new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize); self->data64 = (uint64_t *)c_realloc(self->data64, new_n*8); self->_size = size; if (new_n >= old_n) { @@ -177,13 +177,13 @@ STC_INLINE cbits cbits_move(cbits* self) { return tmp; } -STC_INLINE cbits cbits_with_size(const int64_t size, const bool value) { +STC_INLINE cbits cbits_with_size(const _llong size, const bool value) { cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size}; cbits_set_all(&set, value); return set; } -STC_INLINE cbits cbits_with_pattern(const int64_t size, const uint64_t pattern) { +STC_INLINE cbits cbits_with_pattern(const _llong size, const uint64_t pattern) { cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size}; cbits_set_pattern(&set, pattern); return set; @@ -200,7 +200,7 @@ typedef struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } i_type; STC_INLINE void _i_memb(_init)(i_type* self) { memset(self->data64, 0, i_capacity*8); } STC_INLINE void _i_memb(_drop)(i_type* self) {} -STC_INLINE int64_t _i_memb(_size)(const i_type* self) { return i_capacity; } +STC_INLINE _llong _i_memb(_size)(const i_type* self) { return i_capacity; } STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; } STC_INLINE i_type* _i_memb(_take)(i_type* self, i_type other) @@ -215,13 +215,13 @@ STC_INLINE i_type* _i_memb(_copy)(i_type* self, const i_type* other) STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value); STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern); -STC_INLINE i_type _i_memb(_with_size)(const int64_t size, const bool value) { +STC_INLINE i_type _i_memb(_with_size)(const _llong size, const bool value) { assert(size <= i_capacity); i_type set; _i_memb(_set_all)(&set, value); return set; } -STC_INLINE i_type _i_memb(_with_pattern)(const int64_t size, const uint64_t pattern) { +STC_INLINE i_type _i_memb(_with_pattern)(const _llong size, const uint64_t pattern) { assert(size <= i_capacity); i_type set; _i_memb(_set_pattern)(&set, pattern); return set; @@ -234,36 +234,36 @@ STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value) { c_memset(self->data64, value? ~0 : 0, _cbits_bytes(_i_memb(_size)(self))); } STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern) { - int64_t n = _cbits_words(_i_memb(_size)(self)); + _llong n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] = pattern; } -STC_INLINE bool _i_memb(_test)(const i_type* self, const int64_t i) +STC_INLINE bool _i_memb(_test)(const i_type* self, const _llong i) { return (self->data64[i>>6] & _cbits_bit(i)) != 0; } -STC_INLINE bool _i_memb(_at)(const i_type* self, const int64_t i) +STC_INLINE bool _i_memb(_at)(const i_type* self, const _llong i) { return (self->data64[i>>6] & _cbits_bit(i)) != 0; } -STC_INLINE void _i_memb(_set)(i_type *self, const int64_t i) +STC_INLINE void _i_memb(_set)(i_type *self, const _llong i) { self->data64[i>>6] |= _cbits_bit(i); } -STC_INLINE void _i_memb(_reset)(i_type *self, const int64_t i) +STC_INLINE void _i_memb(_reset)(i_type *self, const _llong i) { self->data64[i>>6] &= ~_cbits_bit(i); } -STC_INLINE void _i_memb(_set_value)(i_type *self, const int64_t i, const bool b) { +STC_INLINE void _i_memb(_set_value)(i_type *self, const _llong i, const bool b) { self->data64[i>>6] ^= ((uint64_t)-(int)b ^ self->data64[i>>6]) & _cbits_bit(i); } -STC_INLINE void _i_memb(_flip)(i_type *self, const int64_t i) +STC_INLINE void _i_memb(_flip)(i_type *self, const _llong i) { self->data64[i>>6] ^= _cbits_bit(i); } STC_INLINE void _i_memb(_flip_all)(i_type *self) { - int64_t n = _cbits_words(_i_memb(_size)(self)); + _llong n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] ^= ~(uint64_t)0; } STC_INLINE i_type _i_memb(_from)(const char* str) { - int64_t n = c_strlen(str); + _llong n = c_strlen(str); i_type set = _i_memb(_with_size)(n, false); while (n--) if (str[n] == '1') _i_memb(_set)(&set, n); return set; @@ -272,26 +272,26 @@ STC_INLINE i_type _i_memb(_from)(const char* str) { /* Intersection */ STC_INLINE void _i_memb(_intersect)(i_type *self, const i_type* other) { _i_assert(self->_size == other->_size); - int64_t n = _cbits_words(_i_memb(_size)(self)); + _llong n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] &= other->data64[n]; } /* Union */ STC_INLINE void _i_memb(_union)(i_type *self, const i_type* other) { _i_assert(self->_size == other->_size); - int64_t n = _cbits_words(_i_memb(_size)(self)); + _llong n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] |= other->data64[n]; } /* Exclusive disjunction */ STC_INLINE void _i_memb(_xor)(i_type *self, const i_type* other) { _i_assert(self->_size == other->_size); - int64_t n = _cbits_words(_i_memb(_size)(self)); + _llong n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] ^= other->data64[n]; } -STC_INLINE int64_t _i_memb(_count)(const i_type* self) +STC_INLINE _llong _i_memb(_count)(const i_type* self) { return _cbits_count(self->data64, _i_memb(_size)(self)); } -STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, int64_t start, int64_t stop) +STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, _llong start, _llong stop) { return _cbits_to_str(self->data64, _i_memb(_size)(self), out, start, stop); } STC_INLINE bool _i_memb(_subset_of)(const i_type* self, const i_type* other) { diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 63ce5b09..6f42bcc1 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -30,6 +30,7 @@ #include #include +typedef long long _llong; #define c_NPOS INTPTR_MAX #define c_ZI PRIiPTR #define c_ZU PRIuPTR @@ -200,9 +201,9 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { #define c_forrange_1(stop) c_forrange_3(_c_i, 0, stop) #define c_forrange_2(i, stop) c_forrange_3(i, 0, stop) #define c_forrange_3(i, start, stop) \ - for (long long i=start, _end=(long long)(stop); i < _end; ++i) + for (_llong i=start, _end=(_llong)(stop); i < _end; ++i) #define c_forrange_4(i, start, stop, step) \ - for (long long i=start, _inc=step, _end=(long long)(stop) - (_inc > 0) \ + for (_llong i=start, _inc=step, _end=(_llong)(stop) - (_inc > 0) \ ; (_inc > 0) ^ (i > _end); i += _inc) #ifndef __cplusplus diff --git a/misc/examples/bits.c b/misc/examples/bits.c index 95452300..ce8e1de4 100644 --- a/misc/examples/bits.c +++ b/misc/examples/bits.c @@ -10,18 +10,18 @@ int main(void) cbits_drop(&set), cbits_drop(&s2) ){ - printf("count %" c_ZI ", %" c_ZI "\n", cbits_count(&set), cbits_size(&set)); + printf("count %lld, %lld\n", cbits_count(&set), cbits_size(&set)); cbits s1 = cbits_from("1110100110111"); char buf[256]; cbits_to_str(&s1, buf, 0, 255); - printf("buf: %s: %" c_ZI "\n", buf, cbits_count(&s1)); + printf("buf: %s: %lld\n", buf, cbits_count(&s1)); cbits_drop(&s1); cbits_reset(&set, 9); cbits_resize(&set, 43, false); printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255)); - printf("%4" c_ZI ": ", cbits_size(&set)); + printf("%4lld: ", cbits_size(&set)); c_forrange (i, cbits_size(&set)) printf("%d", cbits_test(&set, i)); puts(""); @@ -31,12 +31,12 @@ int main(void) cbits_resize(&set, 93, false); cbits_resize(&set, 102, true); cbits_set_value(&set, 99, false); - printf("%4" c_ZI ": ", cbits_size(&set)); + printf("%4lld: ", cbits_size(&set)); c_forrange (i, cbits_size(&set)) printf("%d", cbits_test(&set, i)); puts("\nIterate:"); - printf("%4" c_ZI ": ", cbits_size(&set)); + printf("%4lld: ", cbits_size(&set)); c_forrange (i, cbits_size(&set)) printf("%d", cbits_test(&set, i)); puts(""); @@ -59,7 +59,7 @@ int main(void) puts(""); cbits_set_all(&set, false); - printf("%4" c_ZI ": ", cbits_size(&set)); + printf("%4lld: ", cbits_size(&set)); c_forrange (i, cbits_size(&set)) printf("%d", cbits_test(&set, i)); puts(""); diff --git a/misc/examples/bits2.c b/misc/examples/bits2.c index b002af3c..913bd185 100644 --- a/misc/examples/bits2.c +++ b/misc/examples/bits2.c @@ -9,10 +9,10 @@ int main() { Bits s1 = Bits_from("1110100110111"); - printf("size %" c_ZI "\n", Bits_size(&s1)); + printf("size %lld\n", Bits_size(&s1)); char buf[256]; Bits_to_str(&s1, buf, 0, 256); - printf("buf: %s: count=%" c_ZI "\n", buf, Bits_count(&s1)); + printf("buf: %s: count=%lld\n", buf, Bits_count(&s1)); Bits_reset(&s1, 8); printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256)); -- cgit v1.2.3 From c773d8b1f41d5c2ceb228c44a9958e22db0990e2 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 7 Jul 2023 17:41:07 +0200 Subject: Backported fixes on issues #60 and #62 to STC 4.2. Note that cbits now uses long long for indices and sizes in the API, which is easier to print with "%lld", and is at least 64 bits. --- include/stc/cbits.h | 94 ++++++++++++++++++++++------------------------- include/stc/ccommon.h | 5 ++- misc/examples/bits.c | 12 +++--- misc/examples/bits2.c | 4 +- misc/examples/intrusive.c | 2 +- 5 files changed, 56 insertions(+), 61 deletions(-) diff --git a/include/stc/cbits.h b/include/stc/cbits.h index 826df847..9463c82c 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -31,7 +31,7 @@ int main() { cbits_reset(&bset, 9); cbits_resize(&bset, 43, false); - printf("%4zu: ", cbits_size(&bset)); + printf("%4lld: ", cbits_size(&bset)); c_forrange (i, cbits_size(&bset)) printf("%d", cbits_at(&bset, i)); puts(""); @@ -41,7 +41,7 @@ int main() { cbits_resize(&bset, 102, true); cbits_set_value(&bset, 99, false); - printf("%4zu: ", cbits_size(&bset)); + printf("%4lld: ", cbits_size(&bset)); c_forrange (i, cbits_size(&bset)) printf("%d", cbits_at(&bset, i)); puts(""); @@ -54,11 +54,8 @@ int main() { #include #include -#ifndef i_ssize -#define i_ssize intptr_t -#endif #define _cbits_bit(i) ((uint64_t)1 << ((i) & 63)) -#define _cbits_words(n) (i_ssize)(((n) + 63)>>6) +#define _cbits_words(n) (_llong)(((n) + 63)>>6) #define _cbits_bytes(n) (_cbits_words(n) * c_sizeof(uint64_t)) #if defined(__GNUC__) @@ -80,23 +77,23 @@ int main() { } #endif -STC_INLINE i_ssize _cbits_count(const uint64_t* set, const i_ssize sz) { - const i_ssize n = sz>>6; - i_ssize count = 0; - for (i_ssize i = 0; i < n; ++i) +STC_INLINE _llong _cbits_count(const uint64_t* set, const _llong sz) { + const _llong n = sz>>6; + _llong count = 0; + for (_llong i = 0; i < n; ++i) count += cpopcount64(set[i]); if (sz & 63) count += cpopcount64(set[n] & (_cbits_bit(sz) - 1)); return count; } -STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz, - char* out, i_ssize start, i_ssize stop) { +STC_INLINE char* _cbits_to_str(const uint64_t* set, const _llong sz, + char* out, _llong start, _llong stop) { if (stop > sz) stop = sz; assert(start <= stop); c_memset(out, '0', stop - start); - for (i_ssize i = start; i < stop; ++i) + for (_llong i = start; i < stop; ++i) if ((set[i>>6] & _cbits_bit(i)) != 0) out[i - start] = '1'; out[stop - start] = '\0'; @@ -104,8 +101,8 @@ STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz, } #define _cbits_OPR(OPR, VAL) \ - const i_ssize n = sz>>6; \ - for (i_ssize i = 0; i < n; ++i) \ + const _llong n = sz>>6; \ + for (_llong i = 0; i < n; ++i) \ if ((set[i] OPR other[i]) != VAL) \ return false; \ if (!(sz & 63)) \ @@ -113,10 +110,10 @@ STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz, const uint64_t i = (uint64_t)n, m = _cbits_bit(sz) - 1; \ return ((set[i] OPR other[i]) & m) == (VAL & m) -STC_INLINE bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const i_ssize sz) +STC_INLINE bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const _llong sz) { _cbits_OPR(|, set[i]); } -STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const i_ssize sz) +STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const _llong sz) { _cbits_OPR(&, 0); } #endif // CBITS_H_INCLUDED @@ -128,12 +125,11 @@ STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, cons #define _i_assert(x) assert(x) #define i_type cbits -struct { uint64_t *data64; i_ssize _size; } typedef i_type; +typedef struct { uint64_t *data64; _llong _size; } i_type; STC_INLINE cbits cbits_init(void) { return c_LITERAL(cbits){NULL}; } -STC_INLINE void cbits_create(cbits* self) { self->data64 = NULL; self->_size = 0; } STC_INLINE void cbits_drop(cbits* self) { c_free(self->data64); } -STC_INLINE i_ssize cbits_size(const cbits* self) { return self->_size; } +STC_INLINE _llong cbits_size(const cbits* self) { return self->_size; } STC_INLINE cbits* cbits_take(cbits* self, cbits other) { if (self->data64 != other.data64) { @@ -144,7 +140,7 @@ STC_INLINE cbits* cbits_take(cbits* self, cbits other) { } STC_INLINE cbits cbits_clone(cbits other) { - const i_ssize bytes = _cbits_bytes(other._size); + const _llong bytes = _cbits_bytes(other._size); cbits set = {(uint64_t *)c_memcpy(c_malloc(bytes), other.data64, bytes), other._size}; return set; } @@ -158,16 +154,16 @@ STC_INLINE cbits* cbits_copy(cbits* self, const cbits* other) { return self; } -STC_INLINE void cbits_resize(cbits* self, const i_ssize size, const bool value) { - const i_ssize new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize); +STC_INLINE void cbits_resize(cbits* self, const _llong size, const bool value) { + const _llong new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize); self->data64 = (uint64_t *)c_realloc(self->data64, new_n*8); self->_size = size; if (new_n >= old_n) { c_memset(self->data64 + old_n, -(int)value, (new_n - old_n)*8); if (old_n > 0) { - uint64_t m = _cbits_bit(osize) - 1; /* mask */ - value ? (self->data64[old_n - 1] |= ~m) - : (self->data64[old_n - 1] &= m); + uint64_t mask = _cbits_bit(osize) - 1; + if (value) self->data64[old_n - 1] |= ~mask; + else self->data64[old_n - 1] &= mask; } } } @@ -181,13 +177,13 @@ STC_INLINE cbits cbits_move(cbits* self) { return tmp; } -STC_INLINE cbits cbits_with_size(const i_ssize size, const bool value) { +STC_INLINE cbits cbits_with_size(const _llong size, const bool value) { cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size}; cbits_set_all(&set, value); return set; } -STC_INLINE cbits cbits_with_pattern(const i_ssize size, const uint64_t pattern) { +STC_INLINE cbits cbits_with_pattern(const _llong size, const uint64_t pattern) { cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size}; cbits_set_pattern(&set, pattern); return set; @@ -200,12 +196,11 @@ STC_INLINE cbits cbits_with_pattern(const i_ssize size, const uint64_t pattern) #define i_type c_PASTE(cbits, i_capacity) #endif -struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } typedef i_type; +typedef struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } i_type; -STC_INLINE i_type _i_memb(_init)(void) { return c_LITERAL(i_type){0}; } -STC_INLINE void _i_memb(_create)(i_type* self) {} +STC_INLINE void _i_memb(_init)(i_type* self) { memset(self->data64, 0, i_capacity*8); } STC_INLINE void _i_memb(_drop)(i_type* self) {} -STC_INLINE i_ssize _i_memb(_size)(const i_type* self) { return i_capacity; } +STC_INLINE _llong _i_memb(_size)(const i_type* self) { return i_capacity; } STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; } STC_INLINE i_type* _i_memb(_take)(i_type* self, i_type other) @@ -216,17 +211,17 @@ STC_INLINE i_type _i_memb(_clone)(i_type other) STC_INLINE i_type* _i_memb(_copy)(i_type* self, const i_type* other) { *self = *other; return self; } - + STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value); STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern); -STC_INLINE i_type _i_memb(_with_size)(const i_ssize size, const bool value) { +STC_INLINE i_type _i_memb(_with_size)(const _llong size, const bool value) { assert(size <= i_capacity); i_type set; _i_memb(_set_all)(&set, value); return set; } -STC_INLINE i_type _i_memb(_with_pattern)(const i_ssize size, const uint64_t pattern) { +STC_INLINE i_type _i_memb(_with_pattern)(const _llong size, const uint64_t pattern) { assert(size <= i_capacity); i_type set; _i_memb(_set_pattern)(&set, pattern); return set; @@ -239,36 +234,36 @@ STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value) { c_memset(self->data64, value? ~0 : 0, _cbits_bytes(_i_memb(_size)(self))); } STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern) { - i_ssize n = _cbits_words(_i_memb(_size)(self)); + _llong n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] = pattern; } -STC_INLINE bool _i_memb(_test)(const i_type* self, const i_ssize i) +STC_INLINE bool _i_memb(_test)(const i_type* self, const _llong i) { return (self->data64[i>>6] & _cbits_bit(i)) != 0; } -STC_INLINE bool _i_memb(_at)(const i_type* self, const i_ssize i) +STC_INLINE bool _i_memb(_at)(const i_type* self, const _llong i) { return (self->data64[i>>6] & _cbits_bit(i)) != 0; } -STC_INLINE void _i_memb(_set)(i_type *self, const i_ssize i) +STC_INLINE void _i_memb(_set)(i_type *self, const _llong i) { self->data64[i>>6] |= _cbits_bit(i); } -STC_INLINE void _i_memb(_reset)(i_type *self, const i_ssize i) +STC_INLINE void _i_memb(_reset)(i_type *self, const _llong i) { self->data64[i>>6] &= ~_cbits_bit(i); } -STC_INLINE void _i_memb(_set_value)(i_type *self, const i_ssize i, const bool b) { +STC_INLINE void _i_memb(_set_value)(i_type *self, const _llong i, const bool b) { self->data64[i>>6] ^= ((uint64_t)-(int)b ^ self->data64[i>>6]) & _cbits_bit(i); } -STC_INLINE void _i_memb(_flip)(i_type *self, const i_ssize i) +STC_INLINE void _i_memb(_flip)(i_type *self, const _llong i) { self->data64[i>>6] ^= _cbits_bit(i); } STC_INLINE void _i_memb(_flip_all)(i_type *self) { - i_ssize n = _cbits_words(_i_memb(_size)(self)); + _llong n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] ^= ~(uint64_t)0; } STC_INLINE i_type _i_memb(_from)(const char* str) { - int64_t n = c_strlen(str); + _llong n = c_strlen(str); i_type set = _i_memb(_with_size)(n, false); while (n--) if (str[n] == '1') _i_memb(_set)(&set, n); return set; @@ -277,26 +272,26 @@ STC_INLINE i_type _i_memb(_from)(const char* str) { /* Intersection */ STC_INLINE void _i_memb(_intersect)(i_type *self, const i_type* other) { _i_assert(self->_size == other->_size); - i_ssize n = _cbits_words(_i_memb(_size)(self)); + _llong n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] &= other->data64[n]; } /* Union */ STC_INLINE void _i_memb(_union)(i_type *self, const i_type* other) { _i_assert(self->_size == other->_size); - i_ssize n = _cbits_words(_i_memb(_size)(self)); + _llong n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] |= other->data64[n]; } /* Exclusive disjunction */ STC_INLINE void _i_memb(_xor)(i_type *self, const i_type* other) { _i_assert(self->_size == other->_size); - i_ssize n = _cbits_words(_i_memb(_size)(self)); + _llong n = _cbits_words(_i_memb(_size)(self)); while (n--) self->data64[n] ^= other->data64[n]; } -STC_INLINE int64_t _i_memb(_count)(const i_type* self) +STC_INLINE _llong _i_memb(_count)(const i_type* self) { return _cbits_count(self->data64, _i_memb(_size)(self)); } -STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, int64_t start, int64_t stop) +STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, _llong start, _llong stop) { return _cbits_to_str(self->data64, _i_memb(_size)(self), out, start, stop); } STC_INLINE bool _i_memb(_subset_of)(const i_type* self, const i_type* other) { @@ -312,7 +307,6 @@ STC_INLINE bool _i_memb(_disjoint)(const i_type* self, const i_type* other) { #pragma GCC diagnostic pop #endif #define CBITS_H_INCLUDED -#undef _i_size #undef _i_memb #undef _i_assert #undef i_capacity diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index d5508807..38dc2bd9 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -32,6 +32,7 @@ #include "priv/altnames.h" #include "priv/raii.h" +typedef long long _llong; #define c_NPOS INTPTR_MAX #define c_ZI PRIiPTR #define c_ZU PRIuPTR @@ -71,8 +72,8 @@ #define c_LITERAL(T) T #else #define _i_alloc(T) ((T*)i_malloc(c_sizeof(T))) - #define _i_new(T, ...) ((T*)memcpy(_i_alloc(T), (T[]){__VA_ARGS__}, sizeof(T))) - #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), (T[]){__VA_ARGS__}, sizeof(T))) + #define _i_new(T, ...) ((T*)memcpy(_i_alloc(T), ((T[]){__VA_ARGS__}), sizeof(T))) + #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T))) #define c_LITERAL(T) (T) #endif #define c_malloc(sz) malloc(c_i2u(sz)) diff --git a/misc/examples/bits.c b/misc/examples/bits.c index 1323d4e7..e0a11346 100644 --- a/misc/examples/bits.c +++ b/misc/examples/bits.c @@ -9,18 +9,18 @@ int main(void) cbits_drop(&set), cbits_drop(&s2) ){ - printf("count %" c_ZI ", %" c_ZI "\n", cbits_count(&set), cbits_size(&set)); + printf("count %lld, %lld\n", cbits_count(&set), cbits_size(&set)); cbits s1 = cbits_from("1110100110111"); char buf[256]; cbits_to_str(&s1, buf, 0, 255); - printf("buf: %s: %" c_ZI "\n", buf, cbits_count(&s1)); + printf("buf: %s: %lld\n", buf, cbits_count(&s1)); cbits_drop(&s1); cbits_reset(&set, 9); cbits_resize(&set, 43, false); printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255)); - printf("%4" c_ZI ": ", cbits_size(&set)); + printf("%4lld: ", cbits_size(&set)); c_forrange (i, cbits_size(&set)) printf("%d", cbits_test(&set, i)); puts(""); @@ -30,12 +30,12 @@ int main(void) cbits_resize(&set, 93, false); cbits_resize(&set, 102, true); cbits_set_value(&set, 99, false); - printf("%4" c_ZI ": ", cbits_size(&set)); + printf("%4lld: ", cbits_size(&set)); c_forrange (i, cbits_size(&set)) printf("%d", cbits_test(&set, i)); puts("\nIterate:"); - printf("%4" c_ZI ": ", cbits_size(&set)); + printf("%4lld: ", cbits_size(&set)); c_forrange (i, cbits_size(&set)) printf("%d", cbits_test(&set, i)); puts(""); @@ -58,7 +58,7 @@ int main(void) puts(""); cbits_set_all(&set, false); - printf("%4" c_ZI ": ", cbits_size(&set)); + printf("%4lld: ", cbits_size(&set)); c_forrange (i, cbits_size(&set)) printf("%d", cbits_test(&set, i)); puts(""); diff --git a/misc/examples/bits2.c b/misc/examples/bits2.c index b002af3c..913bd185 100644 --- a/misc/examples/bits2.c +++ b/misc/examples/bits2.c @@ -9,10 +9,10 @@ int main() { Bits s1 = Bits_from("1110100110111"); - printf("size %" c_ZI "\n", Bits_size(&s1)); + printf("size %lld\n", Bits_size(&s1)); char buf[256]; Bits_to_str(&s1, buf, 0, 256); - printf("buf: %s: count=%" c_ZI "\n", buf, Bits_count(&s1)); + printf("buf: %s: count=%lld\n", buf, Bits_count(&s1)); Bits_reset(&s1, 8); printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256)); diff --git a/misc/examples/intrusive.c b/misc/examples/intrusive.c index 0d503575..0f153589 100644 --- a/misc/examples/intrusive.c +++ b/misc/examples/intrusive.c @@ -16,7 +16,7 @@ void printList(List list) { int main() { List list = {0}; c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8}) - List_push_back_node(&list, c_new(List_node, {0, *i.ref})); + List_push_back_node(&list, c_new(List_node, {.value=*i.ref})); printList(list); -- cgit v1.2.3 From 2d1011251596edee16d3bd6afb0e3c3b9df1157b Mon Sep 17 00:00:00 2001 From: tylov Date: Sat, 8 Jul 2023 14:00:23 +0200 Subject: Added support for column-major md cspan. API change: the create function cspan_md(order, array, d1, d2, ...) has the new first argument order, which must be either 'C' or 'F' (C: row-major or Fortran: column-major). The representation of strides was changed. --- docs/cspan_api.md | 15 ++- include/stc/cspan.h | 164 +++++++++++++++------------ misc/benchmarks/various/cspan_bench.c | 12 +- misc/benchmarks/various/string_bench_STC.cpp | 5 +- misc/examples/multidim.c | 2 +- misc/tests/cspan_test.c | 10 +- 6 files changed, 117 insertions(+), 91 deletions(-) diff --git a/docs/cspan_api.md b/docs/cspan_api.md index c78bb8a0..58b06af0 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -22,14 +22,14 @@ using_cspan4(S, ValueType); // define span types S, S2, S3, S4 with ## Methods All functions are type-safe. Note that the span argument itself is generally not side-effect safe, -i.e., it may be expanded multiple times. However, all integer arguments are safe, e.g. +i.e., it may be expanded multiple times. However, all index arguments are safe, e.g. `cspan_at(&ms3, i++, j++, k++)` is allowed. If the number of arguments does not match the span rank, a compile error is issued. Runtime bounds checks are enabled by default (define `STC_NDEBUG` or `NDEBUG` to disable). ```c SpanType cspan_init(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from compatible STC container SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from C array -SpanTypeN cspan_md(ValueType* data, intptr_t xdim, ...); // make a multi-dimensional cspan +SpanTypeN cspan_md(char order, ValueType* data, d1, d2, ...); // make a multi-dim cspan. order: 'C' or 'F' (Fortran) intptr_t cspan_size(const SpanTypeN* self); // return number of elements intptr_t cspan_rank(const SpanTypeN* self); // dimensions; compile time constant @@ -42,6 +42,9 @@ ValueType* cspan_back(const SpanTypeN* self); // general index slicing to create a subspan. // {i} reduces rank. {i,c_END} slice to end. {c_ALL} use the full extent. SpanTypeR cspan_slice(T SpanTypeR, const SpanTypeN* self, {x0,x1}, {y0,y1}.., {N0,N1}); + + // transpose the md span (inverse axes). no changes to the underlying array. +void cspan_transpose(const SpanTypeN* self); // create a subspan of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); SpanType cspan_submd2(const SpanType2* self, intptr_t x); // return a 1d subspan from a 2d span. @@ -50,8 +53,8 @@ SpanTypeN cspan_submd4(const SpanType4* self, intptr_t x, ...); // numbe // create a subspan of same rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); SpanType cspan_subspan(const SpanType* self, intptr_t offset, intptr_t count); -SpanType2 cspan_subspan2(const SpanType2 self, intptr_t offset, intptr_t count); -SpanType3 cspan_subspan3(const SpanType3 self, intptr_t offset, intptr_t count); +SpanType2 cspan_subspan2(const SpanType2* self, intptr_t offset, intptr_t count); +SpanType3 cspan_subspan3(const SpanType3* self, intptr_t offset, intptr_t count); SpanTypeN_iter SpanType_begin(const SpanTypeN* self); SpanTypeN_iter SpanType_end(const SpanTypeN* self); @@ -99,7 +102,7 @@ using_cspan3(myspan, int); // define myspan, myspan2, myspan3. int main() { int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; - myspan3 ms3 = cspan_md(arr, 2, 3, 4); + myspan3 ms3 = cspan_md('C', arr, 2, 3, 4); // C-order, i.e. row-major. myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {1,3}, {2,c_END}); myspan2 ss2 = cspan_submd3(&ss3, 1); @@ -148,7 +151,7 @@ int main() Span span = c_init(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}); // create a 3d cspan: - Span3 span3 = cspan_md(span.data, 2, 4, 3); + Span3 span3 = cspan_md('C', span.data, 2, 4, 3); // reduce rank: (i.e. span3[1]) Span2 span2 = cspan_submd3(&span3, 1); diff --git a/include/stc/cspan.h b/include/stc/cspan.h index d7a72267..35f5029f 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -30,7 +30,7 @@ using_cspan(Intspan, int, 1); int demo1() { float raw[4*5]; - Span2f ms = cspan_md(raw, 4, 5); + Span2f ms = cspan_md('C', raw, 4, 5); for (int i=0; iref += _cspan_next##RANK(RANK, it->pos, it->_s->shape, it->_s->stride.d); \ - if (it->pos[0] == it->_s->shape[0]) it->ref = NULL; \ + static const struct { int8_t i, j, inc; } t[2] = {{RANK - 1, 0, -1}, {0, RANK - 1, 1}}; \ + const int order = (it->_s->stride.d[0] < it->_s->stride.d[RANK - 1]); /* 0='C', 1='F' */ \ + it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, t[order].i, t[order].inc); \ + if (it->pos[t[order].j] == it->_s->shape[t[order].j]) \ + it->ref = NULL; \ } \ struct stc_nostruct #define using_cspan2(Self, T) using_cspan_3(Self, T, 1); using_cspan_3(Self##2, T, 2) #define using_cspan3(Self, T) using_cspan2(Self, T); using_cspan_3(Self##3, T, 3) #define using_cspan4(Self, T) using_cspan3(Self, T); using_cspan_3(Self##4, T, 4) -typedef struct { int32_t d[1]; } cspan_idx1; -typedef struct { int32_t d[2]; } cspan_idx2; -typedef struct { int32_t d[3]; } cspan_idx3; -typedef struct { int32_t d[4]; } cspan_idx4; -typedef struct { int32_t d[5]; } cspan_idx5; -typedef struct { int32_t d[6]; } cspan_idx6; +typedef struct { int32_t d[1]; } cspan_tup1; +typedef struct { int32_t d[2]; } cspan_tup2; +typedef struct { int32_t d[3]; } cspan_tup3; +typedef struct { int32_t d[4]; } cspan_tup4; +typedef struct { int32_t d[5]; } cspan_tup5; +typedef struct { int32_t d[6]; } cspan_tup6; #define c_END -1 #define c_ALL 0,-1 -#define cspan_md(array, ...) \ - {.data=array, .shape={__VA_ARGS__}, .stride={.d={__VA_ARGS__}}} +#define cspan_md(order, array, ...) \ + {.data=array, .shape={__VA_ARGS__}, \ + .stride=*(c_PASTE(cspan_tup, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(order, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} -/* For static initialization, use cspan_init(). c_init() for non-static only. */ +#define cspan_transpose(self) \ + _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self)) + +/* Use cspan_init() for static initialization only. c_init() for non-static init. */ #define cspan_init(SpanType, ...) \ {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}} @@ -134,17 +141,18 @@ typedef struct { int32_t d[6]; } cspan_idx6; #define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) #define cspan_rank(self) c_arraylen((self)->shape) +#define cspan_order(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) -#define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) -#define cspan_idx_1 cspan_idx_4 -#define cspan_idx_2 cspan_idx_4 -#define cspan_idx_3 cspan_idx_4 -#define cspan_idx_4(self, ...) \ +#define cspan_index(self, ...) c_PASTE(cspan_tup_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) +#define cspan_tup_1 cspan_tup_3 +#define cspan_tup_2 cspan_tup_3 +#define cspan_tup_3(self, ...) \ c_PASTE(_cspan_idx, c_NUMARGS(__VA_ARGS__))((self)->shape, (self)->stride, __VA_ARGS__) // small/fast -#define cspan_idx_5(self, ...) \ +#define cspan_tup_4(self, ...) \ (_cspan_idxN(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \ c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general -#define cspan_idx_6 cspan_idx_5 +#define cspan_tup_5 cspan_tup_4 +#define cspan_tup_6 cspan_tup_4 #define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__)) #define cspan_front(self) ((self)->data) @@ -162,19 +170,20 @@ typedef struct { int32_t d[6]; } cspan_idx6; #define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__) #define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__) #define cspan_submd2(self, x) \ - {.data=cspan_at(self, x, 0), .shape={(self)->shape[1]}} + {.data=cspan_at(self, x, 0), .shape={(self)->shape[1]}, .stride={.d={(self)->stride.d[1]}}} #define cspan_submd3_2(self, x) \ {.data=cspan_at(self, x, 0, 0), .shape={(self)->shape[1], (self)->shape[2]}, \ - .stride={.d={0, (self)->stride.d[2]}}} + .stride={.d={(self)->stride.d[1], (self)->stride.d[2]}}} #define cspan_submd3_3(self, x, y) \ - {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}} + {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}, .stride={.d={(self)->stride.d[2]}}} #define cspan_submd4_2(self, x) \ {.data=cspan_at(self, x, 0, 0, 0), .shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \ - .stride={.d={0, (self)->stride.d[2], (self)->stride.d[3]}}} + .stride={.d={(self)->stride.d[1], (self)->stride.d[2], (self)->stride.d[3]}}} #define cspan_submd4_3(self, x, y) \ - {.data=cspan_at(self, x, y, 0, 0), .shape={(self)->shape[2], (self)->shape[3]}, .stride={.d={0, (self)->stride.d[3]}}} + {.data=cspan_at(self, x, y, 0, 0), .shape={(self)->shape[2], (self)->shape[3]}, \ + .stride={.d={(self)->stride.d[2], (self)->stride.d[3]}}} #define cspan_submd4_4(self, x, y, z) \ - {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}} + {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}, .stride={.d={(self)->stride.d[3]}}} // private definitions: @@ -184,83 +193,96 @@ STC_INLINE intptr_t _cspan_size(const int32_t shape[], int rank) { return sz; } -STC_INLINE intptr_t _cspan_idx1(const int32_t shape[1], const cspan_idx1 stri, int32_t x) +STC_INLINE void _cspan_transpose(int32_t shape[], int32_t stride[], int rank) { + for (int i = 0; i < --rank; ++i) { + c_swap(int32_t, shape + i, shape + rank); + c_swap(int32_t, stride + i, stride + rank); + } +} + +STC_INLINE intptr_t _cspan_idx1(const int32_t shape[1], const cspan_tup1 stri, int32_t x) { c_ASSERT(c_LTu(x, shape[0])); return x; } -STC_INLINE intptr_t _cspan_idx2(const int32_t shape[2], const cspan_idx2 stri, int32_t x, int32_t y) - { c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1])); return (intptr_t)stri.d[1]*x + y; } +STC_INLINE intptr_t _cspan_idx2(const int32_t shape[2], const cspan_tup2 stri, int32_t x, int32_t y) + { c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1])); return (intptr_t)stri.d[0]*x + stri.d[1]*y; } -STC_INLINE intptr_t _cspan_idx3(const int32_t shape[3], const cspan_idx3 stri, int32_t x, int32_t y, int32_t z) { +STC_INLINE intptr_t _cspan_idx3(const int32_t shape[3], const cspan_tup3 stri, int32_t x, int32_t y, int32_t z) { c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2])); - return (intptr_t)stri.d[2]*(stri.d[1]*x + y) + z; + return (intptr_t)stri.d[0]*x + stri.d[1]*y + stri.d[2]*z; } -STC_INLINE intptr_t _cspan_idx4(const int32_t shape[4], const cspan_idx4 stri, int32_t x, int32_t y, - int32_t z, int32_t w) { - c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2]) && c_LTu(w, shape[3])); - return (intptr_t)stri.d[3]*(stri.d[2]*(stri.d[1]*x + y) + z) + w; + +STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stride[], const int32_t a[]) { + intptr_t off = 0; + while (rank--) { + c_ASSERT(c_LTu(a[rank], shape[rank])); + off += stride[rank]*a[rank]; + } + return off; } -STC_API intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stri[], const int32_t a[]); -STC_API intptr_t _cspan_next2(int rank, int32_t pos[], const int32_t shape[], const int32_t stride[]); -#define _cspan_next1(r, pos, d, s) (++pos[0], 1) +#define _cspan_next1(pos, d, s, r, i, inc) (++pos[0], 1) +STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc); #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 #define _cspan_next6 _cspan_next2 -STC_API intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank, - const int32_t shape[], const int32_t stri[], +STC_API intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, + const int32_t shape[], const int32_t stride[], int rank, const int32_t a[][2]); + +STC_API int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank); #endif // STC_CSPAN_H_INCLUDED /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) -STC_DEF intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stri[], const int32_t a[]) { - intptr_t off = a[0]; - c_ASSERT(c_LTu(a[0], shape[0])); - for (int i = 1; i < rank; ++i) { - off *= stri[i]; - off += a[i]; - c_ASSERT(c_LTu(a[i], shape[i])); +STC_DEF int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank) { + int32_t k = 1, i, j, inc, s1, s2; + if (order == 'F') i = 0, j = rank, inc = 1; + else /* 'C' */ i = rank - 1, j = -1, inc = -1; + s1 = shape[i]; shape[i] = 1; + + for (i += inc; i != j; i += inc) { + s2 = shape[i]; + shape[i] = (k *= s1); + s1 = s2; } - return off; + return shape; } -STC_DEF intptr_t _cspan_next2(int rank, int32_t pos[], const int32_t shape[], const int32_t stride[]) { - intptr_t off = 1, rs = 1; - ++pos[rank - 1]; - while (--rank && pos[rank] == shape[rank]) { - pos[rank] = 0, ++pos[rank - 1]; - const intptr_t ds = rs*shape[rank]; - rs *= stride[rank]; - off += rs - ds; +STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc) { + intptr_t off = stride[i]; + ++pos[i]; + for (; --rank && pos[i] == shape[i]; i += inc) { + pos[i] = 0; ++pos[i + inc]; + off += stride[i + inc] - stride[i]*shape[i]; } return off; } -STC_DEF intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank, - const int32_t shape[], const int32_t stri[], +STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, + const int32_t shape[], const int32_t stride[], int rank, const int32_t a[][2]) { intptr_t off = 0; - int i = 0, j = 0; - int32_t t, s = 1; + int i = 0, oi = 0; + int32_t end; for (; i < rank; ++i) { - off *= stri[i]; - off += a[i][0]; - switch (a[i][1]) { - case 0: s *= stri[i]; c_ASSERT(c_LTu(a[i][0], shape[i])); continue; - case -1: t = shape[i]; break; - default: t = a[i][1]; break; + off += stride[i]*a[i][0]; + switch (a[i][1]) { + case 0: c_ASSERT(c_LTu(a[i][0], shape[i])); continue; + case -1: end = shape[i]; break; + default: end = a[i][1]; } - odim[j] = t - a[i][0]; - ostri[j] = s*stri[i]; - c_ASSERT(c_LTu(0, odim[j]) & !c_LTu(shape[i], t)); - s = 1; ++j; + oshape[oi] = end - a[i][0]; + ostride[oi] = stride[i]; + c_ASSERT(c_LTu(0, oshape[oi]) & !c_LTu(shape[i], end)); + ++oi; } - *orank = j; + *orank = oi; return off; } + #endif #undef i_opt #undef i_header diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c index 02ae3237..6ca7425d 100644 --- a/misc/benchmarks/various/cspan_bench.c +++ b/misc/benchmarks/various/cspan_bench.c @@ -28,8 +28,8 @@ static void MDRanges_setup(intptr_t state) for (intptr_t s = 0; s < state; ++s) { - MD3 r_in = cspan_md(Vin, nx, ny, nz); - MD3 r_out = cspan_md(Vout, nx, ny, nz); + MD3 r_in = cspan_md('C', Vin, nx, ny, nz); + MD3 r_out = cspan_md('C', Vout, nx, ny, nz); r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); @@ -64,8 +64,8 @@ static void TraditionalForLoop(intptr_t state) static void MDRanges_nested_loop(intptr_t state) { - MD3 r_in = cspan_md(Vin, nx, ny, nz); - MD3 r_out = cspan_md(Vout, nx, ny, nz); + MD3 r_in = cspan_md('C', Vin, nx, ny, nz); + MD3 r_out = cspan_md('C', Vout, nx, ny, nz); r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); @@ -91,8 +91,8 @@ static void MDRanges_nested_loop(intptr_t state) static void MDRanges_loop_over_joined(intptr_t state) { - MD3 r_in = cspan_md(Vin, nx, ny, nz); - MD3 r_out = cspan_md(Vout, nx, ny, nz); + MD3 r_in = cspan_md('C', Vin, nx, ny, nz); + MD3 r_out = cspan_md('C', Vout, nx, ny, nz); r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp index ae8e4c38..319b0b19 100644 --- a/misc/benchmarks/various/string_bench_STC.cpp +++ b/misc/benchmarks/various/string_bench_STC.cpp @@ -4,10 +4,11 @@ #include #include #include -#define i_static +#define i_implement #include // string -#define i_static +#define i_implement #include // string_view +#include #define i_key_str #include // vec of cstr with const char* lookup diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c index 2f3ad907..df8f485d 100644 --- a/misc/examples/multidim.c +++ b/misc/examples/multidim.c @@ -14,7 +14,7 @@ int main() ispan ms1 = cspan_from(&v); // View the same data as a 3D array 2 x 3 x 4 - ispan3 ms3 = cspan_md(v.data, 2, 3, 4); + ispan3 ms3 = cspan_md('C', v.data, 2, 3, 4); puts("ms3:"); for (int i=0; i != ms3.shape[0]; i++) { diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index 9afa63f5..d266fa38 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -8,7 +8,7 @@ using_cspan3(intspan, int); CTEST(cspan, subdim) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - intspan3 m = cspan_md(array, 2, 2, 3); + intspan3 m = cspan_md('C', array, 2, 2, 3); for (size_t i = 0; i < m.shape[0]; ++i) { intspan2 sub_i = cspan_submd3(&m, i); @@ -23,7 +23,7 @@ CTEST(cspan, subdim) { CTEST(cspan, slice) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - intspan2 m1 = cspan_md(array, 3, 4); + intspan2 m1 = cspan_md('C', array, 3, 4); size_t sum1 = 0; for (size_t i = 0; i < m1.shape[0]; ++i) { @@ -53,7 +53,7 @@ CTEST(cspan, slice2) { c_forrange (i, 10*20*30) cstack_int_push(&stack, i); - intspan3 ms3 = cspan_md(stack.data, 10, 20, 30); + intspan3 ms3 = cspan_md('C', stack.data, 10, 20, 30); ms3 = cspan_slice(intspan3, &ms3, {1,4}, {3,7}, {20,24}); size_t sum = 0; @@ -93,7 +93,7 @@ CTEST_SETUP(cspan_cube) { c_forrange (i, N) cstack_int_push(&_self->stack, i+1); - intspan3 ms3 = cspan_md(_self->stack.data, CUBE, CUBE, CUBE); + intspan3 ms3 = cspan_md('C', _self->stack.data, CUBE, CUBE, CUBE); c_forrange (i, 0, ms3.shape[0], TSIZE) { c_forrange (j, 0, ms3.shape[1], TSIZE) { @@ -114,7 +114,7 @@ CTEST_TEARDOWN(cspan_cube) { CTEST_F(cspan_cube, slice3) { intptr_t n = cstack_int_size(&_self->stack); - //printf("\ntiles: %zi, cells: %zi\n", Tiles_size(&_self->tiles), n); + //printf("\ntiles: %d, cells: %d\n", (int)Tiles_size(&_self->tiles), (int)n); int64_t sum = 0; // iterate each 3d tile in sequence -- cgit v1.2.3 From a7f7951490b9709dd75e143d0afdf51d5869eb54 Mon Sep 17 00:00:00 2001 From: tylov Date: Sat, 8 Jul 2023 16:03:00 +0200 Subject: Fixed some internal renaming bugs in cspan.h --- include/stc/cspan.h | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 35f5029f..860450eb 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -72,7 +72,7 @@ int demo2() { typedef struct { \ Self##_value *data; \ int32_t shape[RANK]; \ - cspan_tup##RANK stride; \ + cspan_tuple##RANK stride; \ } Self; \ \ typedef struct { Self##_value *ref; int32_t pos[RANK]; const Self *_s; } Self##_iter; \ @@ -107,18 +107,18 @@ int demo2() { #define using_cspan2(Self, T) using_cspan_3(Self, T, 1); using_cspan_3(Self##2, T, 2) #define using_cspan3(Self, T) using_cspan2(Self, T); using_cspan_3(Self##3, T, 3) #define using_cspan4(Self, T) using_cspan3(Self, T); using_cspan_3(Self##4, T, 4) -typedef struct { int32_t d[1]; } cspan_tup1; -typedef struct { int32_t d[2]; } cspan_tup2; -typedef struct { int32_t d[3]; } cspan_tup3; -typedef struct { int32_t d[4]; } cspan_tup4; -typedef struct { int32_t d[5]; } cspan_tup5; -typedef struct { int32_t d[6]; } cspan_tup6; +typedef struct { int32_t d[1]; } cspan_tuple1; +typedef struct { int32_t d[2]; } cspan_tuple2; +typedef struct { int32_t d[3]; } cspan_tuple3; +typedef struct { int32_t d[4]; } cspan_tuple4; +typedef struct { int32_t d[5]; } cspan_tuple5; +typedef struct { int32_t d[6]; } cspan_tuple6; #define c_END -1 #define c_ALL 0,-1 #define cspan_md(order, array, ...) \ {.data=array, .shape={__VA_ARGS__}, \ - .stride=*(c_PASTE(cspan_tup, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(order, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} + .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(order, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} #define cspan_transpose(self) \ _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self)) @@ -143,16 +143,16 @@ typedef struct { int32_t d[6]; } cspan_tup6; #define cspan_rank(self) c_arraylen((self)->shape) #define cspan_order(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) -#define cspan_index(self, ...) c_PASTE(cspan_tup_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) -#define cspan_tup_1 cspan_tup_3 -#define cspan_tup_2 cspan_tup_3 -#define cspan_tup_3(self, ...) \ +#define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) +#define cspan_idx_1 cspan_idx_3 +#define cspan_idx_2 cspan_idx_3 +#define cspan_idx_3(self, ...) \ c_PASTE(_cspan_idx, c_NUMARGS(__VA_ARGS__))((self)->shape, (self)->stride, __VA_ARGS__) // small/fast -#define cspan_tup_4(self, ...) \ +#define cspan_idx_4(self, ...) \ (_cspan_idxN(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \ c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general -#define cspan_tup_5 cspan_tup_4 -#define cspan_tup_6 cspan_tup_4 +#define cspan_idx_5 cspan_idx_4 +#define cspan_idx_6 cspan_idx_4 #define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__)) #define cspan_front(self) ((self)->data) @@ -200,17 +200,16 @@ STC_INLINE void _cspan_transpose(int32_t shape[], int32_t stride[], int rank) { } } -STC_INLINE intptr_t _cspan_idx1(const int32_t shape[1], const cspan_tup1 stri, int32_t x) +STC_INLINE intptr_t _cspan_idx1(const int32_t shape[1], const cspan_tuple1 stri, int32_t x) { c_ASSERT(c_LTu(x, shape[0])); return x; } -STC_INLINE intptr_t _cspan_idx2(const int32_t shape[2], const cspan_tup2 stri, int32_t x, int32_t y) +STC_INLINE intptr_t _cspan_idx2(const int32_t shape[2], const cspan_tuple2 stri, int32_t x, int32_t y) { c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1])); return (intptr_t)stri.d[0]*x + stri.d[1]*y; } -STC_INLINE intptr_t _cspan_idx3(const int32_t shape[3], const cspan_tup3 stri, int32_t x, int32_t y, int32_t z) { +STC_INLINE intptr_t _cspan_idx3(const int32_t shape[3], const cspan_tuple3 stri, int32_t x, int32_t y, int32_t z) { c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2])); return (intptr_t)stri.d[0]*x + stri.d[1]*y + stri.d[2]*z; } - STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stride[], const int32_t a[]) { intptr_t off = 0; while (rank--) { -- cgit v1.2.3 From c8a11225cf30740590d469d835c7ba367627abca Mon Sep 17 00:00:00 2001 From: tylov Date: Sat, 8 Jul 2023 23:45:13 +0200 Subject: Fixes from 32-bit raspberry pi testing. --- include/stc/ccommon.h | 2 +- misc/tests/cspan_test.c | 5 ++--- misc/tests/ctest.h | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 6f42bcc1..0cce1610 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -174,7 +174,7 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { n |= n >> 1, n |= n >> 2; n |= n >> 4, n |= n >> 8; n |= n >> 16; - #if INTPTR_SIZE == INT64_SIZE + #if INTPTR_MAX == INT64_MAX n |= n >> 32; #endif return n + 1; diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index d266fa38..b6953936 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -113,10 +113,9 @@ CTEST_TEARDOWN(cspan_cube) { CTEST_F(cspan_cube, slice3) { - intptr_t n = cstack_int_size(&_self->stack); - //printf("\ntiles: %d, cells: %d\n", (int)Tiles_size(&_self->tiles), (int)n); + long long n = cstack_int_size(&_self->stack); + long long sum = 0; - int64_t sum = 0; // iterate each 3d tile in sequence c_foreach (i, Tiles, _self->tiles) c_foreach (t, intspan3, *i.ref) diff --git a/misc/tests/ctest.h b/misc/tests/ctest.h index 373cda0e..6b1b1084 100644 --- a/misc/tests/ctest.h +++ b/misc/tests/ctest.h @@ -408,7 +408,8 @@ void assert_dbl_compare(const char* cmp, double exp, double real, double tol, co void assert_pointers(const char* cmp, const void* exp, const void* real, const char* caller, int line) { if ((exp == real) != (cmp[0] == '=')) { - CTEST_ERR("%s:%d assertion failed (0x%02llx) %s (0x%02llx)", caller, line, (unsigned long long)exp , cmp, (unsigned long long)real); + CTEST_ERR("%s:%d assertion failed (0x%02llx) %s (0x%02llx)", caller, line, + (unsigned long long)(uintptr_t)exp , cmp, (unsigned long long)(uintptr_t)real); } } -- cgit v1.2.3 From be5864d5f658d544ad5c2af9f1c5b37b4d96bde8 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 9 Jul 2023 06:38:44 +0200 Subject: Several minor fixes in cspan.h. --- include/stc/cspan.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 860450eb..715efea8 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -125,7 +125,7 @@ typedef struct { int32_t d[6]; } cspan_tuple6; /* Use cspan_init() for static initialization only. c_init() for non-static init. */ #define cspan_init(SpanType, ...) \ - {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}} + {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}, .stride={.d={1}}} #define cspan_slice(OutSpan, parent, ...) \ OutSpan##_slice_((parent)->data, (parent)->shape, (parent)->stride.d, cspan_rank(parent) + \ @@ -134,14 +134,14 @@ typedef struct { int32_t d[6]; } cspan_tuple6; /* create a cspan from a cvec, cstack, cdeq, cqueue, or cpque (heap) */ #define cspan_from(container) \ - {.data=(container)->data, .shape={(int32_t)(container)->_len}} + {.data=(container)->data, .shape={(int32_t)(container)->_len}, .stride={.d={1}}} #define cspan_from_array(array) \ - {.data=(array) + c_static_assert(sizeof(array) != sizeof(void*)), .shape={c_arraylen(array)}} + {.data=(array) + c_static_assert(sizeof(array) != sizeof(void*)), .shape={c_arraylen(array)}, .stride={.d={1}}} #define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) #define cspan_rank(self) c_arraylen((self)->shape) -#define cspan_order(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) +#define cspan_is_order_F(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) #define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) #define cspan_idx_1 cspan_idx_3 @@ -158,15 +158,15 @@ typedef struct { int32_t d[6]; } cspan_tuple6; #define cspan_front(self) ((self)->data) #define cspan_back(self) ((self)->data + cspan_size(self) - 1) -// cspan_subspanN. (N<4) Optimized, same as e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); +// cspan_subspanN. (N<=3) Optimized, same as e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); #define cspan_subspan(self, offset, count) \ - {.data=cspan_at(self, offset), .shape={count}} + {.data=cspan_at(self, offset), .shape={count}, .stride=(self)->stride} #define cspan_subspan2(self, offset, count) \ - {.data=cspan_at(self, offset, 0), .shape={count, (self)->shape[1]}, .stride={(self)->stride}} + {.data=cspan_at(self, offset, 0), .shape={count, (self)->shape[1]}, .stride=(self)->stride} #define cspan_subspan3(self, offset, count) \ - {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride={(self)->stride}} + {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride=(self)->stride} -// cspan_submdN: reduce rank (N<5) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); +// cspan_submdN: reduce rank (N<=4) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); #define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__) #define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__) #define cspan_submd2(self, x) \ @@ -219,7 +219,7 @@ STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t s return off; } -#define _cspan_next1(pos, d, s, r, i, inc) (++pos[0], 1) +#define _cspan_next1(pos, shape, stride, rank, i, inc) (++pos[0], stride[0]) STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc); #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 -- cgit v1.2.3 From 6fe1ec0e0e3dbce71797873f71a5f306b046319f Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 10 Jul 2023 10:53:30 +0200 Subject: - Fixed meta-programming bug in carc and cbox hash function def (regression). - Reverted to allow static linking of cstr and csview. Still defaults to shared linking + inlines. --- include/stc/carc.h | 2 +- include/stc/cbox.h | 2 +- include/stc/cspan.h | 2 +- include/stc/cstr.h | 137 +++++++++++++++++++++++--------------------- include/stc/csview.h | 27 ++++----- include/stc/priv/template.h | 9 ++- 6 files changed, 95 insertions(+), 84 deletions(-) diff --git a/include/stc/carc.h b/include/stc/carc.h index db0cdcec..b77b7dfb 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -213,7 +213,7 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { { return i_hash(rx); } STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { return i_hash(self->get); } + { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } #else STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return c_default_hash(&rx); } diff --git a/include/stc/cbox.h b/include/stc/cbox.h index c8d919b2..86d5a6a6 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -196,7 +196,7 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) { { return i_hash(rx); } STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { return i_hash(self->get); } + { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } #else STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return c_default_hash(&rx); } diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 715efea8..7a0e9c8d 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -189,7 +189,7 @@ typedef struct { int32_t d[6]; } cspan_tuple6; STC_INLINE intptr_t _cspan_size(const int32_t shape[], int rank) { intptr_t sz = shape[0]; - while (rank-- > 1) sz *= shape[rank]; + while (--rank > 0) sz *= shape[rank]; return sz; } diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 0f217f53..17943ad5 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -24,6 +24,7 @@ /* A string type with short string optimization in C99 with good small-string * optimization (22 characters with 24 bytes string). */ +#define i_header // external linkage by default. override with i_static. #define _i_inc_utf8 #include "utf8.h" @@ -61,8 +62,8 @@ enum { cstr_s_cap = sizeof(cstr_buf) - 2 }; #define cstr_l_drop(s) c_free((s)->lon.data) #define cstr_is_long(s) ((s)->sml.size > 127) -extern char* _cstr_init(cstr* self, intptr_t len, intptr_t cap); -extern char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); +STC_API char* _cstr_init(cstr* self, intptr_t len, intptr_t cap); +STC_API char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); /**************************** PUBLIC API **********************************/ @@ -70,22 +71,22 @@ extern char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); #define cstr_null (c_LITERAL(cstr){0}) #define cstr_toraw(self) cstr_str(self) -extern char* cstr_reserve(cstr* self, intptr_t cap); -extern void cstr_shrink_to_fit(cstr* self); -extern char* cstr_resize(cstr* self, intptr_t size, char value); -extern intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); -extern intptr_t cstr_find_sv(const cstr* self, csview search); -extern char* cstr_assign_n(cstr* self, const char* str, intptr_t len); -extern char* cstr_append_n(cstr* self, const char* str, intptr_t len); -extern char* cstr_append_uninit(cstr *self, intptr_t len); -extern bool cstr_getdelim(cstr *self, int delim, FILE *fp); -extern void cstr_erase(cstr* self, intptr_t pos, intptr_t len); -extern void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); -extern cstr cstr_from_fmt(const char* fmt, ...); -extern intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); -extern intptr_t cstr_printf(cstr* self, const char* fmt, ...); -extern cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); -extern uint64_t cstr_hash(const cstr *self); +STC_API char* cstr_reserve(cstr* self, intptr_t cap); +STC_API void cstr_shrink_to_fit(cstr* self); +STC_API char* cstr_resize(cstr* self, intptr_t size, char value); +STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); +STC_API intptr_t cstr_find_sv(const cstr* self, csview search); +STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len); +STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len); +STC_API char* cstr_append_uninit(cstr *self, intptr_t len); +STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp); +STC_API void cstr_erase(cstr* self, intptr_t pos, intptr_t len); +STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); +STC_API cstr cstr_from_fmt(const char* fmt, ...); +STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); +STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...); +STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); +STC_API uint64_t cstr_hash(const cstr *self); STC_INLINE cstr_buf cstr_buffer(cstr* s) { return cstr_is_long(s) @@ -169,31 +170,14 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self) // utf8 methods defined in/depending on src/utf8code.c: -extern cstr cstr_tocase(csview sv, int k); - -STC_INLINE cstr cstr_casefold_sv(csview sv) - { return cstr_tocase(sv, 0); } - -STC_INLINE cstr cstr_tolower_sv(csview sv) - { return cstr_tocase(sv, 1); } - -STC_INLINE cstr cstr_toupper_sv(csview sv) - { return cstr_tocase(sv, 2); } - -STC_INLINE cstr cstr_tolower(const char* str) - { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } - -STC_INLINE cstr cstr_toupper(const char* str) - { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } - -STC_INLINE void cstr_lowercase(cstr* self) - { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } - -STC_INLINE void cstr_uppercase(cstr* self) - { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } - -STC_INLINE bool cstr_valid_utf8(const cstr* self) - { return utf8_valid(cstr_str(self)); } +STC_API cstr cstr_casefold_sv(csview sv); +STC_API cstr cstr_tolower_sv(csview sv); +STC_API cstr cstr_toupper_sv(csview sv); +STC_API cstr cstr_tolower(const char* str); +STC_API cstr cstr_toupper(const char* str); +STC_API void cstr_lowercase(cstr* self); +STC_API void cstr_uppercase(cstr* self); +STC_API bool cstr_valid_utf8(const cstr* self); // other utf8 @@ -410,7 +394,7 @@ fn_tocase[] = {{tolower, utf8_casefold}, {tolower, utf8_tolower}, {toupper, utf8_toupper}}; -cstr cstr_tocase(csview sv, int k) { +STC_DEF cstr cstr_tocase(csview sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); const char *end = sv.str + sv.size; @@ -430,25 +414,49 @@ cstr cstr_tocase(csview sv, int k) { cstr_shrink_to_fit(&out); return out; } + +STC_DEF cstr cstr_casefold_sv(csview sv) + { return cstr_tocase(sv, 0); } + +STC_DEF cstr cstr_tolower_sv(csview sv) + { return cstr_tocase(sv, 1); } + +STC_DEF cstr cstr_toupper_sv(csview sv) + { return cstr_tocase(sv, 2); } + +STC_DEF cstr cstr_tolower(const char* str) + { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } + +STC_DEF cstr cstr_toupper(const char* str) + { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } + +STC_DEF void cstr_lowercase(cstr* self) + { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } + +STC_DEF void cstr_uppercase(cstr* self) + { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } + +STC_DEF bool cstr_valid_utf8(const cstr* self) + { return utf8_valid(cstr_str(self)); } #endif // i_import /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement +#if defined i_implement || defined i_static #ifndef CSTR_C_INCLUDED #define CSTR_C_INCLUDED -uint64_t cstr_hash(const cstr *self) { +STC_DEF uint64_t cstr_hash(const cstr *self) { csview sv = cstr_sv(self); return cfasthash(sv.str, sv.size); } -intptr_t cstr_find_sv(const cstr* self, csview search) { +STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { csview sv = cstr_sv(self); char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); return res ? (res - sv.str) : c_NPOS; } -char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { +STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { cstr_buf r = cstr_buffer(self); if (pos1 != pos2) { const intptr_t newlen = (r.size + pos2 - pos1); @@ -460,7 +468,7 @@ char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) return r.data; } -char* _cstr_init(cstr* self, const intptr_t len, const intptr_t cap) { +STC_DEF char* _cstr_init(cstr* self, const intptr_t len, const intptr_t cap) { if (cap > cstr_s_cap) { self->lon.data = (char *)c_malloc(cap + 1); cstr_l_set_size(self, len); @@ -471,7 +479,7 @@ char* _cstr_init(cstr* self, const intptr_t len, const intptr_t cap) { return self->sml.data; } -void cstr_shrink_to_fit(cstr* self) { +STC_DEF void cstr_shrink_to_fit(cstr* self) { cstr_buf r = cstr_buffer(self); if (r.size == r.cap) return; @@ -485,7 +493,7 @@ void cstr_shrink_to_fit(cstr* self) { } } -char* cstr_reserve(cstr* self, const intptr_t cap) { +STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) { if (cstr_is_long(self)) { if (cap > cstr_l_cap(self)) { self->lon.data = (char *)c_realloc(self->lon.data, cap + 1); @@ -507,7 +515,7 @@ char* cstr_reserve(cstr* self, const intptr_t cap) { return self->sml.data; } -char* cstr_resize(cstr* self, const intptr_t size, const char value) { +STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) { cstr_buf r = cstr_buffer(self); if (size > r.size) { if (size > r.cap && !(r.data = cstr_reserve(self, size))) @@ -518,20 +526,20 @@ char* cstr_resize(cstr* self, const intptr_t size, const char value) { return r.data; } -intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { +STC_DEF intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { csview sv = cstr_sv(self); if (pos > sv.size) return c_NPOS; const char* res = strstr((char*)sv.str + pos, search); return res ? (res - sv.str) : c_NPOS; } -char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { +STC_DEF char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { char* d = cstr_reserve(self, len); if (d) { c_memmove(d, str, len); _cstr_set_size(self, len); } return d; } -char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { +STC_DEF char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { cstr_buf r = cstr_buffer(self); if (r.size + len > r.cap) { const size_t off = (size_t)(str - r.data); @@ -544,7 +552,7 @@ char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { return r.data; } -char* cstr_append_uninit(cstr *self, intptr_t len) { +STC_DEF char* cstr_append_uninit(cstr *self, intptr_t len) { cstr_buf r = cstr_buffer(self); if (r.size + len > r.cap && !(r.data = cstr_reserve(self, r.size*3/2 + len))) return NULL; @@ -552,7 +560,7 @@ char* cstr_append_uninit(cstr *self, intptr_t len) { return r.data + r.size; } -bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { +STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { int c = fgetc(fp); if (c == EOF) return false; @@ -572,8 +580,7 @@ bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } } -cstr -cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { +STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { cstr out = cstr_null; intptr_t from = 0; char* res; if (!count) count = INT32_MAX; @@ -588,14 +595,14 @@ cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { return out; } -void cstr_erase(cstr* self, const intptr_t pos, intptr_t len) { +STC_DEF void cstr_erase(cstr* self, const intptr_t pos, intptr_t len) { cstr_buf r = cstr_buffer(self); if (len > r.size - pos) len = r.size - pos; c_memmove(&r.data[pos], &r.data[pos + len], r.size - (pos + len)); _cstr_set_size(self, r.size - len); } -void cstr_u8_erase(cstr* self, const intptr_t bytepos, const intptr_t u8len) { +STC_DEF void cstr_u8_erase(cstr* self, const intptr_t bytepos, const intptr_t u8len) { cstr_buf r = cstr_buffer(self); intptr_t len = utf8_pos(r.data + bytepos, u8len); c_memmove(&r.data[bytepos], &r.data[bytepos + len], r.size - (bytepos + len)); @@ -610,7 +617,7 @@ void cstr_u8_erase(cstr* self, const intptr_t bytepos, const intptr_t u8len) { # pragma warning(disable: 4996) #endif -intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list args) { +STC_DEF intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list args) { va_list args2; va_copy(args2, args); const int n = vsnprintf(NULL, 0ULL, fmt, args); @@ -625,7 +632,7 @@ intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list args) { # pragma warning(pop) #endif -cstr cstr_from_fmt(const char* fmt, ...) { +STC_DEF cstr cstr_from_fmt(const char* fmt, ...) { cstr s = cstr_null; va_list args; va_start(args, fmt); @@ -634,7 +641,7 @@ cstr cstr_from_fmt(const char* fmt, ...) { return s; } -intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...) { +STC_DEF intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...) { va_list args; va_start(args, fmt); const intptr_t n = cstr_vfmt(self, cstr_size(self), fmt, args); @@ -643,7 +650,7 @@ intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...) { } /* NB! self-data in args is UB */ -intptr_t cstr_printf(cstr* self, const char* fmt, ...) { +STC_DEF intptr_t cstr_printf(cstr* self, const char* fmt, ...) { va_list args; va_start(args, fmt); const intptr_t n = cstr_vfmt(self, 0, fmt, args); diff --git a/include/stc/csview.h b/include/stc/csview.h index f960968c..85965928 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,6 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#define i_header // external linkage by default. override with i_static. #define _i_inc_utf8 #include "utf8.h" @@ -33,12 +34,12 @@ #define csview_lit(literal) c_sv_1(literal) #define csview_from_n(str, n) c_sv_2(str, n) -extern csview_iter csview_advance(csview_iter it, intptr_t pos); -extern intptr_t csview_find_sv(csview sv, csview search); -extern uint64_t csview_hash(const csview *self); -extern csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); -extern csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); -extern csview csview_token(csview sv, const char* sep, intptr_t* start); +STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); +STC_API intptr_t csview_find_sv(csview sv, csview search); +STC_API uint64_t csview_hash(const csview *self); +STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); +STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); +STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); STC_INLINE csview csview_from(const char* str) { return c_LITERAL(csview){str, c_strlen(str)}; } @@ -150,11 +151,11 @@ STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u #endif /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement +#if defined i_implement || defined i_static #ifndef CSVIEW_C_INCLUDED #define CSVIEW_C_INCLUDED -csview_iter csview_advance(csview_iter it, intptr_t pos) { +STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { int inc = -1; if (pos > 0) pos = -pos, inc = 1; while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; @@ -163,15 +164,15 @@ csview_iter csview_advance(csview_iter it, intptr_t pos) { return it; } -intptr_t csview_find_sv(csview sv, csview search) { +STC_DEF intptr_t csview_find_sv(csview sv, csview search) { char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); return res ? (res - sv.str) : c_NPOS; } -uint64_t csview_hash(const csview *self) +STC_DEF uint64_t csview_hash(const csview *self) { return cfasthash(self->str, self->size); } -csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { +STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { if (pos < 0) { pos += sv.size; if (pos < 0) pos = 0; @@ -182,7 +183,7 @@ csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { return sv; } -csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { +STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { if (p1 < 0) { p1 += sv.size; if (p1 < 0) p1 = 0; @@ -193,7 +194,7 @@ csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { return sv; } -csview csview_token(csview sv, const char* sep, intptr_t* start) { +STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { intptr_t sep_size = c_strlen(sep); csview slice = {sv.str + *start, sv.size - *start}; const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 03c27bdb..7138a87c 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -102,6 +102,9 @@ #if c_option(c_no_emplace) #define i_no_emplace #endif +#if c_option(c_native_cmp) + #define i_native_cmp +#endif #if defined i_key_str #define i_keyclass cstr @@ -194,10 +197,10 @@ #endif #ifndef i_no_cmp - #if c_option(c_native_cmp) || defined i_native_cmp || defined i_cmp || defined i_less + #if defined i_cmp || defined i_less || defined i_native_cmp #define _i_has_cmp #endif - #if defined i_eq + #if defined i_eq || defined i_native_cmp #define _i_has_eq #endif @@ -219,7 +222,7 @@ #endif #endif -#if !(defined i_hash || defined _i_cbox || defined _i_carc) +#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_native_cmp) #define i_hash c_default_hash #endif -- cgit v1.2.3 From 7342a721e5dbef94bb1b1541f01154fe4a37aeb8 Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 10 Jul 2023 10:58:36 +0200 Subject: Reverted from crange_init() to crange_make() again. Added to changelog for v4.3 --- README.md | 16 +++++++++++++--- docs/ccommon_api.md | 13 ++++++------- include/stc/algo/crange.h | 12 ++++++------ include/stc/ccommon.h | 4 ---- misc/examples/forfilter.c | 4 ++-- misc/examples/prime.c | 2 +- 6 files changed, 28 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 3628ecd1..af9ce1ad 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ STC - Smart Template Containers =============================== -### [Version 4.3 RC2](#version-history) +### [Version 4.3 RC3](#version-history) --- Description @@ -613,10 +613,20 @@ STC is generally very memory efficient. Memory usage for the different container # Version History ## Version 4.3 -- algo/coroutine.h much improved with new API and more features. +- Some breaking changes. +- coroutines: much improved with some new API and added features. +- cspan: Support for column-major (fortran order) multidim spans and transposed views. +- Removed default comparison for clist, cvec and cdeq (as with cstack and cqueue). + - Using i_val_str, i_valclass, i_valboxed still expects comparisons defined. + - Define i_native_cmp to enable built-in i_val types comparisons (<, ==). +- cstr and csview are now shared linked by default. Static linking by defining i_static. - New cdeq and cqueue implementation(s), using circular buffer. -- Removed deprecated uppercase flow-control macro names. +- Renamed i_extern => i_import. + - Define i_import before #include will also define utf8 case conversions. + - Define i_import before #include will also define cstr + utf8 tables. +- Renamed c_make() => c_init() macro for initialization lists. - Removed deprecated crandom.h. Use crand.h with new API. +- Removed deprecated uppercase flow-control macro names. - Improved default string hash function. ## Version 4.2 diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index d39f6de6..f21f2eaf 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -82,16 +82,16 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i); ### crange A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: ```c -crange crange_init(stop); // will generate 0, 1, ..., stop-1 -crange crange_init(start, stop); // will generate start, start+1, ... stop-1 -crange crange_init(start, stop, step); // will generate start, start+step, ... upto-not-including stop +crange crange_make(stop); // will generate 0, 1, ..., stop-1 +crange crange_make(start, stop); // will generate start, start+1, ... stop-1 +crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop // note that step may be negative. crange_iter crange_begin(crange* self); crange_iter crange_end(crange* self); void crange_next(crange_iter* it); // 1. All primes less than 32: -crange r1 = crange_init(3, 32, 2); +crange r1 = crange_make(3, 32, 2); printf("2"); // first prime c_forfilter (i, crange, r1, isPrime(*i.ref)) printf(" %lld", *i.ref); @@ -99,7 +99,7 @@ c_forfilter (i, crange, r1, isPrime(*i.ref)) // 2. The first 11 primes: printf("2"); -crange range = crange_init(3, INT64_MAX, 2); +crange range = crange_make(3, INT64_MAX, 2); c_forfilter (i, crange, range, isPrime(*i.ref) && c_flt_take(10) @@ -140,7 +140,7 @@ bool isPrime(long long i) { int main() { // Get 10 prime numbers starting from 1000. Skip the first 15 primes, // then select every 25th prime (including the initial). - crange R = crange_init(1001, INT64_MAX, 2); // 1001, 1003, ... + crange R = crange_make(1001, INT64_MAX, 2); // 1001, 1003, ... c_forfilter (i, crange, R, isPrime(*i.ref) && @@ -171,7 +171,6 @@ Make any container from an initializer list: ... // Initializes with const char*, internally converted to cstr! cset_str myset = c_init(cset_str, {"This", "is", "the", "story"}); -cset_str myset2 = c_clone(myset); int x = 7, y = 8; cmap_int mymap = c_init(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h index 34ed541b..45ef53a1 100644 --- a/include/stc/algo/crange.h +++ b/include/stc/algo/crange.h @@ -27,14 +27,14 @@ int main() { - crange r1 = crange_init(80, 90); + crange r1 = crange_make(80, 90); c_foreach (i, crange, r1) printf(" %lld", *i.ref); puts(""); // use a temporary crange object. int a = 100, b = INT32_MAX; - crange r2 = crange_init(a, b, 8); + crange r2 = crange_make(a, b, 8); c_forfilter (i, crange, r2, c_flt_skip(i, 10) && c_flt_take(i, 3)) @@ -51,11 +51,11 @@ typedef long long crange_value; typedef struct { crange_value start, end, step, value; } crange; typedef struct { crange_value *ref, end, step; } crange_iter; -#define crange_init(...) c_MACRO_OVERLOAD(crange_init, __VA_ARGS__) -#define crange_init_1(stop) crange_init_3(0, stop, 1) -#define crange_init_2(start, stop) crange_init_3(start, stop, 1) +#define crange_make(...) c_MACRO_OVERLOAD(crange_make, __VA_ARGS__) +#define crange_make_1(stop) crange_make_3(0, stop, 1) +#define crange_make_2(start, stop) crange_make_3(start, stop, 1) -STC_INLINE crange crange_init_3(crange_value start, crange_value stop, crange_value step) +STC_INLINE crange crange_make_3(crange_value start, crange_value stop, crange_value step) { crange r = {start, stop - (step > 0), step}; return r; } STC_INLINE crange_iter crange_begin(crange* self) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 0cce1610..d6da8734 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -241,8 +241,4 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) #endif -// [deprecated]: -#define c_make(...) c_init(__VA_ARGS__) -#define cspan_make(...) cspan_init(__VA_ARGS__) -#define crange_make(...) crange_init(__VA_ARGS__) #endif // CCOMMON_H_INCLUDED diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index d39693b5..7e3c4c9c 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -55,7 +55,7 @@ fn main() { void demo2(void) { IVec vector = {0}; - crange r = crange_init(INT64_MAX); + crange r = crange_make(INT64_MAX); c_forfilter (x, crange, r, c_flt_skipwhile(x, *x.ref != 11) && (*x.ref % 2) != 0 && @@ -125,7 +125,7 @@ void demo5(void) { #define flt_even(i) ((*i.ref & 1) == 0) #define flt_mid_decade(i) ((*i.ref % 10) != 0) - crange R = crange_init(1963, INT32_MAX); + crange R = crange_make(1963, INT32_MAX); c_forfilter (i, crange, R, c_flt_skip(i,15) && diff --git a/misc/examples/prime.c b/misc/examples/prime.c index 34fa144c..cb3b095a 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -41,7 +41,7 @@ int main(void) puts("\n"); puts("Show the last 50 primes using a temporary crange generator:"); - crange range = crange_init(n - 1, 0, -2); + crange range = crange_make(n - 1, 0, -2); c_forfilter (i, crange, range, cbits_test(&primes, *i.ref/2) && -- cgit v1.2.3 From 8debe47bc014c41b6cf8082dcef4b87e4ef29cfa Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 10 Jul 2023 12:16:44 +0200 Subject: Renamed input enum flags for cregex functions. --- README.md | 1 + docs/ccommon_api.md | 8 ++++---- docs/cregex_api.md | 18 +++++++++--------- include/stc/cregex.h | 20 ++++++++++++-------- misc/examples/regex_match.c | 2 +- misc/examples/regex_replace.c | 2 +- misc/tests/cregex_test.c | 12 ++++++------ src/cregex.c | 12 ++++++------ 8 files changed, 40 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index af9ce1ad..ab350488 100644 --- a/README.md +++ b/README.md @@ -625,6 +625,7 @@ STC is generally very memory efficient. Memory usage for the different container - Define i_import before #include will also define utf8 case conversions. - Define i_import before #include will also define cstr + utf8 tables. - Renamed c_make() => c_init() macro for initialization lists. +- Renamed input enum flags for cregex functions. - Removed deprecated crandom.h. Use crand.h with new API. - Removed deprecated uppercase flow-control macro names. - Improved default string hash function. diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index f21f2eaf..7569bb5b 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -369,8 +369,8 @@ int main() ### Coroutine API To resume the coroutine from where it was suspended with *cco_yield()*: call the coroutine again. -**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement; use -`if-else-if` constructs instead. +**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement from a +cco_routine scope; Use `if-else-if` constructs instead. | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| @@ -384,11 +384,11 @@ To resume the coroutine from where it was suspended with *cco_yield()*: call the | | `cco_yield_v();` | Yield/suspend execution (return void) | | | `cco_yield_v(ret);` | Yield/suspend execution (return ret) | | | `cco_yield_final();` | Yield final time, enables cleanup-state | -| | `cco_yield_final(val);` | Yield a final value (e.g. CCO_ERROR) | +| | `cco_yield_final(ret);` | Yield a final value (e.g. CCO_ERROR) | | | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| | | `cco_await_v(condition);` | Suspend until condition is true (return void) | | | `cco_await_v(condition, ret);` | Suspend until condition is true (return ret)| -| | `cco_await_on(cocall);` | Await on sub-coroutine to finish | +| | `cco_await_on(cocall);` | Await on sub-coroutine to finish (return its ret) | | | `cco_return;` | Return from coroutine (inside cco_routine) | | | `cco_closure(Closure, ...);` | Define a coroutine closure struct (optional) | | | Semaphores: | | diff --git a/docs/cregex_api.md b/docs/cregex_api.md index ff69c549..f87240f8 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -12,16 +12,16 @@ The API is simple and includes powerful string pattern matches and replace funct ```c enum { // compile-flags - CREG_C_DOTALL = 1<<0, // dot matches newline too: can be set/overridden by (?s) and (?-s) in RE - CREG_C_ICASE = 1<<1, // ignore case mode: can be set/overridden by (?i) and (?-i) in RE + CREG_DOTALL = 1<<0, // dot matches newline too: can be set/overridden by (?s) and (?-s) in RE + CREG_ICASE = 1<<1, // ignore case mode: can be set/overridden by (?i) and (?-i) in RE // match-flags - CREG_M_FULLMATCH = 1<<2, // like start-, end-of-line anchors were in pattern: "^ ... $" - CREG_M_NEXT = 1<<3, // use end of previous match[0] as start of input - CREG_M_STARTEND = 1<<4, // use match[0] as start+end of input + CREG_FULLMATCH = 1<<2, // like start-, end-of-line anchors were in pattern: "^ ... $" + CREG_NEXT = 1<<3, // use end of previous match[0] as start of input + CREG_STARTEND = 1<<4, // use match[0] as start+end of input // replace-flags - CREG_R_STRIP = 1<<5, // only keep the replaced matches, strip the rest + CREG_STRIP = 1<<5, // only keep the replaced matches, strip the rest }; cregex cregex_init(void); @@ -138,7 +138,7 @@ In order to use a callback function in the replace call, see `examples/regex_rep To iterate multiple matches in an input string, you may use ```c csview match[5] = {0}; -while (cregex_find(&re, input, match, CREG_M_NEXT) == CREG_OK) +while (cregex_find(&re, input, match, CREG_NEXT) == CREG_OK) for (int k = 1; i <= cregex_captures(&re); ++k) printf("submatch %d: %.*s\n", k, c_SV(match[k])); ``` @@ -181,8 +181,8 @@ For reference, **cregex** uses the following files: | \B | Not UTF8 word boundary | * | | \Q | Start literal input mode | * | | \E | End literal input mode | * | -| (?i) (?-i) | Ignore case on/off (override CREG_C_ICASE) | * | -| (?s) (?-s) | Dot matches newline on/off (override CREG_C_DOTALL) | * | +| (?i) (?-i) | Ignore case on/off (override CREG_ICASE) | * | +| (?s) (?-s) | Dot matches newline on/off (override CREG_DOTALL) | * | | \n \t \r | Match UTF8 newline, tab, carriage return | | | \d \s \w | Match UTF8 digit, whitespace, alphanumeric character | | | \D \S \W | Do not match the groups described above | | diff --git a/include/stc/cregex.h b/include/stc/cregex.h index 1d1d441f..bce94b04 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -39,15 +39,19 @@ THE SOFTWARE. enum { CREG_DEFAULT = 0, + /* compile-flags */ - CREG_C_DOTALL = 1<<0, /* dot matches newline too */ - CREG_C_ICASE = 1<<1, /* ignore case */ + CREG_DOTALL = 1<<0, /* dot matches newline too */ + CREG_ICASE = 1<<1, /* ignore case */ + /* match-flags */ - CREG_M_FULLMATCH = 1<<2, /* like start-, end-of-line anchors were in pattern: "^ ... $" */ - CREG_M_NEXT = 1<<3, /* use end of previous match[0] as start of input */ - CREG_M_STARTEND = 1<<4, /* use match[0] as start+end of input */ + CREG_FULLMATCH = 1<<2, /* like start-, end-of-line anchors were in pattern: "^ ... $" */ + CREG_NEXT = 1<<3, /* use end of previous match[0] as start of input */ + CREG_STARTEND = 1<<4, /* use match[0] as start+end of input */ + /* replace-flags */ - CREG_R_STRIP = 1<<5, /* only keep the matched strings, strip rest */ + CREG_STRIP = 1<<5, /* only keep the matched strings, strip rest */ + /* limits */ CREG_MAX_CLASSES = 16, CREG_MAX_CAPTURES = 32, @@ -83,7 +87,7 @@ typedef struct { #define c_formatch(it, Re, Input) \ for (cregex_iter it = {Re, Input}; \ - cregex_find_4(it.re, it.input, it.match, CREG_M_NEXT) == CREG_OK; ) + cregex_find_4(it.re, it.input, it.match, CREG_NEXT) == CREG_OK; ) STC_INLINE cregex cregex_init(void) { cregex re = {0}; @@ -117,7 +121,7 @@ int cregex_find_4(const cregex* re, const char* input, csview match[], int mflag STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { csview *mp = NULL; if (match) { match[0] = input; mp = match; } - return cregex_find(re, input.str, mp, CREG_M_STARTEND); + return cregex_find(re, input.str, mp, CREG_STARTEND); } /* match + compile RE pattern */ diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c index ebda366f..310e0797 100644 --- a/misc/examples/regex_match.c +++ b/misc/examples/regex_match.c @@ -28,7 +28,7 @@ int main() printf(" %g\n", (double)*i.ref); // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_R_STRIP); + cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); printf("\n%s\n", cstr_str(&nums)); cstr_drop(&nums); diff --git a/misc/examples/regex_replace.c b/misc/examples/regex_replace.c index 2c7794af..3a33efde 100644 --- a/misc/examples/regex_replace.c +++ b/misc/examples/regex_replace.c @@ -48,7 +48,7 @@ int main() printf("euros: %s\n", cstr_str(&str)); /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_R_STRIP)); + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); printf("strip: %s\n", cstr_str(&str)); /* Wrap all words in ${} */ diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 3ddcc608..4e192de6 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -15,7 +15,7 @@ CTEST(cregex, compile_match_char) ASSERT_EQ(re.error, 0); csview match; - ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_M_FULLMATCH), CREG_OK); + ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_FULLMATCH), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); // ä is two bytes wide @@ -193,14 +193,14 @@ CTEST(cregex, search_all) int res; ASSERT_EQ(re.error, CREG_OK); inp="ab,ab,ab"; - res = cregex_find(&re, inp, &m, CREG_M_NEXT); + res = cregex_find(&re, inp, &m, CREG_NEXT); ASSERT_EQ(M_START(m), 0); - res = cregex_find(&re, inp, &m, CREG_M_NEXT); + res = cregex_find(&re, inp, &m, CREG_NEXT); ASSERT_EQ(res, CREG_OK); ASSERT_EQ(M_START(m), 3); - res = cregex_find(&re, inp, &m, CREG_M_NEXT); + res = cregex_find(&re, inp, &m, CREG_NEXT); ASSERT_EQ(M_START(m), 6); - res = cregex_find(&re, inp, &m, CREG_M_NEXT); + res = cregex_find(&re, inp, &m, CREG_NEXT); ASSERT_NE(res, CREG_OK); } } @@ -280,7 +280,7 @@ CTEST(cregex, replace) ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022"); // Strip out everything but the matches - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_R_STRIP)); + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;"); } } diff --git a/src/cregex.c b/src/cregex.c index 9b7179b6..ac94a5dd 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -870,8 +870,8 @@ _regcomp1(_Reprog *pp, _Parser *par, const char *s, int cflags) par->error = CREG_OUTOFMEMORY; return NULL; } - pp->flags.icase = (cflags & CREG_C_ICASE) != 0; - pp->flags.dotall = (cflags & CREG_C_DOTALL) != 0; + pp->flags.icase = (cflags & CREG_ICASE) != 0; + pp->flags.dotall = (cflags & CREG_DOTALL) != 0; par->freep = pp->firstinst; par->classp = pp->cclass; par->error = 0; @@ -1116,7 +1116,7 @@ _regexec1(const _Reprog *progp, /* program to run */ /* efficiency: advance and re-evaluate */ continue; case TOK_END: /* Match! */ - match = !(mflags & CREG_M_FULLMATCH) || + match = !(mflags & CREG_FULLMATCH) || ((s == j->eol || r == 0 || r == '\n') && (tlp->se.m[0].str == bol || tlp->se.m[0].str[-1] == '\n')); tlp->se.m[0].size = (s - tlp->se.m[0].str); @@ -1184,9 +1184,9 @@ _regexec(const _Reprog *progp, /* program to run */ j.eol = NULL; if (mp && mp[0].size) { - if (mflags & CREG_M_STARTEND) + if (mflags & CREG_STARTEND) j.starts = mp[0].str, j.eol = mp[0].str + mp[0].size; - else if (mflags & CREG_M_NEXT) + else if (mflags & CREG_NEXT) j.starts = mp[0].str + mp[0].size; } @@ -1298,7 +1298,7 @@ cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int cou csview match[CREG_MAX_CAPTURES]; int nmatch = cregex_captures(re) + 1; if (!count) count = INT32_MAX; - bool copy = !(rflags & CREG_R_STRIP); + bool copy = !(rflags & CREG_STRIP); while (count-- && cregex_find_sv(re, input, match) == CREG_OK) { _build_subst(replace, nmatch, match, mfun, &subst); -- cgit v1.2.3 From 071b41c0fe95cb3f9a72bbe0417d856e7989ca08 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 9 Jul 2023 00:06:54 +0200 Subject: Backport from dev43: Bugfixes on 4.2 from raspberry pi 32-bit testing. Fixes issue #61: too small int used in example. --- misc/examples/make.sh | 2 +- misc/examples/prime.c | 20 +++++++++++--------- misc/examples/queue.c | 2 +- misc/examples/random.c | 2 +- misc/tests/cspan_test.c | 5 ++--- misc/tests/ctest.h | 3 ++- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/misc/examples/make.sh b/misc/examples/make.sh index 0297e5a1..b0c0bd52 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -6,7 +6,7 @@ if [ "$(uname)" = 'Linux' ]; then oflag='-o ' fi -cc=gcc; cflags="-s -O3 -std=c99 -Wconversion -Wpedantic -Wall -Wsign-compare -Wwrite-strings" +cc=gcc; cflags="-s -O3 -std=c99 -Wconversion -Wpedantic -Wall -Wsign-compare -Wwrite-strings -Wno-maybe-uninitialized" #cc=gcc; cflags="-g -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" #cc=tcc; cflags="-Wall -std=c99" #cc=clang; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall -Wno-unused-function -Wsign-compare -Wwrite-strings" diff --git a/misc/examples/prime.c b/misc/examples/prime.c index d0887353..c3a0663c 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -5,20 +5,22 @@ #include #include +typedef long long llong; -cbits sieveOfEratosthenes(int64_t n) + +cbits sieveOfEratosthenes(llong n) { cbits bits = cbits_with_size(n/2 + 1, true); - int64_t q = (int64_t)sqrt((double) n) + 1; - for (int64_t i = 3; i < q; i += 2) { - int64_t j = i; + llong q = (llong)sqrt((double) n) + 1; + for (llong i = 3; i < q; i += 2) { + llong j = i; for (; j < n; j += 2) { if (cbits_test(&bits, j>>1)) { i = j; break; } } - for (int64_t j = i*i; j < n; j += i*2) + for (llong j = i*i; j < n; j += i*2) cbits_reset(&bits, j>>1); } return bits; @@ -26,15 +28,15 @@ cbits sieveOfEratosthenes(int64_t n) int main(void) { - int64_t n = 1000000000; - printf("Computing prime numbers up to %" c_ZI "\n", n); + llong n = 100000000; + printf("Computing prime numbers up to %lld\n", n); clock_t t1 = clock(); cbits primes = sieveOfEratosthenes(n + 1); - int64_t np = cbits_count(&primes); + llong np = cbits_count(&primes); clock_t t2 = clock(); - printf("Number of primes: %" c_ZI ", time: %f\n\n", np, (float)(t2 - t1) / (float)CLOCKS_PER_SEC); + printf("Number of primes: %lld, time: %f\n\n", np, (float)(t2 - t1) / (float)CLOCKS_PER_SEC); puts("Show all the primes in the range [2, 1000):"); printf("2"); c_forrange (i, 3, 1000, 2) diff --git a/misc/examples/queue.c b/misc/examples/queue.c index 83c18d09..90c800aa 100644 --- a/misc/examples/queue.c +++ b/misc/examples/queue.c @@ -6,7 +6,7 @@ #include int main() { - int n = 100000000; + int n = 1000000; crand_unif_t dist; crand_t rng = crand_init(1234); dist = crand_unif_init(0, n); diff --git a/misc/examples/random.c b/misc/examples/random.c index ea9c483e..b4b437cf 100644 --- a/misc/examples/random.c +++ b/misc/examples/random.c @@ -4,7 +4,7 @@ int main() { - const size_t N = 1000000000; + const size_t N = 10000000; const uint64_t seed = (uint64_t)time(NULL), range = 1000000; crand_t rng = crand_init(seed); diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index 5d46f579..83ac762b 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -112,10 +112,9 @@ CTEST_TEARDOWN(cspan_cube) { CTEST_F(cspan_cube, slice3) { - intptr_t n = cstack_int_size(&_self->stack); - //printf("\ntiles: %zi, cells: %zi\n", Tiles_size(&_self->tiles), n); + long long n = cstack_int_size(&_self->stack); + long long sum = 0; - int64_t sum = 0; // iterate each 3d tile in sequence c_foreach (i, Tiles, _self->tiles) c_foreach (t, intspan3, *i.ref) diff --git a/misc/tests/ctest.h b/misc/tests/ctest.h index 373cda0e..6b1b1084 100644 --- a/misc/tests/ctest.h +++ b/misc/tests/ctest.h @@ -408,7 +408,8 @@ void assert_dbl_compare(const char* cmp, double exp, double real, double tol, co void assert_pointers(const char* cmp, const void* exp, const void* real, const char* caller, int line) { if ((exp == real) != (cmp[0] == '=')) { - CTEST_ERR("%s:%d assertion failed (0x%02llx) %s (0x%02llx)", caller, line, (unsigned long long)exp , cmp, (unsigned long long)real); + CTEST_ERR("%s:%d assertion failed (0x%02llx) %s (0x%02llx)", caller, line, + (unsigned long long)(uintptr_t)exp , cmp, (unsigned long long)(uintptr_t)real); } } -- cgit v1.2.3 From afc968975a057f5b2653e3cfa51ef2eff83a8d5b Mon Sep 17 00:00:00 2001 From: tylov Date: Tue, 11 Jul 2023 16:36:55 +0200 Subject: Internal updates and doc reorg. --- docs/cspan_api.md | 41 ++++++++-------- include/stc/cspan.h | 72 +++++++++++++++------------- misc/benchmarks/various/cspan_bench.c | 14 +++--- misc/benchmarks/various/string_bench_STD.cpp | 1 + misc/examples/multidim.c | 1 - 5 files changed, 67 insertions(+), 62 deletions(-) diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 58b06af0..e2636086 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -29,7 +29,11 @@ a compile error is issued. Runtime bounds checks are enabled by default (define SpanType cspan_init(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from compatible STC container SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from C array -SpanTypeN cspan_md(char order, ValueType* data, d1, d2, ...); // make a multi-dim cspan. order: 'C' or 'F' (Fortran) + + // make a subspan of input span rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); +SpanType cspan_subspan(const SpanType* span, intptr_t offset, intptr_t count); +SpanType2 cspan_subspan2(const SpanType2* span, intptr_t offset, intptr_t count); +SpanType3 cspan_subspan3(const SpanType3* span, intptr_t offset, intptr_t count); intptr_t cspan_size(const SpanTypeN* self); // return number of elements intptr_t cspan_rank(const SpanTypeN* self); // dimensions; compile time constant @@ -39,35 +43,30 @@ ValueType* cspan_at(const SpanTypeN* self, intptr_t x, ...); // #args mus ValueType* cspan_front(const SpanTypeN* self); ValueType* cspan_back(const SpanTypeN* self); - // general index slicing to create a subspan. - // {i} reduces rank. {i,c_END} slice to end. {c_ALL} use the full extent. -SpanTypeR cspan_slice(T SpanTypeR, const SpanTypeN* self, {x0,x1}, {y0,y1}.., {N0,N1}); +SpanTypeN_iter SpanType_begin(const SpanTypeN* self); +SpanTypeN_iter SpanType_end(const SpanTypeN* self); +void SpanType_next(SpanTypeN_iter* it); +SpanTypeN cspan_md(char order, ValueType* data, d1, d2, ...); // make a multi-dim cspan. order: 'C' or 'F' (Fortran) // transpose the md span (inverse axes). no changes to the underlying array. void cspan_transpose(const SpanTypeN* self); - - // create a subspan of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); -SpanType cspan_submd2(const SpanType2* self, intptr_t x); // return a 1d subspan from a 2d span. -SpanTypeN cspan_submd3(const SpanType3* self, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span. -SpanTypeN cspan_submd4(const SpanType4* self, intptr_t x, ...); // number of args determines rank of output span. - // create a subspan of same rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); -SpanType cspan_subspan(const SpanType* self, intptr_t offset, intptr_t count); -SpanType2 cspan_subspan2(const SpanType2* self, intptr_t offset, intptr_t count); -SpanType3 cspan_subspan3(const SpanType3* self, intptr_t offset, intptr_t count); + // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); +OutSpan1 cspan_submd2(const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span. +OutSpanN cspan_submd3(const SpanType3* parent, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span. +OutSpanN cspan_submd4(const SpanType4* parent, intptr_t x, ...); // number of args decides rank of output span. -SpanTypeN_iter SpanType_begin(const SpanTypeN* self); -SpanTypeN_iter SpanType_end(const SpanTypeN* self); -void SpanType_next(SpanTypeN_iter* it); + // general slicing of an md span. + // {i}: reduce rank. {i,c_END}: slice to end. {c_ALL}: use full extent. +OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeN* parent, {x0,x1}, {y0,y1}.., {N0,N1}); ``` -## Types - -| Type name | Type definition | Used to represent... | +## TypesPd +| Type name | Type definition / usage | Used to represent... | |:------------------|:----------------------------------------------------|:---------------------| | SpanTypeN | `struct { ValueType *data; uint32_t shape[N]; .. }` | SpanType with rank N | | SpanTypeN`_value` | `ValueType` | The ValueType | -| `c_ALL` | | Full extent | -| `c_END` | | End of extent | +| `c_ALL` | Use with `cspan_slice()`. | Full extent | +| `c_END` | " | End of extent | ## Example 1 diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 7a0e9c8d..027b5275 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -107,58 +107,37 @@ int demo2() { #define using_cspan2(Self, T) using_cspan_3(Self, T, 1); using_cspan_3(Self##2, T, 2) #define using_cspan3(Self, T) using_cspan2(Self, T); using_cspan_3(Self##3, T, 3) #define using_cspan4(Self, T) using_cspan3(Self, T); using_cspan_3(Self##4, T, 4) -typedef struct { int32_t d[1]; } cspan_tuple1; -typedef struct { int32_t d[2]; } cspan_tuple2; -typedef struct { int32_t d[3]; } cspan_tuple3; -typedef struct { int32_t d[4]; } cspan_tuple4; -typedef struct { int32_t d[5]; } cspan_tuple5; -typedef struct { int32_t d[6]; } cspan_tuple6; +#define using_cspan_tuple(N) typedef struct { int32_t d[N]; } cspan_tuple##N +using_cspan_tuple(1); using_cspan_tuple(2); +using_cspan_tuple(3); using_cspan_tuple(4); +using_cspan_tuple(5); using_cspan_tuple(6); +using_cspan_tuple(7); using_cspan_tuple(8); + #define c_END -1 #define c_ALL 0,-1 -#define cspan_md(order, array, ...) \ - {.data=array, .shape={__VA_ARGS__}, \ - .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(order, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} - -#define cspan_transpose(self) \ - _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self)) - /* Use cspan_init() for static initialization only. c_init() for non-static init. */ #define cspan_init(SpanType, ...) \ {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}, .stride={.d={1}}} -#define cspan_slice(OutSpan, parent, ...) \ - OutSpan##_slice_((parent)->data, (parent)->shape, (parent)->stride.d, cspan_rank(parent) + \ - c_static_assert(cspan_rank(parent) == sizeof((int32_t[][2]){__VA_ARGS__})/sizeof(int32_t[2])), \ - (const int32_t[][2]){__VA_ARGS__}) - /* create a cspan from a cvec, cstack, cdeq, cqueue, or cpque (heap) */ #define cspan_from(container) \ {.data=(container)->data, .shape={(int32_t)(container)->_len}, .stride={.d={1}}} #define cspan_from_array(array) \ - {.data=(array) + c_static_assert(sizeof(array) != sizeof(void*)), .shape={c_arraylen(array)}, .stride={.d={1}}} + {.data=(array), .shape={c_arraylen(array)}, .stride={.d={1}}} #define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) #define cspan_rank(self) c_arraylen((self)->shape) #define cspan_is_order_F(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) #define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) -#define cspan_idx_1 cspan_idx_3 -#define cspan_idx_2 cspan_idx_3 -#define cspan_idx_3(self, ...) \ - c_PASTE(_cspan_idx, c_NUMARGS(__VA_ARGS__))((self)->shape, (self)->stride, __VA_ARGS__) // small/fast -#define cspan_idx_4(self, ...) \ - (_cspan_idxN(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \ - c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general -#define cspan_idx_5 cspan_idx_4 -#define cspan_idx_6 cspan_idx_4 #define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__)) #define cspan_front(self) ((self)->data) #define cspan_back(self) ((self)->data + cspan_size(self) - 1) -// cspan_subspanN. (N<=3) Optimized, same as e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); +// cspan_subspanX: (X <= 3) optimized. Similar to cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); #define cspan_subspan(self, offset, count) \ {.data=cspan_at(self, offset), .shape={count}, .stride=(self)->stride} #define cspan_subspan2(self, offset, count) \ @@ -166,16 +145,17 @@ typedef struct { int32_t d[6]; } cspan_tuple6; #define cspan_subspan3(self, offset, count) \ {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride=(self)->stride} -// cspan_submdN: reduce rank (N<=4) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); -#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__) -#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__) + +// cspan_submd(): Reduce rank (N <= 4) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); #define cspan_submd2(self, x) \ {.data=cspan_at(self, x, 0), .shape={(self)->shape[1]}, .stride={.d={(self)->stride.d[1]}}} +#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__) #define cspan_submd3_2(self, x) \ {.data=cspan_at(self, x, 0, 0), .shape={(self)->shape[1], (self)->shape[2]}, \ .stride={.d={(self)->stride.d[1], (self)->stride.d[2]}}} #define cspan_submd3_3(self, x, y) \ {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}, .stride={.d={(self)->stride.d[2]}}} +#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__) #define cspan_submd4_2(self, x) \ {.data=cspan_at(self, x, 0, 0, 0), .shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \ .stride={.d={(self)->stride.d[1], (self)->stride.d[2], (self)->stride.d[3]}}} @@ -185,7 +165,33 @@ typedef struct { int32_t d[6]; } cspan_tuple6; #define cspan_submd4_4(self, x, y, z) \ {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}, .stride={.d={(self)->stride.d[3]}}} -// private definitions: + +#define cspan_md(order, array, ...) \ + {.data=array, .shape={__VA_ARGS__}, \ + .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(order, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} + +#define cspan_transpose(self) \ + _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self)) + + +// General slicing function; +#define cspan_slice(OutSpan, parent, ...) \ + OutSpan##_slice_((parent)->data, (parent)->shape, (parent)->stride.d, cspan_rank(parent) + \ + c_static_assert(cspan_rank(parent) == sizeof((int32_t[][2]){__VA_ARGS__})/sizeof(int32_t[2])), \ + (const int32_t[][2]){__VA_ARGS__}) + +// ----------- private definitions ------------ + +// cspan_index() helpers: +#define cspan_idx_1 cspan_idx_3 +#define cspan_idx_2 cspan_idx_3 +#define cspan_idx_3(self, ...) \ + c_PASTE(_cspan_idx, c_NUMARGS(__VA_ARGS__))((self)->shape, (self)->stride, __VA_ARGS__) // small/fast +#define cspan_idx_4(self, ...) \ + (_cspan_idxN(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \ + c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general +#define cspan_idx_5 cspan_idx_4 +#define cspan_idx_6 cspan_idx_4 STC_INLINE intptr_t _cspan_size(const int32_t shape[], int rank) { intptr_t sz = shape[0]; diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c index 6ca7425d..e724bdbd 100644 --- a/misc/benchmarks/various/cspan_bench.c +++ b/misc/benchmarks/various/cspan_bench.c @@ -12,8 +12,8 @@ enum { nz = 64 }; int lx = 15, ly = 10, lz = 5; -int hx = 20, hy = 15, hz = 15; -intptr_t n = 1000000; +int hx = 30, hy = 15, hz = 15; +intptr_t n = 100000; // define the contents of two nx x ny x nz arrays in and out double Vout[nx * ny * nz]; @@ -49,10 +49,10 @@ static void TraditionalForLoop(intptr_t state) for (int s = 0; s < state; ++s) { for (int x = lx; x < hx; ++x) { for (int y = ly; y < hy; ++y) { - for (int z = lz; z < hz; ++z) - { - double d = Vin[nz*(ny*x + y) + z]; - Vout[nz*(ny*x + y) + z] += d; + for (int z = lz; z < hz; ++z) { + int i = nz*(ny*x + y) + z; + double d = Vin[i]; + Vout[i] += d; sum += d; } } @@ -64,13 +64,13 @@ static void TraditionalForLoop(intptr_t state) static void MDRanges_nested_loop(intptr_t state) { + clock_t t = clock(); MD3 r_in = cspan_md('C', Vin, nx, ny, nz); MD3 r_out = cspan_md('C', Vout, nx, ny, nz); r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); // C++23: for (auto [o, i] : std::views::zip(flat(r_out), flat(r_in))) { o = i; } - clock_t t = clock(); double sum = 0; for (intptr_t s = 0; s < state; ++s) { diff --git a/misc/benchmarks/various/string_bench_STD.cpp b/misc/benchmarks/various/string_bench_STD.cpp index 8bb87937..07934948 100644 --- a/misc/benchmarks/various/string_bench_STD.cpp +++ b/misc/benchmarks/various/string_bench_STD.cpp @@ -12,6 +12,7 @@ #include #define i_static #include +#include std::vector read_file(const char* name) { diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c index df8f485d..43c21443 100644 --- a/misc/examples/multidim.c +++ b/misc/examples/multidim.c @@ -28,7 +28,6 @@ int main() } puts("ss3 = ms3[:, 1:3, 1:3]"); ispan3 ss3 = ms3; - //cspan_slice(&ss3, {c_ALL}, {1,3}, {1,3}); ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3}); for (int i=0; i != ss3.shape[0]; i++) { -- cgit v1.2.3 From 0bcb0fcd981cb15329dfd4fb675097564164da18 Mon Sep 17 00:00:00 2001 From: tylov Date: Tue, 11 Jul 2023 22:16:09 +0200 Subject: Fixed an issue in template.h Reverted to cspan_md() and cspan_md_left() for column-major. Changed cspan_submdX(): add OutputSpanType as first parameter - aligns with cspan_slice() and adds type safety. --- docs/cspan_api.md | 14 ++++++------ include/stc/cspan.h | 42 +++++++++++++++++++++-------------- include/stc/priv/template.h | 6 ++++- misc/benchmarks/various/cspan_bench.c | 12 +++++----- misc/examples/multidim.c | 6 ++--- misc/tests/cspan_test.c | 12 +++++----- 6 files changed, 52 insertions(+), 40 deletions(-) diff --git a/docs/cspan_api.md b/docs/cspan_api.md index e2636086..4262b1ef 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -52,9 +52,9 @@ SpanTypeN cspan_md(char order, ValueType* data, d1, d2, ...); // make a mu void cspan_transpose(const SpanTypeN* self); // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); -OutSpan1 cspan_submd2(const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span. -OutSpanN cspan_submd3(const SpanType3* parent, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span. -OutSpanN cspan_submd4(const SpanType4* parent, intptr_t x, ...); // number of args decides rank of output span. +OutSpan1 cspan_submd2(TYPE OutSpan1, const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span. +OutSpanN cspan_submd3(TYPE OutSpanN, const SpanType3* parent, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span. +OutSpanN cspan_submd4(TYPE OutSpanN, const SpanType4* parent, intptr_t x, ...); // number of args decides rank of output span. // general slicing of an md span. // {i}: reduce rank. {i,c_END}: slice to end. {c_ALL}: use full extent. @@ -101,9 +101,9 @@ using_cspan3(myspan, int); // define myspan, myspan2, myspan3. int main() { int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; - myspan3 ms3 = cspan_md('C', arr, 2, 3, 4); // C-order, i.e. row-major. + myspan3 ms3 = cspan_md(arr, 2, 3, 4); // C-order, i.e. row-major. myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {1,3}, {2,c_END}); - myspan2 ss2 = cspan_submd3(&ss3, 1); + myspan2 ss2 = cspan_submd3(myspan2, &ss3, 1); c_forrange (i, ss2.shape[0]) c_forrange (j, ss2.shape[1]) @@ -150,10 +150,10 @@ int main() Span span = c_init(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}); // create a 3d cspan: - Span3 span3 = cspan_md('C', span.data, 2, 4, 3); + Span3 span3 = cspan_md(span.data, 2, 4, 3); // reduce rank: (i.e. span3[1]) - Span2 span2 = cspan_submd3(&span3, 1); + Span2 span2 = cspan_submd3(Span2, &span3, 1); puts("\niterate span2 flat:"); c_foreach (i, Span2, span2) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 027b5275..89986d6f 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -30,7 +30,7 @@ using_cspan(Intspan, int, 1); int demo1() { float raw[4*5]; - Span2f ms = cspan_md('C', raw, 4, 5); + Span2f ms = cspan_md(raw, 4, 5); for (int i=0; ishape[1]}, .stride={.d={(self)->stride.d[1]}}} -#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__) -#define cspan_submd3_2(self, x) \ - {.data=cspan_at(self, x, 0, 0), .shape={(self)->shape[1], (self)->shape[2]}, \ +#define cspan_submd2(OutSpan, self, ...) _cspan_submdN(OutSpan, 2, self, __VA_ARGS__) +#define cspan_submd3(OutSpan, self, ...) _cspan_submdN(OutSpan, 3, self, __VA_ARGS__) +#define cspan_submd4(OutSpan, self, ...) _cspan_submdN(OutSpan, 4, self, __VA_ARGS__) + +#define _cspan_submdN(OutSpan, N, self, ...) \ + _cspan_submd##N(c_static_assert(cspan_rank((OutSpan*)0) == N - c_NUMARGS(__VA_ARGS__)), self, __VA_ARGS__) + +#define _cspan_submd2(ok, self, x) \ + {.data=cspan_at(self, x, 0) + ok, .shape={(self)->shape[1]}, .stride={.d={(self)->stride.d[1]}}} +#define _cspan_submd3(...) c_MACRO_OVERLOAD(_cspan_submd3, __VA_ARGS__) +#define _cspan_submd3_3(ok, self, x) \ + {.data=cspan_at(self, x, 0, 0) + ok, .shape={(self)->shape[1], (self)->shape[2]}, \ .stride={.d={(self)->stride.d[1], (self)->stride.d[2]}}} -#define cspan_submd3_3(self, x, y) \ - {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}, .stride={.d={(self)->stride.d[2]}}} -#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__) -#define cspan_submd4_2(self, x) \ - {.data=cspan_at(self, x, 0, 0, 0), .shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \ +#define _cspan_submd3_4(ok, self, x, y) \ + {.data=cspan_at(self, x, y, 0) + ok, .shape={(self)->shape[2]}, .stride={.d={(self)->stride.d[2]}}} +#define _cspan_submd4(...) c_MACRO_OVERLOAD(_cspan_submd4, __VA_ARGS__) +#define _cspan_submd4_3(ok, self, x) \ + {.data=cspan_at(self, x, 0, 0, 0) + ok, .shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \ .stride={.d={(self)->stride.d[1], (self)->stride.d[2], (self)->stride.d[3]}}} -#define cspan_submd4_3(self, x, y) \ - {.data=cspan_at(self, x, y, 0, 0), .shape={(self)->shape[2], (self)->shape[3]}, \ +#define _cspan_submd4_4(ok, self, x, y) \ + {.data=cspan_at(self, x, y, 0, 0) + ok, .shape={(self)->shape[2], (self)->shape[3]}, \ .stride={.d={(self)->stride.d[2], (self)->stride.d[3]}}} -#define cspan_submd4_4(self, x, y, z) \ - {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}, .stride={.d={(self)->stride.d[3]}}} +#define _cspan_submd4_5(ok, self, x, y, z) \ + {.data=cspan_at(self, x, y, z, 0) + ok, .shape={(self)->shape[3]}, .stride={.d={(self)->stride.d[3]}}} - -#define cspan_md(order, array, ...) \ +#define cspan_md(array, ...) cspan_md_order('C', array, __VA_ARGS__) +#define cspan_md_left(array, ...) cspan_md_order('F', array, __VA_ARGS__) +#define cspan_md_order(order, array, ...) \ {.data=array, .shape={__VA_ARGS__}, \ .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(order, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 7138a87c..5551eeae 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -164,6 +164,8 @@ #error "No i_key or i_val defined" #elif defined i_keyraw ^ defined i_keyto #error "Both i_keyraw/valraw and i_keyto/valto must be defined, if any" +#elif defined i_keyfrom && !defined i_keyraw && !defined i_keyclone + #define i_keyclone i_keyfrom #elif defined i_keyfrom && !defined i_keyraw #error "i_keyfrom/valfrom defined without i_keyraw/valraw" #elif defined i_from || defined i_drop @@ -261,7 +263,9 @@ #error "i_val* must be defined for maps" #endif -#if !(defined i_valclone || defined i_no_clone) && (defined i_valdrop || defined i_valraw) +#if !defined i_valclone && defined i_valfrom && !defined i_valraw + #define i_valclone i_valfrom +#elif !(defined i_valclone || defined i_no_clone) && (defined i_valdrop || defined i_valraw) #error i_valclone should be defined when i_valdrop or i_valraw is defined #endif #ifndef i_valraw diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c index e724bdbd..392c9d3f 100644 --- a/misc/benchmarks/various/cspan_bench.c +++ b/misc/benchmarks/various/cspan_bench.c @@ -28,8 +28,8 @@ static void MDRanges_setup(intptr_t state) for (intptr_t s = 0; s < state; ++s) { - MD3 r_in = cspan_md('C', Vin, nx, ny, nz); - MD3 r_out = cspan_md('C', Vout, nx, ny, nz); + MD3 r_in = cspan_md(Vin, nx, ny, nz); + MD3 r_out = cspan_md(Vout, nx, ny, nz); r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); @@ -65,8 +65,8 @@ static void TraditionalForLoop(intptr_t state) static void MDRanges_nested_loop(intptr_t state) { clock_t t = clock(); - MD3 r_in = cspan_md('C', Vin, nx, ny, nz); - MD3 r_out = cspan_md('C', Vout, nx, ny, nz); + MD3 r_in = cspan_md(Vin, nx, ny, nz); + MD3 r_out = cspan_md(Vout, nx, ny, nz); r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); @@ -91,8 +91,8 @@ static void MDRanges_nested_loop(intptr_t state) static void MDRanges_loop_over_joined(intptr_t state) { - MD3 r_in = cspan_md('C', Vin, nx, ny, nz); - MD3 r_out = cspan_md('C', Vout, nx, ny, nz); + MD3 r_in = cspan_md(Vin, nx, ny, nz); + MD3 r_out = cspan_md(Vout, nx, ny, nz); r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c index 43c21443..dbea9699 100644 --- a/misc/examples/multidim.c +++ b/misc/examples/multidim.c @@ -14,7 +14,7 @@ int main() ispan ms1 = cspan_from(&v); // View the same data as a 3D array 2 x 3 x 4 - ispan3 ms3 = cspan_md('C', v.data, 2, 3, 4); + ispan3 ms3 = cspan_md(v.data, 2, 3, 4); puts("ms3:"); for (int i=0; i != ms3.shape[0]; i++) { @@ -45,7 +45,7 @@ int main() printf(" %d", *i.ref); puts(""); - ispan2 ms2 = cspan_submd3(&ms3, 0); + ispan2 ms2 = cspan_submd3(ispan2, &ms3, 0); // write data using 2D view for (int i=0; i != ms2.shape[0]; i++) @@ -58,7 +58,7 @@ int main() puts(""); puts("iterate subspan ms3[1]:"); - ispan2 sub = cspan_submd3(&ms3, 1); + ispan2 sub = cspan_submd3(ispan2, &ms3, 1); c_foreach (i, ispan2, sub) printf(" %d", *i.ref); puts(""); diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index b6953936..6834dce1 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -8,12 +8,12 @@ using_cspan3(intspan, int); CTEST(cspan, subdim) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - intspan3 m = cspan_md('C', array, 2, 2, 3); + intspan3 m = cspan_md(array, 2, 2, 3); for (size_t i = 0; i < m.shape[0]; ++i) { - intspan2 sub_i = cspan_submd3(&m, i); + intspan2 sub_i = cspan_submd3(intspan2, &m, i); for (size_t j = 0; j < m.shape[1]; ++j) { - intspan sub_i_j = cspan_submd2(&sub_i, j); + intspan sub_i_j = cspan_submd2(intspan, &sub_i, j); for (size_t k = 0; k < m.shape[2]; ++k) { ASSERT_EQ(*cspan_at(&sub_i_j, k), *cspan_at(&m, i, j, k)); } @@ -23,7 +23,7 @@ CTEST(cspan, subdim) { CTEST(cspan, slice) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - intspan2 m1 = cspan_md('C', array, 3, 4); + intspan2 m1 = cspan_md(array, 3, 4); size_t sum1 = 0; for (size_t i = 0; i < m1.shape[0]; ++i) { @@ -53,7 +53,7 @@ CTEST(cspan, slice2) { c_forrange (i, 10*20*30) cstack_int_push(&stack, i); - intspan3 ms3 = cspan_md('C', stack.data, 10, 20, 30); + intspan3 ms3 = cspan_md(stack.data, 10, 20, 30); ms3 = cspan_slice(intspan3, &ms3, {1,4}, {3,7}, {20,24}); size_t sum = 0; @@ -93,7 +93,7 @@ CTEST_SETUP(cspan_cube) { c_forrange (i, N) cstack_int_push(&_self->stack, i+1); - intspan3 ms3 = cspan_md('C', _self->stack.data, CUBE, CUBE, CUBE); + intspan3 ms3 = cspan_md(_self->stack.data, CUBE, CUBE, CUBE); c_forrange (i, 0, ms3.shape[0], TSIZE) { c_forrange (j, 0, ms3.shape[1], TSIZE) { -- cgit v1.2.3 From 50cbc73d4fef3ce91d094b80a018769eac439965 Mon Sep 17 00:00:00 2001 From: tylov Date: Wed, 12 Jul 2023 12:38:40 +0200 Subject: template.h: i_valclone and i_valfrom are considered the same when only one is defined and i_valraw is not defined (directly or via valclass/valboxed/val_str). Also applies to key. Some adjustments for benchmarking. --- include/stc/priv/template.h | 41 +++++++++++++++++---------- misc/benchmarks/plotbench/clist_benchmark.cpp | 2 +- misc/benchmarks/plotbench/run_clang.sh | 10 +++---- misc/benchmarks/plotbench/run_gcc.sh | 10 +++---- misc/examples/new_list.c | 5 ++-- 5 files changed, 40 insertions(+), 28 deletions(-) diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 5551eeae..30ed5732 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -105,6 +105,9 @@ #if c_option(c_native_cmp) #define i_native_cmp #endif +#if c_option(c_no_clone) || defined _i_carc + #define i_no_clone +#endif #if defined i_key_str #define i_keyclass cstr @@ -160,14 +163,20 @@ #endif #endif +#if !defined i_keyraw && !defined i_no_clone + #if !defined i_keyfrom && defined i_keyclone + #define i_keyfrom i_keyclone + #elif !defined i_keyclone && defined i_keyfrom + #define i_keyclone i_keyfrom + #endif +#endif + #if !defined i_key #error "No i_key or i_val defined" #elif defined i_keyraw ^ defined i_keyto - #error "Both i_keyraw/valraw and i_keyto/valto must be defined, if any" -#elif defined i_keyfrom && !defined i_keyraw && !defined i_keyclone - #define i_keyclone i_keyfrom -#elif defined i_keyfrom && !defined i_keyraw - #error "i_keyfrom/valfrom defined without i_keyraw/valraw" + #error "Both i_keyraw/i_valraw and i_keyto/i_valto must be defined, if any" +#elif !defined i_no_clone && (defined i_keyclone ^ defined i_keydrop) + #error "Both i_keyclone/i_valclone and i_keydrop/i_valdrop must be defined, if any" #elif defined i_from || defined i_drop #error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead" #endif @@ -175,11 +184,6 @@ #ifndef i_tag #define i_tag i_key #endif -#if c_option(c_no_clone) || defined _i_carc - #define i_no_clone -#elif !(defined i_keyclone || defined i_no_clone) && (defined i_keydrop || defined i_keyraw) - #error i_keyclone/valclone should be defined when i_keydrop/valdrop or i_keyraw/valraw is defined -#endif #ifndef i_keyraw #define i_keyraw i_key #endif @@ -259,15 +263,22 @@ #endif #endif +#if !defined i_valraw && !defined i_no_clone + #if !defined i_valfrom && defined i_valclone + #define i_valfrom i_valclone + #elif !defined i_valclone && defined i_valfrom + #define i_valclone i_valfrom + #endif +#endif + #ifndef i_val #error "i_val* must be defined for maps" +#elif defined i_valraw ^ defined i_valto + #error "Both i_valraw and i_valto must be defined, if any" +#elif !defined i_no_clone && (defined i_valclone ^ defined i_valdrop) + #error "Both i_valclone and i_valdrop must be defined, if any" #endif -#if !defined i_valclone && defined i_valfrom && !defined i_valraw - #define i_valclone i_valfrom -#elif !(defined i_valclone || defined i_no_clone) && (defined i_valdrop || defined i_valraw) - #error i_valclone should be defined when i_valdrop or i_valraw is defined -#endif #ifndef i_valraw #define i_valraw i_val #endif diff --git a/misc/benchmarks/plotbench/clist_benchmark.cpp b/misc/benchmarks/plotbench/clist_benchmark.cpp index 703222b3..01bfbf83 100644 --- a/misc/benchmarks/plotbench/clist_benchmark.cpp +++ b/misc/benchmarks/plotbench/clist_benchmark.cpp @@ -12,7 +12,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 25000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 10000000, S = 0x3ffc, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } diff --git a/misc/benchmarks/plotbench/run_clang.sh b/misc/benchmarks/plotbench/run_clang.sh index c9dbac31..59d577d9 100644 --- a/misc/benchmarks/plotbench/run_clang.sh +++ b/misc/benchmarks/plotbench/run_clang.sh @@ -1,10 +1,10 @@ exe='' if [ "$OS" = "Windows_NT" ] ; then exe=".exe" ; fi -clang++ -I../../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp -clang++ -I../../include -O3 -o clist_benchmark$exe clist_benchmark.cpp -clang++ -I../../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp -clang++ -I../../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp -clang++ -I../../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp +clang++ -DNDEBUG -I../../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp +clang++ -DNDEBUG -I../../include -O3 -o clist_benchmark$exe clist_benchmark.cpp +clang++ -DNDEBUG -I../../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp +clang++ -DNDEBUG -I../../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp +clang++ -DNDEBUG -I../../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp c='Win-Clang-14.0.1' ./cdeq_benchmark$exe $c diff --git a/misc/benchmarks/plotbench/run_gcc.sh b/misc/benchmarks/plotbench/run_gcc.sh index 14d89b9a..73b979d3 100644 --- a/misc/benchmarks/plotbench/run_gcc.sh +++ b/misc/benchmarks/plotbench/run_gcc.sh @@ -1,8 +1,8 @@ -g++ -I../../include -O3 -o cdeq_benchmark cdeq_benchmark.cpp -g++ -I../../include -O3 -o clist_benchmark clist_benchmark.cpp -g++ -I../../include -O3 -o cmap_benchmark cmap_benchmark.cpp -g++ -I../../include -O3 -o csmap_benchmark csmap_benchmark.cpp -g++ -I../../include -O3 -o cvec_benchmark cvec_benchmark.cpp +g++ -DNDEBUG -I../../include -O3 -o cdeq_benchmark cdeq_benchmark.cpp +g++ -DNDEBUG -I../../include -O3 -o clist_benchmark clist_benchmark.cpp +g++ -DNDEBUG -I../../include -O3 -o cmap_benchmark cmap_benchmark.cpp +g++ -DNDEBUG -I../../include -O3 -o csmap_benchmark csmap_benchmark.cpp +g++ -DNDEBUG -I../../include -O3 -o cvec_benchmark cvec_benchmark.cpp c='Mingw-g++-11.3.0' ./cdeq_benchmark $c diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index 8083c315..5ffdaca2 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -32,8 +32,9 @@ int point_cmp(const Point* a, const Point* b) { void MyStruct_drop(MyStruct* s); #define i_type MyList -#define i_valclass MyStruct // MyStruct contains "class"-types, so define as "class" -#define i_opt c_no_clone|c_no_cmp // exclude cloning and comparison support +#define i_val MyStruct +#define i_valdrop MyStruct_drop // define drop function +#define i_no_clone // must explicitely exclude or define cloning support because of drop. #include void MyStruct_drop(MyStruct* s) { -- cgit v1.2.3 From 715a02ba8155de2f7d446e8d7d2ae305c27996b9 Mon Sep 17 00:00:00 2001 From: tylov Date: Wed, 12 Jul 2023 15:19:45 +0200 Subject: Fixed usage of `const i_key` in cvec API, should be `const _cx_value`. Removed cvec_insert(), use cvec_insert_n(). --- docs/cdeq_api.md | 1 - docs/cvec_api.md | 3 +-- include/stc/cvec.h | 6 +----- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index 99980c24..5a00d69a 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -63,7 +63,6 @@ cdeq_X_value* cdeq_X_emplace(cdeq_X* self, i_valraw raw); void cdeq_X_pop_back(cdeq_X* self); cdeq_X_iter cdeq_X_insert_n(cdeq_X* self, intptr_t idx, const i_val[] arr, intptr_t n); // move values -cdeq_X_iter cdeq_X_insert(cdeq_X* self, intptr_t idx, i_val value); // move value cdeq_X_iter cdeq_X_insert_at(cdeq_X* self, cdeq_X_iter it, i_val value); // move value cdeq_X_iter cdeq_X_insert_uninit(cdeq_X* self, intptr_t idx, intptr_t n); // uninitialized data // copy values: diff --git a/docs/cvec_api.md b/docs/cvec_api.md index fa7bf8ca..d19f4bae 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -70,8 +70,7 @@ cvec_X_value* cvec_X_emplace_back(cvec_X* self, i_valraw raw); // a void cvec_X_pop(cvec_X* self); void cvec_X_pop_back(cvec_X* self); // alias for pop -cvec_X_iter cvec_X_insert(cvec_X* self, intptr_t idx, i_val value); // move value -cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_val arr[], intptr_t n); // move values +cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_val arr[], intptr_t n); // move values cvec_X_iter cvec_X_insert_at(cvec_X* self, cvec_X_iter it, i_val value); // move value cvec_X_iter cvec_X_insert_uninit(cvec_X* self, intptr_t idx, intptr_t n); // return iter at idx diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 6806e2bc..e1d34365 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -167,11 +167,7 @@ _cx_MEMB(_insert_n)(_cx_Self* self, const intptr_t idx, const _cx_value arr[], c return it; } STC_INLINE _cx_iter -_cx_MEMB(_insert)(_cx_Self* self, const intptr_t idx, const i_key value) { - return _cx_MEMB(_insert_n)(self, idx, &value, 1); -} -STC_INLINE _cx_iter -_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, const i_key value) { +_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, const _cx_value value) { return _cx_MEMB(_insert_n)(self, _it_ptr(it) - self->data, &value, 1); } -- cgit v1.2.3 From ebe5abc29d51c643520301e42124365477f44957 Mon Sep 17 00:00:00 2001 From: tylov Date: Wed, 12 Jul 2023 19:39:59 +0200 Subject: Changed docs and examples to use i_key* template parameters instead of i_val* for all non-maps. Renamed c_ASSERT() to c_assert() and added optional message parameter to c_static_assert(). --- README.md | 36 ++++++++++---------- docs/carc_api.md | 38 ++++++++++----------- docs/cbox_api.md | 52 ++++++++++++++-------------- docs/ccommon_api.md | 10 +++--- docs/cdeq_api.md | 54 ++++++++++++++--------------- docs/clist_api.md | 56 +++++++++++++++--------------- docs/cpque_api.md | 32 +++++++++--------- docs/cqueue_api.md | 28 +++++++-------- docs/cset_api.md | 2 +- docs/cspan_api.md | 7 ++-- docs/csset_api.md | 2 +- docs/cstack_api.md | 38 ++++++++++----------- docs/csview_api.md | 2 +- docs/cvec_api.md | 64 +++++++++++++++++------------------ include/stc/algo/sort.h | 21 +++++++----- include/stc/cbits.h | 8 ++--- include/stc/ccommon.h | 14 ++++---- include/stc/cdeq.h | 4 +-- include/stc/clist.h | 2 +- include/stc/cmap.h | 2 +- include/stc/cpque.h | 2 +- include/stc/cqueue.h | 4 +-- include/stc/cspan.h | 28 +++++++-------- include/stc/cstack.h | 8 ++--- include/stc/cvec.h | 8 ++--- include/stc/extend.h | 4 ++- misc/benchmarks/various/csort_bench.c | 2 +- misc/examples/arc_containers.c | 8 ++--- misc/examples/arc_demo.c | 8 ++--- misc/examples/arcvec_erase.c | 6 ++-- misc/examples/astar.c | 4 +-- misc/examples/box.c | 4 +-- misc/examples/box2.c | 6 ++-- misc/examples/cointerleave.c | 2 +- misc/examples/complex.c | 4 +-- misc/examples/convert.c | 4 +-- misc/examples/csmap_find.c | 2 +- misc/examples/csmap_insert.c | 2 +- misc/examples/demos.c | 6 ++-- misc/examples/forfilter.c | 4 +-- misc/examples/forloops.c | 2 +- misc/examples/functor.c | 2 +- misc/examples/inits.c | 6 ++-- misc/examples/intrusive.c | 2 +- misc/examples/list.c | 2 +- misc/examples/list_erase.c | 2 +- misc/examples/list_splice.c | 2 +- misc/examples/lower_bound.c | 4 +-- misc/examples/mmap.c | 2 +- misc/examples/multimap.c | 2 +- misc/examples/music_arc.c | 4 +-- misc/examples/new_list.c | 10 +++--- misc/examples/new_pque.c | 2 +- misc/examples/new_queue.c | 4 +-- misc/examples/new_sptr.c | 10 +++--- misc/examples/new_vec.c | 4 +-- misc/examples/person_arc.c | 4 +-- misc/examples/printspan.c | 8 ++--- misc/examples/priority.c | 2 +- misc/examples/queue.c | 2 +- misc/examples/rawptr_elements.c | 2 +- misc/examples/read.c | 2 +- misc/examples/regex_match.c | 2 +- misc/examples/scheduler.c | 2 +- misc/examples/shape.c | 6 ++-- misc/examples/stack.c | 4 +-- misc/tests/cspan_test.c | 4 +-- 67 files changed, 348 insertions(+), 338 deletions(-) diff --git a/README.md b/README.md index ab350488..67c4d7fd 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ List of contents 1. ***Centralized analysis of template parameters***. The analyser assigns values to all non-specified template parameters (based on the specified ones) using meta-programming, so that you don't have to! You may specify a set of "standard" template parameters for each -container, but as a minimum *only one is required*: `i_val` (+ `i_key` for maps). In this +container, but as a minimum *only one is required*: `i_key` (+ `i_val` for maps). In this case, STC assumes that the elements are of basic types. For non-trivial types, additional template parameters must be given. 2. ***Alternative insert/lookup type***. You may specify an alternative type to use for @@ -118,7 +118,7 @@ Benchmark notes: - Container names are prefixed by `c`, e.g. `cvec`, `cstr`. - Public STC macros are prefixed by `c_`, e.g. `c_foreach`, `c_init`. -- Template parameter macros are prefixed by `i_`, e.g. `i_val`, `i_type`. +- Template parameter macros are prefixed by `i_`, e.g. `i_key`, `i_type`. - All containers can be initialized with `{0}`, i.e. no heap allocation used by default init. - Common types for a container type Con: - Con @@ -150,7 +150,7 @@ templated types in C++. However, to specify template parameters with STC, you de including the container: ```c #define i_type Floats // Container type name; unless defined name would be cvec_float -#define i_val float // Container element type +#define i_key float // Container element type #include // "instantiate" the desired container type #include @@ -177,7 +177,7 @@ You may switch to a different container type, e.g. a sorted set (csset): [ [Run this code](https://godbolt.org/z/qznfa65e1) ] ```c #define i_type Floats -#define i_val float +#define i_key float #include // Use a sorted set instead #include @@ -196,7 +196,7 @@ int main() } ``` For user-defined struct elements, `i_cmp` compare function should be defined as the default `<` and `==` -only works for integral types. *Alternatively, `#define i_opt c_no_cmp` to disable sorting and searching*. Similarily, if an element destructor `i_valdrop` is defined, `i_valclone` function is required. +only works for integral types. *Alternatively, `#define i_opt c_no_cmp` to disable sorting and searching*. Similarily, if an element destructor `i_keydrop` is defined, `i_keyclone` function is required. *Alternatively `#define i_opt c_no_clone` to disable container cloning.* Let's make a vector of vectors, which can be cloned. All of its element vectors will be destroyed when destroying the Vec2D. @@ -206,11 +206,11 @@ Let's make a vector of vectors, which can be cloned. All of its element vectors #include #define i_type Vec -#define i_val float +#define i_key float #include #define i_type Vec2D -#define i_valclass Vec // Use i_valclass when element type has "members" _clone(), _drop() and _cmp(). +#define i_keyclass Vec // Use i_keyclass when element type has "members" _clone(), _drop() and _cmp(). #define i_opt c_no_cmp // Disable cmp (search/sort) for Vec2D because Vec_cmp() is not defined. #include @@ -246,12 +246,12 @@ This example uses four different container types: struct Point { float x, y; }; // Define cvec_pnt with a less-comparison function for Point. -#define i_val struct Point +#define i_key struct Point #define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) #define i_tag pnt #include // cvec_pnt: vector of struct Point -#define i_val int +#define i_key int #include // clist_int: singly linked list #define i_key int @@ -369,10 +369,10 @@ or define your own, e.g.: #define i_tag ix #include // cset_ix -#define i_val int +#define i_key int #include // cvec_int -#define i_val Point +#define i_key Point #define i_tag pnt #include // clist_pnt ``` @@ -383,8 +383,8 @@ Each templated type requires one `#include`, even if it's the same container bas The template parameters are given by a `#define i_xxxx` statement, where *xxxx* is the parameter name. The list of template parameters: -- `i_key` *Type* - Element key type for map/set only. **[required]**. -- `i_val` *Type* - Element value type. **[required for]** cmap/csmap, it is the mapped value type. +- `i_key` *Type* - Element key type. **[required]**. Note: `i_val` *may* be used instead for non-maps (not recommended). +- `i_val` *Type* - Element value type. **[required for]** cmap/csmap as the mapped value type. - `i_cmp` *Func* - Three-way comparison of two *i_keyraw*\* or *i_valraw*\* - **[required for]** non-integral *i_keyraw* elements unless *i_opt* is defined with *c_no_cmp*. - `i_hash` *Func* - Hash function taking *i_keyraw*\* - defaults to *c_default_hash*. **[required for]** ***cmap/cset*** with non-POD *i_keyraw* elements. - `i_eq` *Func* - Equality comparison of two *i_keyraw*\* - defaults to *!i_cmp*. Companion with *i_hash*. @@ -458,7 +458,7 @@ and non-emplace methods: #define i_implement // define in ONE file to implement longer functions in cstr #include -#define i_val_str // special macro to enable container of cstr +#define i_key_str // special macro to enable container of cstr #include // vector of string (cstr) ... cvec_str vec = {0}; @@ -518,7 +518,7 @@ last example on the **cmap** page demonstrates how to specify a map with non-tri Define `i_type` instead of `i_tag`: ```c #define i_type MyVec -#define i_val int +#define i_key int #include myvec vec = MyVec_init(); @@ -543,7 +543,7 @@ typedef struct Dataset { // Implementation #define i_is_forward // flag that the container was forward declared. -#define i_val struct Point +#define i_key struct Point #define i_tag pnt #include ``` @@ -617,8 +617,8 @@ STC is generally very memory efficient. Memory usage for the different container - coroutines: much improved with some new API and added features. - cspan: Support for column-major (fortran order) multidim spans and transposed views. - Removed default comparison for clist, cvec and cdeq (as with cstack and cqueue). - - Using i_val_str, i_valclass, i_valboxed still expects comparisons defined. - - Define i_native_cmp to enable built-in i_val types comparisons (<, ==). + - Using i_key_str, i_keyclass, i_keyboxed still expects comparisons defined. + - Define i_native_cmp to enable built-in i_key types comparisons (<, ==). - cstr and csview are now shared linked by default. Static linking by defining i_static. - New cdeq and cqueue implementation(s), using circular buffer. - Renamed i_extern => i_import. diff --git a/docs/carc_api.md b/docs/carc_api.md index 22e6bac2..254f868a 100644 --- a/docs/carc_api.md +++ b/docs/carc_api.md @@ -6,14 +6,14 @@ deallocated when the last remaining **carc** owning the object is destroyed with The object is destroyed using *carc_X_drop()*. A **carc** may also own no objects, in which case it is called empty. The *carc_X_cmp()*, *carc_X_drop()* methods are defined based on -the `i_cmp` and `i_valdrop` macros specified. Use *carc_X_clone(p)* when sharing ownership of +the `i_cmp` and `i_keydrop` macros specified. Use *carc_X_clone(p)* when sharing ownership of the pointed-to object. All **carc** functions can be called by multiple threads on different instances of **carc** without additional synchronization even if these instances are copies and share ownership of the same object. **carc** uses thread-safe atomic reference counting, through the *carc_X_clone()* and *carc_X_drop()* methods. -When declaring a container with shared pointers, define `i_valboxed` with the carc type, see example. +When declaring a container with shared pointers, define `i_keyboxed` with the carc type, see example. See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) for a functional reference, or Rust [std::sync::Arc](https://doc.rust-lang.org/std/sync/struct.Arc.html) / [std::rc::Rc](https://doc.rust-lang.org/std/rc/struct.Rc.html). @@ -21,14 +21,14 @@ See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory ```c #define i_type // full typename of the carc -#define i_val // value: REQUIRED +#define i_key // element type: REQUIRED -#define i_valraw // convertion "raw" type - defaults to i_val -#define i_valto // convertion func i_val* => i_valraw: REQUIRED IF i_valraw defined. -#define i_valfrom // convertion func i_valraw => i_val +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. +#define i_keyfrom // convertion func i_keyraw => i_key #define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc. -#define i_tag // alternative typename: carc_{i_tag}. i_tag defaults to i_val +#define i_tag // alternative typename: carc_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -36,9 +36,9 @@ See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory ## Methods ```c carc_X carc_X_init(); // empty shared pointer -carc_X carc_X_from(i_valraw raw); // create an carc from raw type (available if i_valraw defined by user). -carc_X carc_X_from_ptr(i_val* p); // create an carc from raw pointer. Takes ownership of p. -carc_X carc_X_make(i_val val); // create an carc from constructed val object. Faster than from_ptr(). +carc_X carc_X_from(i_keyraw raw); // create an carc from raw type (available if i_keyraw defined by user). +carc_X carc_X_from_ptr(i_key* p); // create an carc from raw pointer. Takes ownership of p. +carc_X carc_X_make(i_key key); // create an carc from constructed key object. Faster than from_ptr(). carc_X carc_X_clone(carc_X other); // return other with increased use count carc_X carc_X_move(carc_X* self); // transfer ownership to receiver; self becomes NULL @@ -49,7 +49,7 @@ void carc_X_drop(carc_X* self); // destruct (decr long carc_X_use_count(const carc_X* self); void carc_X_reset(carc_X* self); -void carc_X_reset_to(carc_X* self, i_val* p); // assign new carc from ptr. Takes ownership of p. +void carc_X_reset_to(carc_X* self, i_key* p); // assign new carc from ptr. Takes ownership of p. uint64_t carc_X_hash(const carc_X* x); // hash value int carc_X_cmp(const carc_X* x, const carc_X* y); // compares pointer addresses if no `i_cmp` is specified. @@ -58,9 +58,9 @@ bool carc_X_eq(const carc_X* x, const carc_X* y); // carc_X_cmp() = // functions on pointed to objects. -uint64_t carc_X_value_hash(const i_val* x); -int carc_X_value_cmp(const i_val* x, const i_val* y); -bool carc_X_value_eq(const i_val* x, const i_val* y); +uint64_t carc_X_value_hash(const i_key* x); +int carc_X_value_cmp(const i_key* x, const i_key* y); +bool carc_X_value_eq(const i_key* x, const i_key* y); ``` ## Types and constants @@ -69,8 +69,8 @@ bool carc_X_value_eq(const i_val* x, const i_val* y); |:------------------|:--------------------------------------------------|:-----------------------| | `carc_null` | `{0}` | Init nullptr const | | `carc_X` | `struct { carc_X_value* get; long* use_count; }` | The carc type | -| `carc_X_value` | `i_val` | The carc element type | -| `carc_X_raw` | `i_valraw` | Convertion type | +| `carc_X_value` | `i_key` | The carc element type | +| `carc_X_raw` | `i_keyraw` | Convertion type | ## Example @@ -89,12 +89,12 @@ bool carc_X_value_eq(const i_val* x, const i_val* y); #include #define i_type Arc // (atomic) ref. counted pointer -#define i_val Map -#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p)) +#define i_key Map +#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) #include #define i_type Stack -#define i_valboxed Arc // Note: use i_valboxed for carc or cbox value types +#define i_keyboxed Arc // Note: use i_keyboxed for carc or cbox value types #include int main() diff --git a/docs/cbox_api.md b/docs/cbox_api.md index 9151f56d..83d59521 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -2,11 +2,11 @@ **cbox** is a smart pointer to a heap allocated value of type X. A **cbox** can be empty. The *cbox_X_cmp()*, *cbox_X_drop()* methods are defined based on the `i_cmp` -and `i_valdrop` macros specified. Use *cbox_X_clone(p)* to make a deep copy, which uses the -`i_valclone` macro if defined. +and `i_keydrop` macros specified. Use *cbox_X_clone(p)* to make a deep copy, which uses the +`i_keyclone` macro if defined. -When declaring a container of **cbox** values, define `i_valboxed` with the -cbox type instead of defining `i_val`. This will auto-set `i_valdrop`, `i_valclone`, and `i_cmp` using +When declaring a container of **cbox** values, define `i_keyboxed` with the +cbox type instead of defining `i_key`. This will auto-set `i_keydrop`, `i_keyclone`, and `i_cmp` using functions defined by the specified **cbox**. See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr) for a functional reference, or Rust [std::boxed::Box](https://doc.rust-lang.org/std/boxed/struct.Box.html) @@ -15,29 +15,29 @@ See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory ```c #define i_type // full typename of the cbox -#define i_val // value: REQUIRED -#define i_cmp // three-way compare two i_val* : REQUIRED IF i_val is a non-integral type -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED if i_valdrop is defined, unless 'i_opt c_no_clone' is defined. +#define i_key // element type: REQUIRED +#define i_cmp // three-way compare two i_key* : REQUIRED IF i_key is a non-integral type +#define i_keydrop // destroy element func - defaults to empty destruct +#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. -#define i_valraw // convertion type (lookup): default to {i_val} -#define i_valto // convertion func i_val* => i_valraw: REQUIRED IF i_valraw defined. -#define i_valfrom // from-raw func. +#define i_keyraw // convertion type (lookup): default to {i_key} +#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. +#define i_keyfrom // from-raw func. -#define i_valclass // alt. to i_val: REQUIRES that {i_val}_clone, {i_val}_drop, {i_valraw}_cmp exist. -#define i_tag // alternative typename: cbox_{i_tag}. i_tag defaults to i_val +#define i_keyclass // alt. to i_key: REQUIRES that {i_key}_clone, {i_key}_drop, {i_keyraw}_cmp exist. +#define i_tag // alternative typename: cbox_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. -Define `i_opt` with `c_no_cmp` if comparison between i_val's is not needed/available. Will then +Define `i_opt` with `c_no_cmp` if comparison between i_key's is not needed/available. Will then compare the pointer addresses when used. Additionally, `c_no_clone` or `i_is_fwd` may be defined. ## Methods ```c cbox_X cbox_X_init(); // return an empty cbox -cbox_X cbox_X_from(i_valraw raw); // create a cbox from raw type. Avail if i_valraw user defined. -cbox_X cbox_X_from_ptr(i_val* ptr); // create a cbox from a pointer. Takes ownership of ptr. -cbox_X cbox_X_make(i_val val); // create a cbox from unowned val object. +cbox_X cbox_X_from(i_keyraw raw); // create a cbox from raw type. Avail if i_keyraw user defined. +cbox_X cbox_X_from_ptr(i_key* ptr); // create a cbox from a pointer. Takes ownership of ptr. +cbox_X cbox_X_make(i_key val); // create a cbox from unowned val object. cbox_X cbox_X_clone(cbox_X other); // return deep copied clone cbox_X cbox_X_move(cbox_X* self); // transfer ownership to receiving cbox returned. self becomes NULL. @@ -46,7 +46,7 @@ void cbox_X_assign(cbox_X* self, cbox_X* moved); // transfer owners void cbox_X_drop(cbox_X* self); // destruct the contained object and free its heap memory. void cbox_X_reset(cbox_X* self); -void cbox_X_reset_to(cbox_X* self, i_val* p); // assign new cbox from ptr. Takes ownership of p. +void cbox_X_reset_to(cbox_X* self, i_key* p); // assign new cbox from ptr. Takes ownership of p. uint64_t cbox_X_hash(const cbox_X* x); // hash value int cbox_X_cmp(const cbox_X* x, const cbox_X* y); // compares pointer addresses if no `i_cmp` is specified. @@ -55,9 +55,9 @@ bool cbox_X_eq(const cbox_X* x, const cbox_X* y); // cbox_X_cmp() == // functions on pointed to objects. -uint64_t cbox_X_value_hash(const i_val* x); -int cbox_X_value_cmp(const i_val* x, const i_val* y); -bool cbox_X_value_eq(const i_val* x, const i_val* y); +uint64_t cbox_X_value_hash(const i_key* x); +int cbox_X_value_cmp(const i_key* x, const i_key* y); +bool cbox_X_value_eq(const i_key* x, const i_key* y); ``` ## Types and constants @@ -66,7 +66,7 @@ bool cbox_X_value_eq(const i_val* x, const i_val* y); |:-------------------|:--------------------------------|:------------------------| | `cbox_null` | `{0}` | Init nullptr const | | `cbox_X` | `struct { cbox_X_value* get; }` | The cbox type | -| `cbox_X_value` | `i_val` | The cbox element type | +| `cbox_X_value` | `i_key` | The cbox element type | ## Example @@ -77,9 +77,9 @@ void int_drop(int* x) { } #define i_type IBox -#define i_val int -#define i_valdrop int_drop // optional func, just to display elements destroyed -#define i_valclone(x) x // must specified when i_valdrop is defined. +#define i_key int +#define i_keydrop int_drop // optional func, just to display elements destroyed +#define i_keyclone(x) x // must specified when i_keydrop is defined. #include #define i_type ISet @@ -87,7 +87,7 @@ void int_drop(int* x) { #include // ISet : std::set> #define i_type IVec -#define i_valboxed IBox // NB: use i_valboxed instead of i_val +#define i_keyboxed IBox // NB: use i_keyboxed instead of i_key #include // IVec : std::vector> int main() diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 7569bb5b..52ad88e4 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -162,7 +162,7 @@ Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false. Make any container from an initializer list: ```c -#define i_val_str // owned cstr string value type +#define i_key_str // owned cstr string value type #include #define i_key int @@ -210,7 +210,7 @@ You may customize `i_tag` and the comparison function `i_cmp` or `i_less`. There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c). ```c -#define i_val int +#define i_key int #include #include @@ -224,7 +224,7 @@ Containers with random access may also be sorted. Even sorting cdeq/cqueue (with possible and very fast. Note that `i_more` must be defined to retain specified template parameters for use by sort: ```c #define i_type MyDeq -#define i_val int +#define i_key int #define i_more #include // deque #include @@ -273,7 +273,7 @@ int* ip = c_const_cast(int*, cs); // issues a warning! ### Predefined template parameter functions -**crawstr** - Non-owned `const char*` "class" element type: `#define i_valclass crawstr` +**crawstr** - Non-owned `const char*` "class" element type: `#define i_keyclass crawstr` ```c typedef const char* crawstr; int crawstr_cmp(const crawstr* x, const crawstr* y); @@ -485,7 +485,7 @@ return ok; #define i_implement #include -#define i_val_str +#define i_key_str #include // receiver should check errno variable diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index 5a00d69a..292b0933 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -11,16 +11,16 @@ See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque ```c #define i_type // full typename of the container -#define i_val // value: REQUIRED -#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined +#define i_key // value: REQUIRED +#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_valraw // convertion "raw" type - defaults to i_val -#define i_valfrom // convertion func i_valraw => i_val -#define i_valto // convertion func i_val* => i_valraw +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw -#define i_tag // alternative typename: cdeq_{i_tag}. i_tag defaults to i_val +#define i_tag // alternative typename: cdeq_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -44,30 +44,30 @@ intptr_t cdeq_X_capacity(const cdeq_X* self); const cdeq_X_value* cdeq_X_at(const cdeq_X* self, intptr_t idx); cdeq_X_value* cdeq_X_at_mut(cdeq_X* self, intptr_t idx); -const cdeq_X_value* cdeq_X_get(const cdeq_X* self, i_valraw raw); // return NULL if not found -cdeq_X_value* cdeq_X_get_mut(cdeq_X* self, i_valraw raw); // mutable get -cdeq_X_iter cdeq_X_find(const cdeq_X* self, i_valraw raw); -cdeq_X_iter cdeq_X_find_in(cdeq_X_iter i1, cdeq_X_iter i2, i_valraw raw); // return cvec_X_end() if not found +const cdeq_X_value* cdeq_X_get(const cdeq_X* self, i_keyraw raw); // return NULL if not found +cdeq_X_value* cdeq_X_get_mut(cdeq_X* self, i_keyraw raw); // mutable get +cdeq_X_iter cdeq_X_find(const cdeq_X* self, i_keyraw raw); +cdeq_X_iter cdeq_X_find_in(cdeq_X_iter i1, cdeq_X_iter i2, i_keyraw raw); // return cvec_X_end() if not found cdeq_X_value* cdeq_X_front(const cdeq_X* self); cdeq_X_value* cdeq_X_back(const cdeq_X* self); -cdeq_X_value* cdeq_X_push_front(cdeq_X* self, i_val value); -cdeq_X_value* cdeq_X_emplace_front(cdeq_X* self, i_valraw raw); +cdeq_X_value* cdeq_X_push_front(cdeq_X* self, i_key value); +cdeq_X_value* cdeq_X_emplace_front(cdeq_X* self, i_keyraw raw); void cdeq_X_pop_front(cdeq_X* self); -cdeq_X_value* cdeq_X_push_back(cdeq_X* self, i_val value); -cdeq_X_value* cdeq_X_push(cdeq_X* self, i_val value); // alias for push_back() -cdeq_X_value* cdeq_X_emplace_back(cdeq_X* self, i_valraw raw); -cdeq_X_value* cdeq_X_emplace(cdeq_X* self, i_valraw raw); // alias for emplace_back() +cdeq_X_value* cdeq_X_push_back(cdeq_X* self, i_key value); +cdeq_X_value* cdeq_X_push(cdeq_X* self, i_key value); // alias for push_back() +cdeq_X_value* cdeq_X_emplace_back(cdeq_X* self, i_keyraw raw); +cdeq_X_value* cdeq_X_emplace(cdeq_X* self, i_keyraw raw); // alias for emplace_back() void cdeq_X_pop_back(cdeq_X* self); -cdeq_X_iter cdeq_X_insert_n(cdeq_X* self, intptr_t idx, const i_val[] arr, intptr_t n); // move values -cdeq_X_iter cdeq_X_insert_at(cdeq_X* self, cdeq_X_iter it, i_val value); // move value +cdeq_X_iter cdeq_X_insert_n(cdeq_X* self, intptr_t idx, const i_key[] arr, intptr_t n); // move values +cdeq_X_iter cdeq_X_insert_at(cdeq_X* self, cdeq_X_iter it, i_key value); // move value cdeq_X_iter cdeq_X_insert_uninit(cdeq_X* self, intptr_t idx, intptr_t n); // uninitialized data // copy values: -cdeq_X_iter cdeq_X_emplace_n(cdeq_X* self, intptr_t idx, const i_valraw[] arr, intptr_t n); -cdeq_X_iter cdeq_X_emplace_at(cdeq_X* self, cdeq_X_iter it, i_valraw raw); +cdeq_X_iter cdeq_X_emplace_n(cdeq_X* self, intptr_t idx, const i_keyraw[] arr, intptr_t n); +cdeq_X_iter cdeq_X_emplace_at(cdeq_X* self, cdeq_X_iter it, i_keyraw raw); void cdeq_X_erase_n(cdeq_X* self, intptr_t idx, intptr_t n); cdeq_X_iter cdeq_X_erase_at(cdeq_X* self, cdeq_X_iter it); @@ -88,14 +88,14 @@ void cdeq_X_value_drop(cdeq_X_value* pval); | Type name | Type definition | Used to represent... | |:-------------------|:------------------------------------|:-----------------------| -| `cdeq_X` | `struct { cdeq_X_value* data; }` | The cdeq type | -| `cdeq_X_value` | `i_val` | The cdeq value type | -| `cdeq_X_raw` | `i_valraw` | The raw value type | -| `cdeq_X_iter` | `struct { cdeq_X_value* ref; }` | The iterator type | +| `cdeq_X` | `struct { cdeq_X_value* data; }` | The cdeq type | +| `cdeq_X_value` | `i_key` | The cdeq value type | +| `cdeq_X_raw` | `i_keyraw` | The raw value type | +| `cdeq_X_iter` | `struct { cdeq_X_value* ref; }` | The iterator type | ## Examples ```c -#define i_val int +#define i_key int #define i_tag i #include diff --git a/docs/clist_api.md b/docs/clist_api.md index 51b7af6a..023cca41 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -22,16 +22,16 @@ See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list) ## Header file and declaration ```c -#define i_type // container type name (default: clist_{i_val}) -#define i_val // value: REQUIRED -#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined - -#define i_valraw // convertion "raw" type (default: {i_val}) -#define i_valto // convertion func i_val* => i_valraw -#define i_valfrom // convertion func i_valraw => i_val -#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_val +#define i_type // container type name (default: clist_{i_key}) +#define i_key // value: REQUIRED +#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined + +#define i_keyraw // convertion "raw" type (default: {i_key}) +#define i_keyto // convertion func i_key* => i_keyraw +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key #include ``` @@ -53,31 +53,31 @@ intptr_t clist_X_count(const clist_X* list); clist_X_value* clist_X_back(const clist_X* self); clist_X_value* clist_X_front(const clist_X* self); -void clist_X_push_back(clist_X* self, i_val value); // note: no pop_back() -void clist_X_push_front(clist_X* self, i_val value); -void clist_X_push(clist_X* self, i_val value); // alias for push_back() +void clist_X_push_back(clist_X* self, i_key value); // note: no pop_back() +void clist_X_push_front(clist_X* self, i_key value); +void clist_X_push(clist_X* self, i_key value); // alias for push_back() -void clist_X_emplace_back(clist_X* self, i_valraw raw); -void clist_X_emplace_front(clist_X* self, i_valraw raw); -void clist_X_emplace(clist_X* self, i_valraw raw); // alias for emplace_back() +void clist_X_emplace_back(clist_X* self, i_keyraw raw); +void clist_X_emplace_front(clist_X* self, i_keyraw raw); +void clist_X_emplace(clist_X* self, i_keyraw raw); // alias for emplace_back() -clist_X_iter clist_X_insert_at(clist_X* self, clist_X_iter it, i_val value); // return iter to new elem -clist_X_iter clist_X_emplace_at(clist_X* self, clist_X_iter it, i_valraw raw); +clist_X_iter clist_X_insert_at(clist_X* self, clist_X_iter it, i_key value); // return iter to new elem +clist_X_iter clist_X_emplace_at(clist_X* self, clist_X_iter it, i_keyraw raw); void clist_X_pop_front(clist_X* self); clist_X_iter clist_X_erase_at(clist_X* self, clist_X_iter it); // return iter after it clist_X_iter clist_X_erase_range(clist_X* self, clist_X_iter it1, clist_X_iter it2); -intptr_t clist_X_remove(clist_X* self, i_valraw raw); // removes all matches +intptr_t clist_X_remove(clist_X* self, i_keyraw raw); // removes all matches clist_X clist_X_split_off(clist_X* self, clist_X_iter i1, clist_X_iter i2); // split off [i1, i2) clist_X_iter clist_X_splice(clist_X* self, clist_X_iter it, clist_X* other); // return updated valid it clist_X_iter clist_X_splice_range(clist_X* self, clist_X_iter it, // return updated valid it clist_X* other, clist_X_iter it1, clist_X_iter it2); -clist_X_iter clist_X_find(const clist_X* self, i_valraw raw); -clist_X_iter clist_X_find_in(clist_X_iter it1, clist_X_iter it2, i_valraw raw); -const i_val* clist_X_get(const clist_X* self, i_valraw raw); -i_val* clist_X_get_mut(clist_X* self, i_valraw raw); +clist_X_iter clist_X_find(const clist_X* self, i_keyraw raw); +clist_X_iter clist_X_find_in(clist_X_iter it1, clist_X_iter it2, i_keyraw raw); +const i_key* clist_X_get(const clist_X* self, i_keyraw raw); +i_key* clist_X_get_mut(clist_X* self, i_keyraw raw); void clist_X_reverse(clist_X* self); void clist_X_sort(clist_X* self); @@ -108,8 +108,8 @@ void clist_X_value_drop(clist_X_value* pval); |:--------------------|:------------------------------------|:-----------------------------------------| | `clist_X` | `struct { clist_X_node* last; }` | The clist type | | `clist_X_node` | `struct { clist_X_node* next; clist_X_value value; }` | The clist node type | -| `clist_X_value` | `i_val` | The clist element type | -| `clist_X_raw` | `i_valraw` | clist raw value type | +| `clist_X_value` | `i_key` | The clist element type | +| `clist_X_raw` | `i_keyraw` | clist raw value type | | `clist_X_iter` | `struct { clist_value *ref; ... }` | clist iterator | ## Example @@ -117,7 +117,7 @@ void clist_X_value_drop(clist_X_value* pval); Interleave *push_front()* / *push_back()* then *sort()*: ```c #define i_type DList -#define i_val double +#define i_key double #include #include @@ -154,7 +154,7 @@ Use of *erase_at()* and *erase_range()*: ```c // erasing from clist #define i_tag i -#define i_val int +#define i_key int #include #include @@ -189,7 +189,7 @@ mylist contains: 10 30 Splice `[30, 40]` from *L2* into *L1* before `3`: ```c #define i_tag i -#define i_val int +#define i_key int #include #include diff --git a/docs/cpque_api.md b/docs/cpque_api.md index 962ee162..ca94e367 100644 --- a/docs/cpque_api.md +++ b/docs/cpque_api.md @@ -8,17 +8,17 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai ## Header file and declaration ```c -#define i_type // define type name of the container (default cpque_{i_val}) -#define i_val // value: REQUIRED -#define i_less // compare two i_val* : REQUIRED IF i_val/i_valraw is a non-integral type -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined +#define i_type // define type name of the container (default cpque_{i_key}) +#define i_key // value: REQUIRED +#define i_less // compare two i_key* : REQUIRED IF i_key/i_keyraw is a non-integral type +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_valraw // convertion type -#define i_valfrom // convertion func i_valraw => i_val -#define i_valto // convertion func i_val* => i_valraw. +#define i_keyraw // convertion type +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw. -#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_val +#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -28,7 +28,7 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai ```c cpque_X cpque_X_init(void); // create empty pri-queue. cpque_X cpque_X_with_capacity(intptr_t cap); -cpque_X cpque_X_with_size(intptr_t size, i_val null); +cpque_X cpque_X_with_size(intptr_t size, i_key null); cpque_X cpque_X_clone(cpque_X pq); void cpque_X_clear(cpque_X* self); @@ -39,16 +39,16 @@ void cpque_X_drop(cpque_X* self); // destructor intptr_t cpque_X_size(const cpque_X* self); bool cpque_X_empty(const cpque_X* self); -i_val* cpque_X_top(const cpque_X* self); +i_key* cpque_X_top(const cpque_X* self); void cpque_X_make_heap(cpque_X* self); // heapify the vector. -void cpque_X_push(cpque_X* self, i_val value); -void cpque_X_emplace(cpque_X* self, i_valraw raw); // converts from raw +void cpque_X_push(cpque_X* self, i_key value); +void cpque_X_emplace(cpque_X* self, i_keyraw raw); // converts from raw void cpque_X_pop(cpque_X* self); void cpque_X_erase_at(cpque_X* self, intptr_t idx); -i_val cpque_X_value_clone(i_val value); +i_key cpque_X_value_clone(i_key value); ``` ## Types @@ -56,14 +56,14 @@ i_val cpque_X_value_clone(i_val value); | Type name | Type definition | Used to represent... | |:-------------------|:--------------------------------------|:------------------------| | `cpque_X` | `struct {cpque_X_value* data; ...}` | The cpque type | -| `cpque_X_value` | `i_val` | The cpque element type | +| `cpque_X_value` | `i_key` | The cpque element type | ## Example ```c #include #include -#define i_val int64_t +#define i_key int64_t #define i_cmp -c_default_cmp // min-heap #define i_tag i #include diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md index f5df86d6..bce62833 100644 --- a/docs/cqueue_api.md +++ b/docs/cqueue_api.md @@ -7,16 +7,16 @@ See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue ## Header file and declaration ```c -#define i_type // container type name (default: cset_{i_key}) -#define i_val // value: REQUIRED -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined +#define i_type // container type name (default: cqueue_{i_key}) +#define i_key // value: REQUIRED +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_valraw // convertion "raw" type - defaults to i_val -#define i_valfrom // convertion func i_valraw => i_val -#define i_valto // convertion func i_val* => i_valraw +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw -#define i_tag // alternative typename: cqueue_{i_tag}. i_tag defaults to i_val +#define i_tag // alternative typename: cqueue_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -42,8 +42,8 @@ bool cqueue_X_empty(const cqueue_X* self); cqueue_X_value* cqueue_X_front(const cqueue_X* self); cqueue_X_value* cqueue_X_back(const cqueue_X* self); -cqueue_X_value* cqueue_X_push(cqueue_X* self, i_val value); -cqueue_X_value* cqueue_X_emplace(cqueue_X* self, i_valraw raw); +cqueue_X_value* cqueue_X_push(cqueue_X* self, i_key value); +cqueue_X_value* cqueue_X_emplace(cqueue_X* self, i_keyraw raw); void cqueue_X_pop(cqueue_X* self); cqueue_X_iter cqueue_X_begin(const cqueue_X* self); @@ -52,7 +52,7 @@ void cqueue_X_next(cqueue_X_iter* it); cqueue_X_iter cqueue_X_advance(cqueue_X_iter it, intptr_t n); bool cqueue_X_eq(const cqueue_X* c1, const cqueue_X* c2); // require i_eq/i_cmp/i_less. -i_val cqueue_X_value_clone(i_val value); +i_key cqueue_X_value_clone(i_key value); cqueue_X_raw cqueue_X_value_toraw(const cqueue_X_value* pval); void cqueue_X_value_drop(cqueue_X_value* pval); ``` @@ -62,13 +62,13 @@ void cqueue_X_value_drop(cqueue_X_value* pval); | Type name | Type definition | Used to represent... | |:--------------------|:---------------------|:-------------------------| | `cqueue_X` | `cdeq_X` | The cqueue type | -| `cqueue_X_value` | `i_val` | The cqueue element type | -| `cqueue_X_raw` | `i_valraw` | cqueue raw value type | +| `cqueue_X_value` | `i_key` | The cqueue element type | +| `cqueue_X_raw` | `i_keyraw` | cqueue raw value type | | `cqueue_X_iter` | `cdeq_X_iter` | cqueue iterator | ## Examples ```c -#define i_val int +#define i_key int #define i_tag i #include diff --git a/docs/cset_api.md b/docs/cset_api.md index ecf87e5b..7bce3136 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -18,7 +18,7 @@ A **cset** is an associative container that contains a set of unique objects of #define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy #define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy -#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val +#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_key #define i_expandby // default 1. If 2, table expand 2x (else 1.5x) #include ``` diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 4262b1ef..1aeeb4f7 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -47,8 +47,11 @@ SpanTypeN_iter SpanType_begin(const SpanTypeN* self); SpanTypeN_iter SpanType_end(const SpanTypeN* self); void SpanType_next(SpanTypeN_iter* it); -SpanTypeN cspan_md(char order, ValueType* data, d1, d2, ...); // make a multi-dim cspan. order: 'C' or 'F' (Fortran) - // transpose the md span (inverse axes). no changes to the underlying array. +SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // make a multi-dim cspan, row-major order. +SpanTypeN cspan_md_left(ValueType* data, d1, d2, ...); // column-major ordered cspan (layout left). +SpanTypeN cspan_md_ordered(char order, ValueType* data, d1, d2, ...); // order='C': row-major, 'F' (Fortran): column-major. + + // transpose a md span (inverse axes). no changes to the underlying array. void cspan_transpose(const SpanTypeN* self); // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); diff --git a/docs/csset_api.md b/docs/csset_api.md index 5695ecf6..d086b660 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -18,7 +18,7 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo #define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy #define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy -#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_val +#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cstack_api.md b/docs/cstack_api.md index 9cb7b42b..51889d7f 100644 --- a/docs/cstack_api.md +++ b/docs/cstack_api.md @@ -9,15 +9,15 @@ See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack ```c #define i_type // full typename of the container -#define i_val // value: REQUIRED -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined +#define i_key // value: REQUIRED +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_valraw // convertion "raw" type - defaults to i_val -#define i_valfrom // convertion func i_valraw => i_val -#define i_valto // convertion func i_val* => i_valraw +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw -#define i_tag // alternative typename: cstack_{i_tag}. i_tag defaults to i_val +#define i_tag // alternative typename: cstack_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -27,13 +27,13 @@ See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack ```c cstack_X cstack_X_init(void); cstack_X cstack_X_with_capacity(intptr_t cap); -cstack_X cstack_X_with_size(intptr_t size, i_val fill); +cstack_X cstack_X_with_size(intptr_t size, i_key fill); cstack_X cstack_X_clone(cstack_X st); void cstack_X_clear(cstack_X* self); bool cstack_X_reserve(cstack_X* self, intptr_t n); void cstack_X_shrink_to_fit(cstack_X* self); -i_val* cstack_X_append_uninit(cstack_X* self, intptr_t n); +i_key* cstack_X_append_uninit(cstack_X* self, intptr_t n); void cstack_X_copy(cstack_X* self, const cstack_X* other); void cstack_X_drop(cstack_X* self); // destructor @@ -41,12 +41,12 @@ intptr_t cstack_X_size(const cstack_X* self); intptr_t cstack_X_capacity(const cstack_X* self); bool cstack_X_empty(const cstack_X* self); -i_val* cstack_X_top(const cstack_X* self); -const i_val* cstack_X_at(const cstack_X* self, intptr_t idx); -i_val* cstack_X_at_mut(cstack_X* self, intptr_t idx); +i_key* cstack_X_top(const cstack_X* self); +const i_key* cstack_X_at(const cstack_X* self, intptr_t idx); +i_key* cstack_X_at_mut(cstack_X* self, intptr_t idx); -i_val* cstack_X_push(cstack_X* self, i_val value); -i_val* cstack_X_emplace(cstack_X* self, i_valraw raw); +i_key* cstack_X_push(cstack_X* self, i_key value); +i_key* cstack_X_emplace(cstack_X* self, i_keyraw raw); void cstack_X_pop(cstack_X* self); @@ -55,8 +55,8 @@ cstack_X_iter cstack_X_end(const cstack_X* self); void cstack_X_next(cstack_X_iter* it); bool cstack_X_eq(const cstack_X* c1, const cstack_X* c2); // require i_eq/i_cmp/i_less. -i_val cstack_X_value_clone(i_val value); -i_valraw cstack_X_value_toraw(const cvec_X_value* pval); +i_key cstack_X_value_clone(i_key value); +i_keyraw cstack_X_value_toraw(const cvec_X_value* pval); void cstack_X_value_drop(cvec_X_value* pval); ``` @@ -65,14 +65,14 @@ void cstack_X_value_drop(cvec_X_value* pval); | Type name | Type definition | Used to represent... | |:--------------------|:-------------------------------------|:----------------------------| | `cstack_X` | `struct { cstack_value *data; ... }` | The cstack type | -| `cstack_X_value` | `i_val` | The cstack element type | -| `cstack_X_raw` | `i_valraw` | cstack raw value type | +| `cstack_X_value` | `i_key` | The cstack element type | +| `cstack_X_raw` | `i_keyraw` | cstack raw value type | | `cstack_X_iter` | `struct { cstack_value *ref; }` | cstack iterator | ## Example ```c #define i_type IStack -#define i_val int +#define i_key int #include #include diff --git a/docs/csview_api.md b/docs/csview_api.md index a02b007a..33df6a64 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -185,7 +185,7 @@ void print_split(csview input, const char* sep) } #define i_implement #include -#define i_val_str +#define i_key_str #include cstack_str string_split(csview input, const char* sep) diff --git a/docs/cvec_api.md b/docs/cvec_api.md index d19f4bae..ce85e446 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -13,16 +13,16 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect ```c #define i_type // full typename of the container -#define i_val // value: REQUIRED -#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined +#define i_key // value: REQUIRED +#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_valraw // convertion "raw" type - defaults to i_val -#define i_valfrom // convertion func i_valraw => i_val -#define i_valto // convertion func i_val* => i_valraw +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw -#define i_tag // alternative typename: cvec_{i_tag}. i_tag defaults to i_val +#define i_tag // alternative typename: cvec_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -31,15 +31,15 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect ```c cvec_X cvec_X_init(void); -cvec_X cvec_X_with_size(intptr_t size, i_val null); +cvec_X cvec_X_with_size(intptr_t size, i_key null); cvec_X cvec_X_with_capacity(intptr_t size); cvec_X cvec_X_clone(cvec_X vec); void cvec_X_clear(cvec_X* self); void cvec_X_copy(cvec_X* self, const cvec_X* other); -cvec_X_iter cvec_X_copy_n(cvec_X* self, intptr_t idx, const i_val* arr, intptr_t n); +cvec_X_iter cvec_X_copy_n(cvec_X* self, intptr_t idx, const i_key* arr, intptr_t n); bool cvec_X_reserve(cvec_X* self, intptr_t cap); -bool cvec_X_resize(cvec_X* self, intptr_t size, i_val null); +bool cvec_X_resize(cvec_X* self, intptr_t size, i_key null); void cvec_X_shrink_to_fit(cvec_X* self); void cvec_X_drop(cvec_X* self); // destructor @@ -48,34 +48,34 @@ intptr_t cvec_X_size(const cvec_X* self); intptr_t cvec_X_capacity(const cvec_X* self); const cvec_X_value* cvec_X_at(const cvec_X* self, intptr_t idx); -const cvec_X_value* cvec_X_get(const cvec_X* self, i_valraw raw); // return NULL if not found +const cvec_X_value* cvec_X_get(const cvec_X* self, i_keyraw raw); // return NULL if not found cvec_X_value* cvec_X_at_mut(cvec_X* self, intptr_t idx); // return mutable at idx -cvec_X_value* cvec_X_get_mut(cvec_X* self, i_valraw raw); // find mutable value -cvec_X_iter cvec_X_find(const cvec_X* self, i_valraw raw); -cvec_X_iter cvec_X_find_in(cvec_X_iter i1, cvec_X_iter i2, i_valraw raw); // return cvec_X_end() if not found +cvec_X_value* cvec_X_get_mut(cvec_X* self, i_keyraw raw); // find mutable value +cvec_X_iter cvec_X_find(const cvec_X* self, i_keyraw raw); +cvec_X_iter cvec_X_find_in(cvec_X_iter i1, cvec_X_iter i2, i_keyraw raw); // return cvec_X_end() if not found // On sorted vectors: -cvec_X_iter cvec_X_binary_search(const cvec_X* self, i_valraw raw); // at elem == raw, else end -cvec_X_iter cvec_X_lower_bound(const cvec_X* self, i_valraw raw); // at first elem >= raw, else end +cvec_X_iter cvec_X_binary_search(const cvec_X* self, i_keyraw raw); // at elem == raw, else end +cvec_X_iter cvec_X_lower_bound(const cvec_X* self, i_keyraw raw); // at first elem >= raw, else end cvec_X_iter cvec_X_binary_search_in(cvec_X_iter i1, cvec_X_iter i2, - i_valraw raw, cvec_X_iter* lower_bound); + i_keyraw raw, cvec_X_iter* lower_bound); cvec_X_value* cvec_X_front(const cvec_X* self); cvec_X_value* cvec_X_back(const cvec_X* self); -cvec_X_value* cvec_X_push(cvec_X* self, i_val value); -cvec_X_value* cvec_X_emplace(cvec_X* self, i_valraw raw); -cvec_X_value* cvec_X_push_back(cvec_X* self, i_val value); // alias for push -cvec_X_value* cvec_X_emplace_back(cvec_X* self, i_valraw raw); // alias for emplace +cvec_X_value* cvec_X_push(cvec_X* self, i_key value); +cvec_X_value* cvec_X_emplace(cvec_X* self, i_keyraw raw); +cvec_X_value* cvec_X_push_back(cvec_X* self, i_key value); // alias for push +cvec_X_value* cvec_X_emplace_back(cvec_X* self, i_keyraw raw); // alias for emplace void cvec_X_pop(cvec_X* self); void cvec_X_pop_back(cvec_X* self); // alias for pop -cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_val arr[], intptr_t n); // move values -cvec_X_iter cvec_X_insert_at(cvec_X* self, cvec_X_iter it, i_val value); // move value +cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_key arr[], intptr_t n); // move values +cvec_X_iter cvec_X_insert_at(cvec_X* self, cvec_X_iter it, i_key value); // move value cvec_X_iter cvec_X_insert_uninit(cvec_X* self, intptr_t idx, intptr_t n); // return iter at idx -cvec_X_iter cvec_X_emplace_n(cvec_X* self, intptr_t idx, const i_valraw raw[], intptr_t n); -cvec_X_iter cvec_X_emplace_at(cvec_X* self, cvec_X_iter it, i_valraw raw); +cvec_X_iter cvec_X_emplace_n(cvec_X* self, intptr_t idx, const i_keyraw raw[], intptr_t n); +cvec_X_iter cvec_X_emplace_at(cvec_X* self, cvec_X_iter it, i_keyraw raw); cvec_X_iter cvec_X_erase_n(cvec_X* self, intptr_t idx, intptr_t n); cvec_X_iter cvec_X_erase_at(cvec_X* self, cvec_X_iter it); @@ -83,7 +83,7 @@ cvec_X_iter cvec_X_erase_range(cvec_X* self, cvec_X_iter it1, cvec_X_ite void cvec_X_sort(cvec_X* self); void cvec_X_sort_range(cvec_X_iter i1, cvec_X_iter i2, - int(*cmp)(const i_val*, const i_val*)); + int(*cmp)(const i_key*, const i_key*)); cvec_X_iter cvec_X_begin(const cvec_X* self); cvec_X_iter cvec_X_end(const cvec_X* self); @@ -101,13 +101,13 @@ cvec_X_raw cvec_X_value_drop(cvec_X_value* pval); | Type name | Type definition | Used to represent... | |:-------------------|:----------------------------------|:-----------------------| | `cvec_X` | `struct { cvec_X_value* data; }` | The cvec type | -| `cvec_X_value` | `i_val` | The cvec value type | -| `cvec_X_raw` | `i_valraw` | The raw value type | +| `cvec_X_value` | `i_key` | The cvec value type | +| `cvec_X_raw` | `i_keyraw` | The raw value type | | `cvec_X_iter` | `struct { cvec_X_value* ref; }` | The iterator type | ## Examples ```c -#define i_val int +#define i_key int #include #include @@ -150,7 +150,7 @@ sorted: 5 7 8 13 16 25 #define i_implement #include -#define i_val_str +#define i_key_str #include int main() { @@ -206,7 +206,7 @@ User User_clone(User user) { // Declare a managed, clonable vector of users. #define i_type UVec -#define i_valclass User // User is a "class" as it has _cmp, _clone and _drop functions. +#define i_keyclass User // User is a "class" as it has _cmp, _clone and _drop functions. #include int main(void) { diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h index 8365ccc5..01e7d521 100644 --- a/include/stc/algo/sort.h +++ b/include/stc/algo/sort.h @@ -22,13 +22,13 @@ */ /* Generic Quicksort in C, performs as fast as c++ std::sort(). template params: -#define i_val - value type [required] +#define i_key - value type [required] #define i_less - less function. default: *x < *y -#define i_type name - define {{name}}_sort_n(), else {{i_val}}array_sort_n(). +#define i_type name - define {{name}}_sort_n(), else {{i_key}}array_sort_n(). // ex1: #include -#define i_val int +#define i_key int #include int main() { @@ -42,7 +42,7 @@ int main() { } // ex2: -#define i_val int +#define i_key int #define i_type IDeq #define i_more // retain input template params to be reused by sort.h #include @@ -62,13 +62,16 @@ int main() { */ #include "../ccommon.h" +#if !defined i_key && defined i_val + #define i_key i_val +#endif #ifndef i_type #define i_at(arr, idx) (&arr[idx]) #ifndef i_tag - #define i_tag i_val + #define i_tag i_key #endif #define i_type c_PASTE(i_tag, array) - typedef i_val i_type; + typedef i_key i_type; #endif #ifndef i_at #define i_at(arr, idx) _cx_MEMB(_at_mut)(arr, idx) @@ -78,7 +81,7 @@ int main() { static inline void _cx_MEMB(_insertsort_ij)(_cx_Self* arr, intptr_t lo, intptr_t hi) { for (intptr_t j = lo, i = lo + 1; i <= hi; j = i, ++i) { - i_val key = *i_at(arr, i); + i_key key = *i_at(arr, i); while (j >= 0 && (i_less((&key), i_at(arr, j)))) { *i_at(arr, j + 1) = *i_at(arr, j); --j; @@ -90,14 +93,14 @@ static inline void _cx_MEMB(_insertsort_ij)(_cx_Self* arr, intptr_t lo, intptr_t static inline void _cx_MEMB(_sort_ij)(_cx_Self* arr, intptr_t lo, intptr_t hi) { intptr_t i = lo, j; while (lo < hi) { - i_val pivot = *i_at(arr, lo + (hi - lo)*7/16); + i_key pivot = *i_at(arr, lo + (hi - lo)*7/16); j = hi; while (i <= j) { while (i_less(i_at(arr, i), (&pivot))) ++i; while (i_less((&pivot), i_at(arr, j))) --j; if (i <= j) { - c_swap(i_val, i_at(arr, i), i_at(arr, j)); + c_swap(i_key, i_at(arr, i), i_at(arr, j)); ++i; --j; } } diff --git a/include/stc/cbits.h b/include/stc/cbits.h index 9463c82c..66bc6354 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -90,7 +90,7 @@ STC_INLINE _llong _cbits_count(const uint64_t* set, const _llong sz) { STC_INLINE char* _cbits_to_str(const uint64_t* set, const _llong sz, char* out, _llong start, _llong stop) { if (stop > sz) stop = sz; - assert(start <= stop); + c_assert(start <= stop); c_memset(out, '0', stop - start); for (_llong i = start; i < stop; ++i) @@ -122,7 +122,7 @@ STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, cons #if !defined i_capacity // DYNAMIC SIZE BITARRAY -#define _i_assert(x) assert(x) +#define _i_assert(x) c_assert(x) #define i_type cbits typedef struct { uint64_t *data64; _llong _size; } i_type; @@ -216,13 +216,13 @@ STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value); STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern); STC_INLINE i_type _i_memb(_with_size)(const _llong size, const bool value) { - assert(size <= i_capacity); + c_assert(size <= i_capacity); i_type set; _i_memb(_set_all)(&set, value); return set; } STC_INLINE i_type _i_memb(_with_pattern)(const _llong size, const uint64_t pattern) { - assert(size <= i_capacity); + c_assert(size <= i_capacity); i_type set; _i_memb(_set_pattern)(&set, pattern); return set; } diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index d6da8734..efbebdc3 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -34,11 +34,6 @@ typedef long long _llong; #define c_NPOS INTPTR_MAX #define c_ZI PRIiPTR #define c_ZU PRIuPTR -#if defined STC_NDEBUG || defined NDEBUG - #define c_ASSERT(expr) (void)(0) -#else - #define c_ASSERT(expr) assert(expr) -#endif #if defined(_MSC_VER) #pragma warning(disable: 4116 4996) // unnamed type definition in parentheses @@ -80,7 +75,14 @@ typedef long long _llong; #define c_free(p) free(p) #define c_delete(T, ptr) do { T *_tp = ptr; T##_drop(_tp); free(_tp); } while (0) -#define c_static_assert(b) ((int)(0*sizeof(int[(b) ? 1 : -1]))) +#define c_static_assert(...) c_MACRO_OVERLOAD(c_static_assert, __VA_ARGS__) +#define c_static_assert_1(b) ((int)(0*sizeof(int[(b) ? 1 : -1]))) +#define c_static_assert_2(b, m) c_static_assert_1(b) +#if defined STC_NDEBUG || defined NDEBUG + #define c_assert(expr) ((void)0) +#else + #define c_assert(expr) assert(expr) +#endif #define c_container_of(p, C, m) ((C*)((char*)(1 ? (p) : &((C*)0)->m) - offsetof(C, m))) #define c_const_cast(T, p) ((T)(p) + 0*sizeof((T)0 == (p))) #define c_swap(T, xp, yp) do { T *_xp = xp, *_yp = yp, \ diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index bac40f90..056ef005 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -51,13 +51,13 @@ _cx_MEMB(_push_back)(_cx_Self* self, _cx_value val) STC_INLINE void _cx_MEMB(_pop_back)(_cx_Self* self) { - assert(!_cx_MEMB(_empty)(self)); + c_assert(!_cx_MEMB(_empty)(self)); self->end = (self->end - 1) & self->capmask; i_keydrop((self->data + self->end)); } STC_INLINE _cx_value _cx_MEMB(_pull_back)(_cx_Self* self) { // move back out of deq - assert(!_cx_MEMB(_empty)(self)); + c_assert(!_cx_MEMB(_empty)(self)); self->end = (self->end - 1) & self->capmask; return self->data[self->end]; } diff --git a/include/stc/clist.h b/include/stc/clist.h index 38358d73..9cc1bb39 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -145,7 +145,7 @@ STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) { _cx_MEMB(_drop)(self) STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value) { return _cx_MEMB(_push_back)(self, value); } STC_INLINE void _cx_MEMB(_pop_front)(_cx_Self* self) - { assert(!_cx_MEMB(_empty)(self)); _cx_MEMB(_erase_after_node)(self, self->last); } + { c_assert(!_cx_MEMB(_empty)(self)); _cx_MEMB(_erase_after_node)(self, self->last); } STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return &self->last->next->value; } STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return &self->last->value; } STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval) { return i_keyto(pval); } diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 21e7b933..513a8b93 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -117,7 +117,7 @@ STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rke STC_INLINE const _cx_mapped* _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) { chash_bucket b = _cx_MEMB(_bucket_)(self, &rkey); - assert(b.found); + c_assert(b.found); return &self->data[b.idx].second; } STC_INLINE _cx_mapped* diff --git a/include/stc/cpque.h b/include/stc/cpque.h index cfe027cc..ca51eeff 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -89,7 +89,7 @@ STC_INLINE const _cx_value* _cx_MEMB(_top)(const _cx_Self* self) { return &self->data[0]; } STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) - { assert(!_cx_MEMB(_empty)(self)); _cx_MEMB(_erase_at)(self, 0); } + { c_assert(!_cx_MEMB(_empty)(self)); _cx_MEMB(_erase_at)(self, 0); } #if !defined i_no_clone STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self q); diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index e9f1b877..5d38ca89 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -88,13 +88,13 @@ STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return self->data + ((self->end - 1) & self->capmask); } STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { // pop_front - assert(!_cx_MEMB(_empty)(self)); + c_assert(!_cx_MEMB(_empty)(self)); i_keydrop((self->data + self->start)); self->start = (self->start + 1) & self->capmask; } STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { // move front out of queue - assert(!_cx_MEMB(_empty)(self)); + c_assert(!_cx_MEMB(_empty)(self)); intptr_t s = self->start; self->start = (s + 1) & self->capmask; return self->data[s]; diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 89986d6f..4d091395 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -84,7 +84,7 @@ int demo2() { const int rank, const int32_t a[][2]) { \ Self s = {.data=v}; int outrank; \ s.data += _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ - c_ASSERT(outrank == RANK); \ + c_assert(outrank == RANK); \ return s; \ } \ STC_INLINE Self##_iter Self##_begin(const Self* self) { \ @@ -145,7 +145,6 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define cspan_subspan3(self, offset, count) \ {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride=(self)->stride} - // cspan_submd(): Reduce rank (N <= 4) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); #define cspan_submd2(OutSpan, self, ...) _cspan_submdN(OutSpan, 2, self, __VA_ARGS__) #define cspan_submd3(OutSpan, self, ...) _cspan_submdN(OutSpan, 3, self, __VA_ARGS__) @@ -172,23 +171,22 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define _cspan_submd4_5(ok, self, x, y, z) \ {.data=cspan_at(self, x, y, z, 0) + ok, .shape={(self)->shape[3]}, .stride={.d={(self)->stride.d[3]}}} -#define cspan_md(array, ...) cspan_md_order('C', array, __VA_ARGS__) -#define cspan_md_left(array, ...) cspan_md_order('F', array, __VA_ARGS__) -#define cspan_md_order(order, array, ...) \ +#define cspan_md(array, ...) cspan_md_ordered('C', array, __VA_ARGS__) +#define cspan_md_left(array, ...) cspan_md_ordered('F', array, __VA_ARGS__) +#define cspan_md_ordered(order, array, ...) \ {.data=array, .shape={__VA_ARGS__}, \ .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(order, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} #define cspan_transpose(self) \ _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self)) - // General slicing function; #define cspan_slice(OutSpan, parent, ...) \ OutSpan##_slice_((parent)->data, (parent)->shape, (parent)->stride.d, cspan_rank(parent) + \ c_static_assert(cspan_rank(parent) == sizeof((int32_t[][2]){__VA_ARGS__})/sizeof(int32_t[2])), \ (const int32_t[][2]){__VA_ARGS__}) -// ----------- private definitions ------------ +/* ------------------- PRIVAT DEFINITIONS ------------------- */ // cspan_index() helpers: #define cspan_idx_1 cspan_idx_3 @@ -215,19 +213,19 @@ STC_INLINE void _cspan_transpose(int32_t shape[], int32_t stride[], int rank) { } STC_INLINE intptr_t _cspan_idx1(const int32_t shape[1], const cspan_tuple1 stri, int32_t x) - { c_ASSERT(c_LTu(x, shape[0])); return x; } + { c_assert(c_LTu(x, shape[0])); return (intptr_t)stri.d[0]*x; } STC_INLINE intptr_t _cspan_idx2(const int32_t shape[2], const cspan_tuple2 stri, int32_t x, int32_t y) - { c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1])); return (intptr_t)stri.d[0]*x + stri.d[1]*y; } + { c_assert(c_LTu(x, shape[0]) && c_LTu(y, shape[1])); return (intptr_t)stri.d[0]*x + stri.d[1]*y; } STC_INLINE intptr_t _cspan_idx3(const int32_t shape[3], const cspan_tuple3 stri, int32_t x, int32_t y, int32_t z) { - c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2])); + c_assert(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2])); return (intptr_t)stri.d[0]*x + stri.d[1]*y + stri.d[2]*z; } STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stride[], const int32_t a[]) { intptr_t off = 0; while (rank--) { - c_ASSERT(c_LTu(a[rank], shape[rank])); + c_assert(c_LTu(a[rank], shape[rank])); off += stride[rank]*a[rank]; } return off; @@ -239,6 +237,8 @@ STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_ #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 #define _cspan_next6 _cspan_next2 +#define _cspan_next7 _cspan_next2 +#define _cspan_next8 _cspan_next2 STC_API intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, const int32_t shape[], const int32_t stride[], @@ -247,7 +247,7 @@ STC_API intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, STC_API int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank); #endif // STC_CSPAN_H_INCLUDED -/* -------------------------- IMPLEMENTATION ------------------------- */ +/* --------------------- IMPLEMENTATION --------------------- */ #if defined(i_implement) || defined(i_static) STC_DEF int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank) { @@ -283,13 +283,13 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, for (; i < rank; ++i) { off += stride[i]*a[i][0]; switch (a[i][1]) { - case 0: c_ASSERT(c_LTu(a[i][0], shape[i])); continue; + case 0: c_assert(c_LTu(a[i][0], shape[i])); continue; case -1: end = shape[i]; break; default: end = a[i][1]; } oshape[oi] = end - a[i][0]; ostride[oi] = stride[i]; - c_ASSERT(c_LTu(0, oshape[oi]) & !c_LTu(shape[i], end)); + c_assert(c_LTu(0, oshape[oi]) & !c_LTu(shape[i], end)); ++oi; } *orank = oi; diff --git a/include/stc/cstack.h b/include/stc/cstack.h index 24ec2d5f..f8640ed1 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -129,10 +129,10 @@ STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value val) { } STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) - { assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } + { c_assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) - { assert(self->_len); return self->data[--self->_len]; } + { c_assert(self->_len); return self->data[--self->_len]; } STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } @@ -141,9 +141,9 @@ STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } STC_INLINE const _cx_value* _cx_MEMB(_at)(const _cx_Self* self, intptr_t idx) - { assert(idx < self->_len); return self->data + idx; } + { c_assert(idx < self->_len); return self->data + idx; } STC_INLINE _cx_value* _cx_MEMB(_at_mut)(_cx_Self* self, intptr_t idx) - { assert(idx < self->_len); return self->data + idx; } + { c_assert(idx < self->_len); return self->data + idx; } #if !defined i_no_emplace STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) diff --git a/include/stc/cvec.h b/include/stc/cvec.h index e1d34365..9b95306e 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -133,9 +133,9 @@ STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return self->da STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return self->data + self->_len - 1; } STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) - { assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } + { c_assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) - { assert(self->_len); return self->data[--self->_len]; } + { c_assert(self->_len); return self->data[--self->_len]; } STC_INLINE _cx_value* _cx_MEMB(_push_back)(_cx_Self* self, i_key value) { return _cx_MEMB(_push)(self, value); } STC_INLINE void _cx_MEMB(_pop_back)(_cx_Self* self) { _cx_MEMB(_pop)(self); } @@ -182,11 +182,11 @@ _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter i1, _cx_iter i2) { STC_INLINE const _cx_value* _cx_MEMB(_at)(const _cx_Self* self, const intptr_t idx) { - assert(idx < self->_len); return self->data + idx; + c_assert(idx < self->_len); return self->data + idx; } STC_INLINE _cx_value* _cx_MEMB(_at_mut)(_cx_Self* self, const intptr_t idx) { - assert(idx < self->_len); return self->data + idx; + c_assert(idx < self->_len); return self->data + idx; } diff --git a/include/stc/extend.h b/include/stc/extend.h index c0a00ff8..52d59414 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -43,8 +43,10 @@ #define _i_val i_val #endif -#ifdef _i_key +#if defined _i_key && defined _i_val c_PASTE(forward_, i_base)(i_type, _i_key, _i_val); +#elif defined _i_key + c_PASTE(forward_, i_base)(i_type, _i_key); #else c_PASTE(forward_, i_base)(i_type, _i_val); #endif diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c index d434693f..f6b7f1db 100644 --- a/misc/benchmarks/various/csort_bench.c +++ b/misc/benchmarks/various/csort_bench.c @@ -7,7 +7,7 @@ #endif #define NDEBUG #define i_type Ints -#define i_val int +#define i_key int #define i_more #include #include diff --git a/misc/examples/arc_containers.c b/misc/examples/arc_containers.c index b05bbea6..524758e7 100644 --- a/misc/examples/arc_containers.c +++ b/misc/examples/arc_containers.c @@ -10,18 +10,18 @@ #include #define i_type Arc // (atomic) ref. counted type -#define i_val Map -#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p)) +#define i_key Map +#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) // no need for atomic ref. count in single thread: #define i_opt c_no_atomic #include #define i_type Stack -#define i_valboxed Arc // define i_valboxed for carc/cbox value (not i_val) +#define i_keyboxed Arc // define i_keyboxed for carc/cbox value (not i_key) #include #define i_type List -#define i_valboxed Arc // as above +#define i_keyboxed Arc // as above #include int main() diff --git a/misc/examples/arc_demo.c b/misc/examples/arc_demo.c index 4cda1c8b..547e1737 100644 --- a/misc/examples/arc_demo.c +++ b/misc/examples/arc_demo.c @@ -6,18 +6,18 @@ void int_drop(int* x) { } // carc implements its own clone method using reference counting, -// so 'i_valclone' is not required to be defined (ignored). +// so 'i_keyclone' is not required to be defined (ignored). #define i_type Arc // set type name to be defined (instead of 'carc_int') -#define i_val int -#define i_valdrop int_drop // optional, just to display the elements destroyed +#define i_key int +#define i_keydrop int_drop // optional, just to display the elements destroyed #define i_native_cmp // use int comparison (x < y, x == y). #include // Arc #define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements #include // csset_Arc (like: std::set>) -#define i_valboxed Arc // note: as above. +#define i_keyboxed Arc // note: as above. #include // cvec_Arc (like: std::vector>) int main() diff --git a/misc/examples/arcvec_erase.c b/misc/examples/arcvec_erase.c index 0b9252d9..f409258b 100644 --- a/misc/examples/arcvec_erase.c +++ b/misc/examples/arcvec_erase.c @@ -3,13 +3,13 @@ void show_drop(int* x) { printf("drop: %d\n", *x); } #define i_type Arc -#define i_val int -#define i_valdrop show_drop +#define i_key int +#define i_keydrop show_drop #define i_native_cmp // enable sort/search for int type #include // Shared pointer to int #define i_type Vec -#define i_valboxed Arc +#define i_keyboxed Arc #include // Vec: cvec diff --git a/misc/examples/astar.c b/misc/examples/astar.c index 1b3876aa..44cdefee 100644 --- a/misc/examples/astar.c +++ b/misc/examples/astar.c @@ -57,11 +57,11 @@ point_key_cmp(const point* a, const point* b) return (i == j) ? 0 : (i < j) ? -1 : 1; } -#define i_val point +#define i_key point #define i_cmp point_cmp_priority #include -#define i_val point +#define i_key point #define i_opt c_no_cmp #include diff --git a/misc/examples/box.c b/misc/examples/box.c index a9131afa..3f55e15d 100644 --- a/misc/examples/box.c +++ b/misc/examples/box.c @@ -29,11 +29,11 @@ void Person_drop(Person* p) { } #define i_type PBox -#define i_valclass Person // "class" binds _cmp, _clone, _drop functions. +#define i_keyclass Person // "class" binds _cmp, _clone, _drop functions. #include #define i_type Persons -#define i_valboxed PBox // "arcbox" informs that PBox is a smart pointer. +#define i_keyboxed PBox // "arcbox" informs that PBox is a smart pointer. #include int main() diff --git a/misc/examples/box2.c b/misc/examples/box2.c index d3762462..5ac706d4 100644 --- a/misc/examples/box2.c +++ b/misc/examples/box2.c @@ -14,15 +14,15 @@ typedef struct { Point bottom_right; } Rectangle; -#define i_val Point +#define i_key Point #include // cbox_Point -#define i_val Rectangle +#define i_key Rectangle #include // cbox_Rectangle // Box in box: #define i_type BoxBoxPoint -#define i_valboxed cbox_Point // NB: use i_valboxed when value is a cbox or carc! +#define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc! #define i_no_cmp #include // BoxBoxPoint diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 61562a5f..c3c5926a 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -2,7 +2,7 @@ #include #include #define i_type IVec -#define i_val int +#define i_key int #include struct GenValue { diff --git a/misc/examples/complex.c b/misc/examples/complex.c index b5ea847a..405afef3 100644 --- a/misc/examples/complex.c +++ b/misc/examples/complex.c @@ -9,11 +9,11 @@ #include #define i_type FloatStack -#define i_val float +#define i_key float #include #define i_type StackList -#define i_valclass FloatStack // "class" picks up _clone, _drop, _cmp +#define i_keyclass FloatStack // "class" picks up _clone, _drop, _cmp #define i_opt c_no_cmp // exclude FloatStack_cmp(): not defined #include diff --git a/misc/examples/convert.c b/misc/examples/convert.c index 318f09b8..3b9dc3ec 100644 --- a/misc/examples/convert.c +++ b/misc/examples/convert.c @@ -6,10 +6,10 @@ #define i_val_str #include -#define i_val_str +#define i_key_str #include -#define i_val_str +#define i_key_str #include int main() diff --git a/misc/examples/csmap_find.c b/misc/examples/csmap_find.c index 645828a3..b535e9ad 100644 --- a/misc/examples/csmap_find.c +++ b/misc/examples/csmap_find.c @@ -8,7 +8,7 @@ #define i_tag istr #include -#define i_val csmap_istr_raw +#define i_key csmap_istr_raw #define i_tag istr #include diff --git a/misc/examples/csmap_insert.c b/misc/examples/csmap_insert.c index 18a88ec3..df638c22 100644 --- a/misc/examples/csmap_insert.c +++ b/misc/examples/csmap_insert.c @@ -12,7 +12,7 @@ #define i_tag istr // Map of int => cstr #include -#define i_val csmap_ii_raw +#define i_key csmap_ii_raw #define i_opt c_no_cmp #define i_tag ii #include diff --git a/misc/examples/demos.c b/misc/examples/demos.c index b2f50ebf..2e91b20c 100644 --- a/misc/examples/demos.c +++ b/misc/examples/demos.c @@ -28,7 +28,7 @@ void stringdemo1() cstr_drop(&cs); } -#define i_val int64_t +#define i_key int64_t #define i_tag ix #include @@ -52,7 +52,7 @@ void vectordemo1() cvec_ix_drop(&bignums); } -#define i_val_str +#define i_key_str #include void vectordemo2() @@ -72,7 +72,7 @@ void vectordemo2() cvec_str_drop(&names); } -#define i_val int +#define i_key int #define i_tag ix #define i_native_cmp #include diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index 7e3c4c9c..f3c008b3 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -7,7 +7,7 @@ #include #define i_type IVec -#define i_val int +#define i_key int #include // filters and transforms: @@ -83,7 +83,7 @@ fn main() { } */ #define i_type SVec -#define i_valclass csview +#define i_keyclass csview #include void demo3(void) diff --git a/misc/examples/forloops.c b/misc/examples/forloops.c index 337cfaa1..99b12871 100644 --- a/misc/examples/forloops.c +++ b/misc/examples/forloops.c @@ -2,7 +2,7 @@ #include #define i_type IVec -#define i_val int +#define i_key int #include #define i_type IMap diff --git a/misc/examples/functor.c b/misc/examples/functor.c index a233a874..ea409a56 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -6,7 +6,7 @@ #define i_type IPQue #define i_base cpque -#define i_val int +#define i_key int #define i_extend bool(*less)(const int*, const int*); #define i_less(x, y) c_extend()->less(x, y) // Note: i_less: c_extend() accessible for cpque types diff --git a/misc/examples/inits.c b/misc/examples/inits.c index a3a6c4d2..53a49f1f 100644 --- a/misc/examples/inits.c +++ b/misc/examples/inits.c @@ -18,17 +18,17 @@ inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) { } -#define i_val ipair_t +#define i_key ipair_t #define i_cmp ipair_cmp #define i_tag ip #include -#define i_val ipair_t +#define i_key ipair_t #define i_cmp ipair_cmp #define i_tag ip #include -#define i_val float +#define i_key float #define i_tag f #include diff --git a/misc/examples/intrusive.c b/misc/examples/intrusive.c index e3939f4e..1e3f7b83 100644 --- a/misc/examples/intrusive.c +++ b/misc/examples/intrusive.c @@ -3,7 +3,7 @@ #include #define i_type List -#define i_val int +#define i_key int #define i_native_cmp #include diff --git a/misc/examples/list.c b/misc/examples/list.c index 08fe837f..a0045db9 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -4,7 +4,7 @@ #include #define i_type DList -#define i_val double +#define i_key double #define i_native_cmp #include diff --git a/misc/examples/list_erase.c b/misc/examples/list_erase.c index 17adf11f..357dd75b 100644 --- a/misc/examples/list_erase.c +++ b/misc/examples/list_erase.c @@ -2,7 +2,7 @@ #include #define i_type IList -#define i_val int +#define i_key int #include int main () diff --git a/misc/examples/list_splice.c b/misc/examples/list_splice.c index e457694d..25c2a42d 100644 --- a/misc/examples/list_splice.c +++ b/misc/examples/list_splice.c @@ -1,6 +1,6 @@ #include -#define i_val int +#define i_key int #define i_tag i #include diff --git a/misc/examples/lower_bound.c b/misc/examples/lower_bound.c index 5b395e45..ee32f49b 100644 --- a/misc/examples/lower_bound.c +++ b/misc/examples/lower_bound.c @@ -1,10 +1,10 @@ #include -#define i_val int +#define i_key int #define i_native_cmp #include -#define i_val int +#define i_key int #include int main() diff --git a/misc/examples/mmap.c b/misc/examples/mmap.c index 63312e04..fd00499c 100644 --- a/misc/examples/mmap.c +++ b/misc/examples/mmap.c @@ -4,7 +4,7 @@ // Multimap entries #define i_implement #include -#define i_val_str +#define i_key_str #include // Map of int => clist_str. diff --git a/misc/examples/multimap.c b/misc/examples/multimap.c index dc4a1ee0..a89b251b 100644 --- a/misc/examples/multimap.c +++ b/misc/examples/multimap.c @@ -40,7 +40,7 @@ OlympicLoc OlympicLoc_clone(OlympicLoc loc); void OlympicLoc_drop(OlympicLoc* self); // Create a clist, can be sorted by year. -#define i_valclass OlympicLoc // binds _cmp, _clone and _drop. +#define i_keyclass OlympicLoc // binds _cmp, _clone and _drop. #define i_tag OL #include diff --git a/misc/examples/music_arc.c b/misc/examples/music_arc.c index 4efc35c8..49008523 100644 --- a/misc/examples/music_arc.c +++ b/misc/examples/music_arc.c @@ -22,13 +22,13 @@ void Song_drop(Song* s) { // Define the shared pointer: #define i_type SongArc -#define i_valclass Song +#define i_keyclass Song #define i_no_hash // no hash fn for Song, fallback hash pointer to Song. #include // ... and a vector of them #define i_type SongVec -#define i_valboxed SongArc // use i_valboxed on carc / cbox (instead of i_val) +#define i_keyboxed SongArc // use i_keyboxed on carc / cbox (instead of i_key) #include void example3() diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index 5ffdaca2..ee250b2b 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -9,7 +9,7 @@ typedef struct { clist_pnt pntlist; } MyStruct; -#define i_val int +#define i_key int #define i_tag i32 #define i_is_forward #include @@ -20,20 +20,20 @@ int point_cmp(const Point* a, const Point* b) { return c ? c : a->y - b->y; } -#define i_val Point +#define i_key Point #define i_cmp point_cmp #define i_is_forward #define i_tag pnt #include -#define i_val float +#define i_key float #define i_native_cmp // use < and == operators for comparison #include void MyStruct_drop(MyStruct* s); #define i_type MyList -#define i_val MyStruct -#define i_valdrop MyStruct_drop // define drop function +#define i_key MyStruct +#define i_keydrop MyStruct_drop // define drop function #define i_no_clone // must explicitely exclude or define cloning support because of drop. #include diff --git a/misc/examples/new_pque.c b/misc/examples/new_pque.c index dc2ecf12..3df39e0e 100644 --- a/misc/examples/new_pque.c +++ b/misc/examples/new_pque.c @@ -3,7 +3,7 @@ typedef struct Point { int x, y; } Point; #define i_type PointQ -#define i_val Point +#define i_key Point #define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) #include diff --git a/misc/examples/new_queue.c b/misc/examples/new_queue.c index b784bc18..104871bf 100644 --- a/misc/examples/new_queue.c +++ b/misc/examples/new_queue.c @@ -10,14 +10,14 @@ int point_cmp(const Point* a, const Point* b) { int c = c_default_cmp(&a->x, &b->x); return c ? c : c_default_cmp(&a->y, &b->y); } -#define i_val Point +#define i_key Point #define i_cmp point_cmp #define i_is_forward #define i_tag pnt #include #define i_type IQ -#define i_val int +#define i_key int #include int main() { diff --git a/misc/examples/new_sptr.c b/misc/examples/new_sptr.c index 2eff41a5..7fef5d1f 100644 --- a/misc/examples/new_sptr.c +++ b/misc/examples/new_sptr.c @@ -9,21 +9,21 @@ int Person_cmp(const Person* a, const Person* b); uint64_t Person_hash(const Person* p); #define i_type PersonArc -#define i_valclass Person // "class" assume _clone, _drop, _cmp, _hash is defined. +#define i_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined. #include #define i_type IPtr -#define i_val int -#define i_valdrop(x) printf("drop: %d\n", *x) +#define i_key int +#define i_keydrop(x) printf("drop: %d\n", *x) #define i_native_cmp #include #define i_type IPStack -#define i_valboxed IPtr +#define i_keyboxed IPtr #include #define i_type PASet -#define i_valboxed PersonArc +#define i_keyboxed PersonArc #include diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c index 6329b185..6d928cfc 100644 --- a/misc/examples/new_vec.c +++ b/misc/examples/new_vec.c @@ -9,14 +9,14 @@ typedef struct MyStruct { cvec_pnt pntvec; } MyStruct; -#define i_val int +#define i_key int #define i_tag i32 #define i_is_forward #include typedef struct Point { int x, y; } Point; -#define i_val Point +#define i_key Point #define i_tag pnt #define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) #define i_eq(a, b) a->x == b->x && a->y == b->y diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c index 3614c02d..c78b541c 100644 --- a/misc/examples/person_arc.c +++ b/misc/examples/person_arc.c @@ -31,12 +31,12 @@ void Person_drop(Person* p) { } #define i_type PSPtr -#define i_valclass Person // ensure Person_drop +#define i_keyclass Person // ensure Person_drop #define i_cmp Person_cmp // specify object cmp, instead of ptr cmp for arc. #include #define i_type Persons -#define i_valboxed PSPtr // binds PSPtr_cmp, PSPtr_drop... +#define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop... #include diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c index 7564bd88..5084536a 100644 --- a/misc/examples/printspan.c +++ b/misc/examples/printspan.c @@ -3,14 +3,14 @@ #include #define i_implement #include -#define i_val int +#define i_key int #include -#define i_val int +#define i_key int #include -#define i_val_str +#define i_key_str #include -#include +#include using_cspan(intspan, int, 1); void printMe(intspan container) { diff --git a/misc/examples/priority.c b/misc/examples/priority.c index 95dd3183..148e8fc5 100644 --- a/misc/examples/priority.c +++ b/misc/examples/priority.c @@ -3,7 +3,7 @@ #include #include -#define i_val int64_t +#define i_key int64_t #define i_cmp -c_default_cmp // min-heap (increasing values) #define i_tag i #include diff --git a/misc/examples/queue.c b/misc/examples/queue.c index 83c18d09..3154f115 100644 --- a/misc/examples/queue.c +++ b/misc/examples/queue.c @@ -1,7 +1,7 @@ #include #include -#define i_val int +#define i_key int #define i_tag i #include diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c index 8dd52aee..9c394d8e 100644 --- a/misc/examples/rawptr_elements.c +++ b/misc/examples/rawptr_elements.c @@ -16,7 +16,7 @@ // Alternatively, using cbox: #define i_type IBox -#define i_val long +#define i_key long #include // unique_ptr alike. // cmap of cstr => IBox diff --git a/misc/examples/read.c b/misc/examples/read.c index 3c1cadf6..c25cd740 100644 --- a/misc/examples/read.c +++ b/misc/examples/read.c @@ -1,7 +1,7 @@ #define i_implement #include #include -#define i_val_str +#define i_key_str #include #include diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c index 310e0797..88d3747b 100644 --- a/misc/examples/regex_match.c +++ b/misc/examples/regex_match.c @@ -3,7 +3,7 @@ #define i_implement #include -#define i_val float +#define i_key float #include int main() diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index c1168850..d812ff42 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -9,7 +9,7 @@ struct Task { }; #define i_type Scheduler -#define i_val struct Task +#define i_key struct Task #include static bool schedule(Scheduler* sched) diff --git a/misc/examples/shape.c b/misc/examples/shape.c index 1d9fe5c5..bd4bdd5a 100644 --- a/misc/examples/shape.c +++ b/misc/examples/shape.c @@ -76,7 +76,7 @@ struct ShapeAPI Triangle_api = { // ============================================================ #define i_type PointVec -#define i_val Point +#define i_key Point #include typedef struct { @@ -122,8 +122,8 @@ struct ShapeAPI Polygon_api = { // ============================================================ #define i_type Shapes -#define i_val Shape* -#define i_valdrop(x) Shape_delete(*x) +#define i_key Shape* +#define i_keydrop(x) Shape_delete(*x) #define i_no_clone #include diff --git a/misc/examples/stack.c b/misc/examples/stack.c index c817e1ae..96bab24b 100644 --- a/misc/examples/stack.c +++ b/misc/examples/stack.c @@ -3,11 +3,11 @@ #define i_tag i #define i_capacity 100 -#define i_val int +#define i_key int #include #define i_tag c -#define i_val char +#define i_key char #include int main() { diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index 6834dce1..aa055ea6 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -44,7 +44,7 @@ CTEST(cspan, slice) { ASSERT_EQ(45, sum2); } -#define i_val int +#define i_key int #include CTEST(cspan, slice2) { @@ -75,7 +75,7 @@ CTEST(cspan, slice2) { #define i_type Tiles -#define i_val intspan3 +#define i_key intspan3 #include CTEST_FIXTURE(cspan_cube) { -- cgit v1.2.3 From 0073f0a2d67239f019041f07d9a322df03fc7ae4 Mon Sep 17 00:00:00 2001 From: tylov Date: Thu, 13 Jul 2023 08:36:14 +0200 Subject: Moved c_defer() macro from raii.h to ccommon.h. Some changes in cspan. --- README.md | 25 +++++++++++++------------ docs/ccommon_api.md | 1 + docs/cspan_api.md | 6 +++--- include/stc/algo/raii.h | 3 --- include/stc/ccommon.h | 5 ++++- include/stc/cspan.h | 9 +++------ misc/examples/astar.c | 1 - misc/examples/bits.c | 1 - misc/examples/box2.c | 1 - misc/examples/convert.c | 1 - misc/examples/person_arc.c | 1 - misc/examples/regex_replace.c | 1 - misc/examples/sorted_map.c | 1 - misc/examples/unordered_set.c | 1 - 14 files changed, 24 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 67c4d7fd..1601204d 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ non-specified template parameters (based on the specified ones) using meta-progr that you don't have to! You may specify a set of "standard" template parameters for each container, but as a minimum *only one is required*: `i_key` (+ `i_val` for maps). In this case, STC assumes that the elements are of basic types. For non-trivial types, additional -template parameters must be given. +template parameters must be given. 2. ***Alternative insert/lookup type***. You may specify an alternative type to use for lookup in containers. E.g., containers with STC string elements (**cstr**) uses `const char*` as lookup type, so constructing a `cstr` (which may allocate memory) for the lookup @@ -147,9 +147,9 @@ Benchmark notes: STC containers have similar functionality to C++ STL standard containers. All containers except for a few, like **cstr** and **cbits** are generic/templated. No type casting is used, so containers are type-safe like templated types in C++. However, to specify template parameters with STC, you define them as macros prior to -including the container: +including the container. ```c -#define i_type Floats // Container type name; unless defined name would be cvec_float +#define i_type Floats // Container type name (optional); if not defined name would be cvec_float #define i_key float // Container element type #include // "instantiate" the desired container type #include @@ -164,15 +164,15 @@ int main(void) for (int i = 0; i < Floats_size(&nums); ++i) printf(" %g", nums.data[i]); - Floats_sort(&nums); - c_foreach (i, Floats, nums) // Alternative and recommended way to iterate. printf(" %g", *i.ref); // i.ref is a pointer to the current element. Floats_drop(&nums); // cleanup memory } ``` -You may switch to a different container type, e.g. a sorted set (csset): +Note that `i_val*` template parameters can be used instead of `i_key*` for *non-map* containers. + +Switching to a different container type, e.g. a sorted set (csset): [ [Run this code](https://godbolt.org/z/qznfa65e1) ] ```c @@ -188,14 +188,14 @@ int main() Floats_push(&nums, 10.f); Floats_push(&nums, 20.f); - // already sorted, print the numbers + // print the numbers (sorted) c_foreach (i, Floats, nums) printf(" %g", *i.ref); Floats_drop(&nums); } ``` -For user-defined struct elements, `i_cmp` compare function should be defined as the default `<` and `==` +For user-defined struct elements, `i_cmp` compare function should be defined because the default `<` and `==` only works for integral types. *Alternatively, `#define i_opt c_no_cmp` to disable sorting and searching*. Similarily, if an element destructor `i_keydrop` is defined, `i_keyclone` function is required. *Alternatively `#define i_opt c_no_clone` to disable container cloning.* @@ -210,8 +210,8 @@ Let's make a vector of vectors, which can be cloned. All of its element vectors #include #define i_type Vec2D -#define i_keyclass Vec // Use i_keyclass when element type has "members" _clone(), _drop() and _cmp(). -#define i_opt c_no_cmp // Disable cmp (search/sort) for Vec2D because Vec_cmp() is not defined. +#define i_keyclass Vec // Use i_keyclass instead i_key when element type has "members" _clone(), _drop() and _cmp(). +#define i_opt c_no_cmp // Disable cmp (search/sort) for Vec2D because Vec_cmp() does not exist. #include int main(void) @@ -242,16 +242,17 @@ This example uses four different container types: #include #define i_key int -#include // cset_int: unordered set +#include // cset_int: unordered set (assume i_key is basic type, uses `==` operator) struct Point { float x, y; }; // Define cvec_pnt with a less-comparison function for Point. #define i_key struct Point -#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) +#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) // enable sort/search #define i_tag pnt #include // cvec_pnt: vector of struct Point #define i_key int +#define i_native_cmp // enable sort/search. Use native `<` and `==` operators #include // clist_int: singly linked list #define i_key int diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 52ad88e4..6bce56af 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -436,6 +436,7 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are #include // or ... // `c_defer` executes the expression(s) when leaving scope. +// Note: does not require inclusion of "raii.h". cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); c_defer (cstr_drop(&s1), cstr_drop(&s2)) { diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 1aeeb4f7..1d3177da 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -47,12 +47,12 @@ SpanTypeN_iter SpanType_begin(const SpanTypeN* self); SpanTypeN_iter SpanType_end(const SpanTypeN* self); void SpanType_next(SpanTypeN_iter* it); -SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // make a multi-dim cspan, row-major order. -SpanTypeN cspan_md_left(ValueType* data, d1, d2, ...); // column-major ordered cspan (layout left). -SpanTypeN cspan_md_ordered(char order, ValueType* data, d1, d2, ...); // order='C': row-major, 'F' (Fortran): column-major. +SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // make a multi-dim cspan, row-major order. +SpanTypeN cspan_md_order(char order, ValueType* data, d1, d2, ...); // order='C': row-major, 'F': column-major (FORTRAN). // transpose a md span (inverse axes). no changes to the underlying array. void cspan_transpose(const SpanTypeN* self); +bool cspan_is_order_F(const SpanTypeN* self); // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); OutSpan1 cspan_submd2(TYPE OutSpan1, const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span. diff --git a/include/stc/algo/raii.h b/include/stc/algo/raii.h index b0008a96..584f5c59 100644 --- a/include/stc/algo/raii.h +++ b/include/stc/algo/raii.h @@ -23,9 +23,6 @@ #ifndef STC_RAII_INCLUDED #define STC_RAII_INCLUDED -#define c_defer(...) \ - for (int _i = 1; _i; _i = 0, __VA_ARGS__) - #define c_with(...) c_MACRO_OVERLOAD(c_with, __VA_ARGS__) #define c_with_2(declvar, drop) \ for (declvar, *_i, **_ip = &_i; _ip; _ip = 0, drop) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index efbebdc3..45c3a360 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -69,6 +69,7 @@ typedef long long _llong; #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T))) #define c_LITERAL(T) (T) #endif +#define c_new_n(T, n) ((T*)malloc(sizeof(T)*(n))) #define c_malloc(sz) malloc(c_i2u(sz)) #define c_calloc(n, sz) calloc(c_i2u(n), c_i2u(sz)) #define c_realloc(p, sz) realloc(p, c_i2u(sz)) @@ -89,12 +90,12 @@ typedef long long _llong; _tv = *_xp; *_xp = *_yp; *_yp = _tv; } while (0) #define c_sizeof (intptr_t)sizeof #define c_strlen(s) (intptr_t)strlen(s) + #define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u(ilen)) #define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u(ilen)) #define c_memmove(d, s, ilen) memmove(d, s, c_i2u(ilen)) #define c_memset(d, val, ilen) memset(d, val, c_i2u(ilen)) #define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u(ilen)) - #define c_u2i(u) ((intptr_t)((u) + 0*sizeof((u) == 1U))) #define c_i2u(i) ((size_t)(i) + 0*sizeof((i) == 1)) #define c_LTu(a, b) ((size_t)(a) < (size_t)(b)) @@ -228,6 +229,8 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { ; it.index < it.size; ++it.ref, ++it.index) #endif +#define c_defer(...) \ + for (int _i = 1; _i; _i = 0, __VA_ARGS__) #define c_drop(C, ...) \ do { c_forlist (_i, C*, {__VA_ARGS__}) C##_drop(*_i.ref); } while(0) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 4d091395..358d5bf0 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -130,9 +130,7 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) #define cspan_rank(self) c_arraylen((self)->shape) #define cspan_is_order_F(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) - #define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) - #define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__)) #define cspan_front(self) ((self)->data) #define cspan_back(self) ((self)->data + cspan_size(self) - 1) @@ -151,7 +149,7 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define cspan_submd4(OutSpan, self, ...) _cspan_submdN(OutSpan, 4, self, __VA_ARGS__) #define _cspan_submdN(OutSpan, N, self, ...) \ - _cspan_submd##N(c_static_assert(cspan_rank((OutSpan*)0) == N - c_NUMARGS(__VA_ARGS__)), self, __VA_ARGS__) + (OutSpan)_cspan_submd##N(c_static_assert(cspan_rank((OutSpan*)0) == N - c_NUMARGS(__VA_ARGS__)), self, __VA_ARGS__) #define _cspan_submd2(ok, self, x) \ {.data=cspan_at(self, x, 0) + ok, .shape={(self)->shape[1]}, .stride={.d={(self)->stride.d[1]}}} @@ -171,9 +169,8 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define _cspan_submd4_5(ok, self, x, y, z) \ {.data=cspan_at(self, x, y, z, 0) + ok, .shape={(self)->shape[3]}, .stride={.d={(self)->stride.d[3]}}} -#define cspan_md(array, ...) cspan_md_ordered('C', array, __VA_ARGS__) -#define cspan_md_left(array, ...) cspan_md_ordered('F', array, __VA_ARGS__) -#define cspan_md_ordered(order, array, ...) \ +#define cspan_md(array, ...) cspan_md_order('C', array, __VA_ARGS__) +#define cspan_md_order(order, array, ...) /* order='C' or 'F' */ \ {.data=array, .shape={__VA_ARGS__}, \ .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(order, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} diff --git a/misc/examples/astar.c b/misc/examples/astar.c index 44cdefee..590b7952 100644 --- a/misc/examples/astar.c +++ b/misc/examples/astar.c @@ -6,7 +6,6 @@ // https://www.redblobgames.com/pathfinding/a-star/introduction.html #define i_implement #include -#include #include typedef struct diff --git a/misc/examples/bits.c b/misc/examples/bits.c index ce8e1de4..e0a11346 100644 --- a/misc/examples/bits.c +++ b/misc/examples/bits.c @@ -1,6 +1,5 @@ #include #include -#include int main(void) { diff --git a/misc/examples/box2.c b/misc/examples/box2.c index 5ac706d4..eaab1c47 100644 --- a/misc/examples/box2.c +++ b/misc/examples/box2.c @@ -1,6 +1,5 @@ // example: https://doc.rust-lang.org/rust-by-example/std/box.html #include -#include typedef struct { double x; diff --git a/misc/examples/convert.c b/misc/examples/convert.c index 3b9dc3ec..3f2f60f6 100644 --- a/misc/examples/convert.c +++ b/misc/examples/convert.c @@ -1,6 +1,5 @@ #define i_implement #include -#include #define i_key_str #define i_val_str diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c index c78b541c..3a759610 100644 --- a/misc/examples/person_arc.c +++ b/misc/examples/person_arc.c @@ -1,7 +1,6 @@ /* cbox: heap allocated boxed type */ #define i_implement #include -#include typedef struct { cstr name, last; } Person; diff --git a/misc/examples/regex_replace.c b/misc/examples/regex_replace.c index 3a33efde..76664b1b 100644 --- a/misc/examples/regex_replace.c +++ b/misc/examples/regex_replace.c @@ -1,7 +1,6 @@ #define i_import #include #include -#include bool add_10_years(int i, csview match, cstr* out) { if (i == 1) { // group 1 matches year diff --git a/misc/examples/sorted_map.c b/misc/examples/sorted_map.c index 2199846c..ff727632 100644 --- a/misc/examples/sorted_map.c +++ b/misc/examples/sorted_map.c @@ -1,7 +1,6 @@ // https://iq.opengenus.org/containers-cpp-stl/ #include -#include #define i_key int #define i_val int #include diff --git a/misc/examples/unordered_set.c b/misc/examples/unordered_set.c index 006a1e80..14d69ce5 100644 --- a/misc/examples/unordered_set.c +++ b/misc/examples/unordered_set.c @@ -2,7 +2,6 @@ // C program to demonstrate various function of stc cset #define i_implement #include -#include #define i_key_str #include -- cgit v1.2.3 From 23aebb77554bc43c929704e9f1c46dc4520024df Mon Sep 17 00:00:00 2001 From: tylov Date: Sat, 15 Jul 2023 18:06:22 +0200 Subject: Reverted to cspan_submdX() without output span type as first argument. Type/argument safety is still present. --- docs/cspan_api.md | 20 ++++++++++---------- include/stc/cspan.h | 43 ++++++++++++++++++------------------------- misc/examples/multidim.c | 4 ++-- misc/tests/cspan_test.c | 30 +++++++++++++++--------------- 4 files changed, 45 insertions(+), 52 deletions(-) diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 1d3177da..1089e48d 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -30,11 +30,6 @@ SpanType cspan_init(T SpanType, {v1, v2, ...}); // make a 1- SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from compatible STC container SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from C array - // make a subspan of input span rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); -SpanType cspan_subspan(const SpanType* span, intptr_t offset, intptr_t count); -SpanType2 cspan_subspan2(const SpanType2* span, intptr_t offset, intptr_t count); -SpanType3 cspan_subspan3(const SpanType3* span, intptr_t offset, intptr_t count); - intptr_t cspan_size(const SpanTypeN* self); // return number of elements intptr_t cspan_rank(const SpanTypeN* self); // dimensions; compile time constant intptr_t cspan_index(const SpanTypeN* self, intptr_t x, ..); // index of element @@ -54,10 +49,15 @@ SpanTypeN cspan_md_order(char order, ValueType* data, d1, d2, ...); // ord void cspan_transpose(const SpanTypeN* self); bool cspan_is_order_F(const SpanTypeN* self); + // create a subspan of input span rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); +SpanType cspan_subspan(const SpanType* span, intptr_t offset, intptr_t count); +SpanType2 cspan_subspan2(const SpanType2* span, intptr_t offset, intptr_t count); +SpanType3 cspan_subspan3(const SpanType3* span, intptr_t offset, intptr_t count); + // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); -OutSpan1 cspan_submd2(TYPE OutSpan1, const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span. -OutSpanN cspan_submd3(TYPE OutSpanN, const SpanType3* parent, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span. -OutSpanN cspan_submd4(TYPE OutSpanN, const SpanType4* parent, intptr_t x, ...); // number of args decides rank of output span. +OutSpan1 cspan_submd2(const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span. +OutSpanN cspan_submd3(const SpanType3* parent, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span. +OutSpanN cspan_submd4(const SpanType4* parent, intptr_t x, ...); // number of args decides rank of output span. // general slicing of an md span. // {i}: reduce rank. {i,c_END}: slice to end. {c_ALL}: use full extent. @@ -106,7 +106,7 @@ int main() { myspan3 ms3 = cspan_md(arr, 2, 3, 4); // C-order, i.e. row-major. myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {1,3}, {2,c_END}); - myspan2 ss2 = cspan_submd3(myspan2, &ss3, 1); + myspan2 ss2 = cspan_submd3(&ss3, 1); c_forrange (i, ss2.shape[0]) c_forrange (j, ss2.shape[1]) @@ -156,7 +156,7 @@ int main() Span3 span3 = cspan_md(span.data, 2, 4, 3); // reduce rank: (i.e. span3[1]) - Span2 span2 = cspan_submd3(Span2, &span3, 1); + Span2 span2 = cspan_submd3(&span3, 1); puts("\niterate span2 flat:"); c_foreach (i, Span2, span2) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 358d5bf0..582e1004 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -82,7 +82,7 @@ int demo2() { } \ STC_INLINE Self Self##_slice_(Self##_value* v, const int32_t shape[], const int32_t stri[], \ const int rank, const int32_t a[][2]) { \ - Self s = {.data=v}; int outrank; \ + Self s; s.data = v; int outrank; \ s.data += _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ c_assert(outrank == RANK); \ return s; \ @@ -144,30 +144,23 @@ using_cspan_tuple(7); using_cspan_tuple(8); {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride=(self)->stride} // cspan_submd(): Reduce rank (N <= 4) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); -#define cspan_submd2(OutSpan, self, ...) _cspan_submdN(OutSpan, 2, self, __VA_ARGS__) -#define cspan_submd3(OutSpan, self, ...) _cspan_submdN(OutSpan, 3, self, __VA_ARGS__) -#define cspan_submd4(OutSpan, self, ...) _cspan_submdN(OutSpan, 4, self, __VA_ARGS__) - -#define _cspan_submdN(OutSpan, N, self, ...) \ - (OutSpan)_cspan_submd##N(c_static_assert(cspan_rank((OutSpan*)0) == N - c_NUMARGS(__VA_ARGS__)), self, __VA_ARGS__) - -#define _cspan_submd2(ok, self, x) \ - {.data=cspan_at(self, x, 0) + ok, .shape={(self)->shape[1]}, .stride={.d={(self)->stride.d[1]}}} -#define _cspan_submd3(...) c_MACRO_OVERLOAD(_cspan_submd3, __VA_ARGS__) -#define _cspan_submd3_3(ok, self, x) \ - {.data=cspan_at(self, x, 0, 0) + ok, .shape={(self)->shape[1], (self)->shape[2]}, \ - .stride={.d={(self)->stride.d[1], (self)->stride.d[2]}}} -#define _cspan_submd3_4(ok, self, x, y) \ - {.data=cspan_at(self, x, y, 0) + ok, .shape={(self)->shape[2]}, .stride={.d={(self)->stride.d[2]}}} -#define _cspan_submd4(...) c_MACRO_OVERLOAD(_cspan_submd4, __VA_ARGS__) -#define _cspan_submd4_3(ok, self, x) \ - {.data=cspan_at(self, x, 0, 0, 0) + ok, .shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \ - .stride={.d={(self)->stride.d[1], (self)->stride.d[2], (self)->stride.d[3]}}} -#define _cspan_submd4_4(ok, self, x, y) \ - {.data=cspan_at(self, x, y, 0, 0) + ok, .shape={(self)->shape[2], (self)->shape[3]}, \ - .stride={.d={(self)->stride.d[2], (self)->stride.d[3]}}} -#define _cspan_submd4_5(ok, self, x, y, z) \ - {.data=cspan_at(self, x, y, z, 0) + ok, .shape={(self)->shape[3]}, .stride={.d={(self)->stride.d[3]}}} +#define cspan_submd2(self, x) \ + {.data=cspan_at(self, x, 0), .shape={(self)->shape[1]}, .stride=(cspan_tuple1){.d={(self)->stride.d[1]}}} +#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__) +#define cspan_submd3_2(self, x) \ + {.data=cspan_at(self, x, 0, 0), .shape={(self)->shape[1], (self)->shape[2]}, \ + .stride=(cspan_tuple2){.d={(self)->stride.d[1], (self)->stride.d[2]}}} +#define cspan_submd3_3(self, x, y) \ + {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}, .stride=(cspan_tuple1){.d={(self)->stride.d[2]}}} +#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__) +#define cspan_submd4_2(self, x) \ + {.data=cspan_at(self, x, 0, 0, 0), .shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \ + .stride=(cspan_tuple3){.d={(self)->stride.d[1], (self)->stride.d[2], (self)->stride.d[3]}}} +#define cspan_submd4_3(self, x, y) \ + {.data=cspan_at(self, x, y, 0, 0), .shape={(self)->shape[2], (self)->shape[3]}, \ + .stride=(cspan_tuple2){.d={(self)->stride.d[2], (self)->stride.d[3]}}} +#define cspan_submd4_4(self, x, y, z) \ + {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}, .stride=(cspan_tuple1){.d={(self)->stride.d[3]}}} #define cspan_md(array, ...) cspan_md_order('C', array, __VA_ARGS__) #define cspan_md_order(order, array, ...) /* order='C' or 'F' */ \ diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c index dbea9699..45b97378 100644 --- a/misc/examples/multidim.c +++ b/misc/examples/multidim.c @@ -45,7 +45,7 @@ int main() printf(" %d", *i.ref); puts(""); - ispan2 ms2 = cspan_submd3(ispan2, &ms3, 0); + ispan2 ms2 = cspan_submd3(&ms3, 0); // write data using 2D view for (int i=0; i != ms2.shape[0]; i++) @@ -58,7 +58,7 @@ int main() puts(""); puts("iterate subspan ms3[1]:"); - ispan2 sub = cspan_submd3(ispan2, &ms3, 1); + ispan2 sub = cspan_submd3(&ms3, 1); c_foreach (i, ispan2, sub) printf(" %d", *i.ref); puts(""); diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index aa055ea6..d7ca9b64 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -10,11 +10,11 @@ CTEST(cspan, subdim) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; intspan3 m = cspan_md(array, 2, 2, 3); - for (size_t i = 0; i < m.shape[0]; ++i) { - intspan2 sub_i = cspan_submd3(intspan2, &m, i); - for (size_t j = 0; j < m.shape[1]; ++j) { - intspan sub_i_j = cspan_submd2(intspan, &sub_i, j); - for (size_t k = 0; k < m.shape[2]; ++k) { + for (int i = 0; i < m.shape[0]; ++i) { + intspan2 sub_i = cspan_submd3(&m, i); + for (int j = 0; j < m.shape[1]; ++j) { + intspan sub_i_j = cspan_submd2(&sub_i, j); + for (int k = 0; k < m.shape[2]; ++k) { ASSERT_EQ(*cspan_at(&sub_i_j, k), *cspan_at(&m, i, j, k)); } } @@ -25,18 +25,18 @@ CTEST(cspan, slice) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; intspan2 m1 = cspan_md(array, 3, 4); - size_t sum1 = 0; - for (size_t i = 0; i < m1.shape[0]; ++i) { - for (size_t j = 0; j < m1.shape[1]; ++j) { + int sum1 = 0; + for (int i = 0; i < m1.shape[0]; ++i) { + for (int j = 0; j < m1.shape[1]; ++j) { sum1 += *cspan_at(&m1, i, j); } } intspan2 m2 = cspan_slice(intspan2, &m1, {c_ALL}, {2,4}); - size_t sum2 = 0; - for (size_t i = 0; i < m2.shape[0]; ++i) { - for (size_t j = 0; j < m2.shape[1]; ++j) { + int sum2 = 0; + for (int i = 0; i < m2.shape[0]; ++i) { + for (int j = 0; j < m2.shape[1]; ++j) { sum2 += *cspan_at(&m2, i, j); } } @@ -56,10 +56,10 @@ CTEST(cspan, slice2) { intspan3 ms3 = cspan_md(stack.data, 10, 20, 30); ms3 = cspan_slice(intspan3, &ms3, {1,4}, {3,7}, {20,24}); - size_t sum = 0; - for (size_t i = 0; i < ms3.shape[0]; ++i) { - for (size_t j = 0; j < ms3.shape[1]; ++j) { - for (size_t k = 0; k < ms3.shape[2]; ++k) { + int sum = 0; + for (int i = 0; i < ms3.shape[0]; ++i) { + for (int j = 0; j < ms3.shape[1]; ++j) { + for (int k = 0; k < ms3.shape[2]; ++k) { sum += *cspan_at(&ms3, i, j, k); } } -- cgit v1.2.3 From e9121702a5d69624ef1e782e85a8f032e4f4e875 Mon Sep 17 00:00:00 2001 From: tylov Date: Sat, 15 Jul 2023 23:20:16 +0200 Subject: Improved warning, and other enhancements in ccommon.h --- README.md | 2 +- docs/carc_api.md | 2 +- docs/cbox_api.md | 2 +- docs/ccommon_api.md | 10 +++++----- docs/cdeq_api.md | 2 +- docs/clist_api.md | 6 +++--- docs/cmap_api.md | 12 ++++++------ docs/cpque_api.md | 2 +- docs/cqueue_api.md | 2 +- docs/crandom_api.md | 2 +- docs/cregex_api.md | 2 +- docs/cset_api.md | 2 +- docs/csmap_api.md | 8 ++++---- docs/cspan_api.md | 6 +++--- docs/csset_api.md | 2 +- docs/cstack_api.md | 2 +- docs/cstr_api.md | 2 +- docs/csview_api.md | 6 +++--- docs/cvec_api.md | 4 ++-- include/c11/fmt.h | 2 +- include/stc/algo/crange.h | 2 +- include/stc/algo/filter.h | 2 +- include/stc/algo/sort.h | 4 ++-- include/stc/carc.h | 4 ++-- include/stc/cbits.h | 2 +- include/stc/cbox.h | 4 ++-- include/stc/ccommon.h | 6 +++--- include/stc/clist.h | 2 +- include/stc/crand.h | 2 +- include/stc/cvec.h | 2 +- misc/benchmarks/plotbench/cpque_benchmark.cpp | 2 +- misc/benchmarks/various/cspan_bench.c | 2 +- misc/benchmarks/various/rust_cmap.c | 2 +- misc/benchmarks/various/sso_bench.cpp | 2 +- misc/benchmarks/various/string_bench_STC.cpp | 2 +- misc/benchmarks/various/string_bench_STD.cpp | 2 +- misc/examples/arc_containers.c | 2 +- misc/examples/arc_demo.c | 2 +- misc/examples/arcvec_erase.c | 2 +- misc/examples/birthday.c | 2 +- misc/examples/bits2.c | 2 +- misc/examples/books.c | 2 +- misc/examples/box.c | 2 +- misc/examples/cointerleave.c | 2 +- misc/examples/complex.c | 2 +- misc/examples/convert.c | 2 +- misc/examples/csmap_erase.c | 2 +- misc/examples/csmap_find.c | 2 +- misc/examples/csmap_insert.c | 2 +- misc/examples/csset_erase.c | 2 +- misc/examples/cstr_match.c | 2 +- misc/examples/demos.c | 18 +++++++++--------- misc/examples/dining_philosophers.c | 2 +- misc/examples/forloops.c | 2 +- misc/examples/functor.c | 2 +- misc/examples/gauss2.c | 2 +- misc/examples/generator.c | 2 +- misc/examples/intrusive.c | 2 +- misc/examples/list.c | 2 +- misc/examples/list_erase.c | 2 +- misc/examples/list_splice.c | 2 +- misc/examples/lower_bound.c | 2 +- misc/examples/mmap.c | 2 +- misc/examples/multidim.c | 2 +- misc/examples/multimap.c | 2 +- misc/examples/music_arc.c | 4 ++-- misc/examples/new_list.c | 2 +- misc/examples/new_map.c | 2 +- misc/examples/new_pque.c | 2 +- misc/examples/new_queue.c | 2 +- misc/examples/new_smap.c | 2 +- misc/examples/new_vec.c | 2 +- misc/examples/person_arc.c | 2 +- misc/examples/printspan.c | 2 +- misc/examples/priority.c | 2 +- misc/examples/queue.c | 2 +- misc/examples/random.c | 2 +- misc/examples/rawptr_elements.c | 2 +- misc/examples/read.c | 2 +- misc/examples/regex2.c | 2 +- misc/examples/regex_match.c | 2 +- misc/examples/regex_replace.c | 2 +- misc/examples/replace.c | 2 +- misc/examples/scheduler.c | 2 +- misc/examples/sidebyside.cpp | 2 +- misc/examples/sorted_map.c | 2 +- misc/examples/splitstr.c | 2 +- misc/examples/sso_map.c | 2 +- misc/examples/sso_substr.c | 2 +- misc/examples/stack.c | 2 +- misc/examples/sview_split.c | 2 +- misc/examples/triples.c | 2 +- misc/examples/unordered_set.c | 2 +- misc/examples/utf8replace_c.c | 2 +- misc/examples/vikings.c | 2 +- 95 files changed, 128 insertions(+), 128 deletions(-) diff --git a/README.md b/README.md index 1601204d..b7e06790 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ Switching to a different container type, e.g. a sorted set (csset): #include // Use a sorted set instead #include -int main() +int main(void) { Floats nums = {0}; Floats_push(&nums, 30.f); diff --git a/docs/carc_api.md b/docs/carc_api.md index 254f868a..8b7b67a1 100644 --- a/docs/carc_api.md +++ b/docs/carc_api.md @@ -97,7 +97,7 @@ bool carc_X_value_eq(const i_key* x, const i_key* y); #define i_keyboxed Arc // Note: use i_keyboxed for carc or cbox value types #include -int main() +int main(void) { Stack s1 = {0}, s2 = {0}; Map *map; diff --git a/docs/cbox_api.md b/docs/cbox_api.md index 83d59521..b6c76d2f 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -90,7 +90,7 @@ void int_drop(int* x) { #define i_keyboxed IBox // NB: use i_keyboxed instead of i_key #include // IVec : std::vector> -int main() +int main(void) { IVec vec = c_init(Vec, {2021, 2012, 2022, 2015}); ISet set = {0}; diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 6bce56af..e053f743 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -137,7 +137,7 @@ bool isPrime(long long i) { return true; } -int main() { +int main(void) { // Get 10 prime numbers starting from 1000. Skip the first 15 primes, // then select every 25th prime (including the initial). crange R = crange_make(1001, INT64_MAX, 2); // 1001, 1003, ... @@ -214,7 +214,7 @@ There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c). #include #include -int main() { +int main(void) { int nums[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}; intarray_sort_n(nums, c_arraylen(nums)); c_forrange (i, c_arraylen(arr)) printf(" %d", arr[i]); @@ -230,7 +230,7 @@ possible and very fast. Note that `i_more` must be defined to retain specified t #include #include -int main() { +int main(void) { MyDeq deq = c_init(MyDeq, {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}); MyDeq_sort_n(&deq, MyDeq_size(&deq)); c_foreach (i, MyDeq, deq) printf(" %d", *i.ref); @@ -348,7 +348,7 @@ int gcd(int a, int b) { // greatest common denominator return a; } -int main() +int main(void) { struct triples t = {.n=INT32_MAX}; int n = 0; @@ -500,7 +500,7 @@ cvec_str readFile(const char* name) return vec; } -int main() +int main(void) { c_with (cvec_str vec = readFile(__FILE__), cvec_str_drop(&vec)) c_foreach (i, cvec_str, vec) diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index 292b0933..c6de6cd6 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -101,7 +101,7 @@ void cdeq_X_value_drop(cdeq_X_value* pval); #include -int main() { +int main(void) { cdeq_i q = cdeq_i_init(); cdeq_i_push_front(&q, 10); c_foreach (i, cdeq_i, q) diff --git a/docs/clist_api.md b/docs/clist_api.md index 023cca41..3d785789 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -122,7 +122,7 @@ Interleave *push_front()* / *push_back()* then *sort()*: #include -int main() { +int main(void) { DList list = c_init(DList, {10., 20., 30., 40., 50., 60., 70., 80., 90.}); c_forrange (i, 1, 10) { @@ -159,7 +159,7 @@ Use of *erase_at()* and *erase_range()*: #include -int main () +int main(void) { clist_i L = c_init(clist_i, {10, 20, 30, 40, 50}); // 10 20 30 40 50 @@ -194,7 +194,7 @@ Splice `[30, 40]` from *L2* into *L1* before `3`: #include -int main() { +int main(void) { clist_i L1 = c_init(clist_i, {1, 2, 3, 4, 5}); clist_i L2 = c_init(clist_i, {10, 20, 30, 40, 50}); diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 8ef322e6..eca350b4 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -121,7 +121,7 @@ bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // ! #define i_val_str #include -int main() +int main(void) { // Create an unordered_map of three strings (that map to strings) cmap_str umap = c_init(cmap_str, { @@ -165,7 +165,7 @@ This example uses a cmap with cstr as mapped value. #define i_val_str #include -int main() +int main(void) { uint32_t col = 0xcc7744ff; @@ -208,7 +208,7 @@ typedef struct { int x, y, z; } Vec3i; #define i_tag vi #include -int main() +int main(void) { // Define map with defered destruct cmap_vi vecs = {0}; @@ -243,7 +243,7 @@ typedef struct { int x, y, z; } Vec3i; #define i_tag iv #include -int main() +int main(void) { cmap_iv vecs = {0} @@ -304,7 +304,7 @@ static inline void Viking_drop(Viking* vk) { #define i_val int #include -int main() +int main(void) { // Use a HashMap to store the vikings' health points. Vikings vikings = {0}; @@ -380,7 +380,7 @@ static inline RViking Viking_toraw(const Viking* vp) { #define i_val int #include -int main() +int main(void) { Vikings vikings = {0}; diff --git a/docs/cpque_api.md b/docs/cpque_api.md index ca94e367..5b63dfd1 100644 --- a/docs/cpque_api.md +++ b/docs/cpque_api.md @@ -68,7 +68,7 @@ i_key cpque_X_value_clone(i_key value); #define i_tag i #include -int main() +int main(void) { intptr_t N = 10000000; crand_t rng = crand_init(1234); diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md index bce62833..b324e5fc 100644 --- a/docs/cqueue_api.md +++ b/docs/cqueue_api.md @@ -74,7 +74,7 @@ void cqueue_X_value_drop(cqueue_X_value* pval); #include -int main() { +int main(void) { cqueue_i Q = cqueue_i_init(); // push() and pop() a few. diff --git a/docs/crandom_api.md b/docs/crandom_api.md index 74e23a6a..22a4f4dd 100644 --- a/docs/crandom_api.md +++ b/docs/crandom_api.md @@ -76,7 +76,7 @@ double crand_norm(crand_t* rng, crand_norm_t* dist); #define i_tag i #include -int main() +int main(void) { enum {N = 10000000}; const double Mean = -12.0, StdDev = 6.0, Scale = 74; diff --git a/docs/cregex_api.md b/docs/cregex_api.md index f87240f8..52476e09 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -102,7 +102,7 @@ If an error occurs ```cregex_compile``` returns a negative error code stored in #define i_import // include dependent cstr, utf8 and cregex function definitions. #include -int main() { +int main(void) { const char* input = "start date is 2023-03-01, end date 2025-12-31."; const char* pattern = "\\b(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)\\b"; diff --git a/docs/cset_api.md b/docs/cset_api.md index 7bce3136..e894ad4f 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -83,7 +83,7 @@ cset_X_value cset_X_value_clone(cset_X_value val); #define i_key_str #include -int main () +int main(void) { Strset first, second={0}, third={0}, fourth={0}, fifth; diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 2fd9f6a5..099d7dfc 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -108,7 +108,7 @@ void csmap_X_value_drop(csmap_X_value* pval); #define i_val_str // ditto #include -int main() +int main(void) { // Create a sorted map of three strings (maps to string) csmap_str colors = c_init(csmap_str, { @@ -166,7 +166,7 @@ static void print_result(strmap_result result) { print_node(result.ref); } -int main() +int main(void) { strmap m = {0}; @@ -191,7 +191,7 @@ This example uses a csmap with cstr as mapped value. #define i_val_str #include -int main() +int main(void) { uint32_t col = 0xcc7744ff; IDSMap idnames = c_init(IDSMap, { {100, "Red"}, {110, "Blue"} }); @@ -237,7 +237,7 @@ static int Vec3i_cmp(const Vec3i* a, const Vec3i* b) { #include #include -int main() +int main(void) { csmap_vi vmap = {0}; diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 1089e48d..09821450 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -101,7 +101,7 @@ if __name__ == '__main__': #include using_cspan3(myspan, int); // define myspan, myspan2, myspan3. -int main() { +int main(void) { int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; myspan3 ms3 = cspan_md(arr, 2, 3, 4); // C-order, i.e. row-major. @@ -123,7 +123,7 @@ int main() { #include #include -int main() { +int main(void) { int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; std::mdspan ms3(arr, 2, 3, 4); @@ -147,7 +147,7 @@ Slicing cspan without and with reducing the rank: using_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3 -int main() +int main(void) { // c_init() can create any STC container/span from an initializer list: Span span = c_init(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, diff --git a/docs/csset_api.md b/docs/csset_api.md index d086b660..aef3af3c 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -83,7 +83,7 @@ csset_X_value csset_X_value_clone(csset_X_value val); #define i_key_str #include -int main () +int main(void) { SSet second={0}, third={0}, fourth={0}, fifth={0}; diff --git a/docs/cstack_api.md b/docs/cstack_api.md index 51889d7f..e799b152 100644 --- a/docs/cstack_api.md +++ b/docs/cstack_api.md @@ -77,7 +77,7 @@ void cstack_X_value_drop(cvec_X_value* pval); #include -int main() { +int main(void) { IStack stk = IStack_init(); for (int i=0; i < 100; ++i) diff --git a/docs/cstr_api.md b/docs/cstr_api.md index c7d19e0c..dae5669f 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -160,7 +160,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt #define i_implement #include -int main() { +int main(void) { cstr s0, s1, full_path; c_defer( cstr_drop(&s0), diff --git a/docs/csview_api.md b/docs/csview_api.md index 33df6a64..79a5c07b 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -121,7 +121,7 @@ uint64_t csview_hash(const csview* x); #include #include -int main () +int main(void) { cstr str1 = cstr_lit("We think in generalities, but we live in details."); // (quoting Alfred N. Whitehead) @@ -151,7 +151,7 @@ red Apples #define i_import // include dependent cstr, utf8 and cregex function definitions. #include -int main() +int main(void) { cstr s1 = cstr_lit("hell😀 w😀rld"); @@ -198,7 +198,7 @@ cstack_str string_split(csview input, const char* sep) return out; } -int main() +int main(void) { print_split(c_sv("//This is a//double-slash//separated//string"), "//"); print_split(c_sv("This has no matching separator"), "xx"); diff --git a/docs/cvec_api.md b/docs/cvec_api.md index ce85e446..d38ef23f 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -112,7 +112,7 @@ cvec_X_raw cvec_X_value_drop(cvec_X_value* pval); #include -int main() +int main(void) { // Create a vector containing integers cvec_int vec = {0}; @@ -153,7 +153,7 @@ sorted: 5 7 8 13 16 25 #define i_key_str #include -int main() { +int main(void) { cvec_str names = cvec_str_init(); cvec_str_emplace(&names, "Mary"); diff --git a/include/c11/fmt.h b/include/c11/fmt.h index 45044e33..d2eab8bc 100644 --- a/include/c11/fmt.h +++ b/include/c11/fmt.h @@ -33,7 +33,7 @@ void fmt_close(fmt_stream* ss); #define FMT_SHORTS #include "c11/fmt.h" -int main() { +int main(void) { const double pi = 3.141592653589793; const size_t x = 1234567890; const char* string = "Hello world"; diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h index 45ef53a1..03162a2d 100644 --- a/include/stc/algo/crange.h +++ b/include/stc/algo/crange.h @@ -25,7 +25,7 @@ #include #include -int main() +int main(void) { crange r1 = crange_make(80, 90); c_foreach (i, crange, r1) diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index f5de1811..4a227927 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -26,7 +26,7 @@ #include #include -int main() +int main(void) { cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7, 8, 9}); diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h index 01e7d521..06d7395f 100644 --- a/include/stc/algo/sort.h +++ b/include/stc/algo/sort.h @@ -31,7 +31,7 @@ template params: #define i_key int #include -int main() { +int main(void) { int nums[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21}; intarray_sort_n(nums, c_arraylen(nums)); @@ -48,7 +48,7 @@ int main() { #include #include -int main() { +int main(void) { IDeq nums = c_init(IDeq, {5434, 25, 245, 1, 654, 33, 543, 21}); IDeq_push_front(&nums, 23); IDeq_push_front(&nums, 321); diff --git a/include/stc/carc.h b/include/stc/carc.h index b77b7dfb..9ba2ddd1 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -46,7 +46,7 @@ void Person_drop(Person* p) { #define i_opt c_no_cmp|c_no_hash // exclude cmp, hash #include -int main() { +int main(void) { ArcPers p = ArcPers_from(Person_make("John", "Smiths")); ArcPers q = ArcPers_clone(p); // share the pointer @@ -225,4 +225,4 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { #undef _i_atomic_inc #undef _i_atomic_dec_and_test #include "priv/template2.h" -#undef _i_carc \ No newline at end of file +#undef _i_carc diff --git a/include/stc/cbits.h b/include/stc/cbits.h index 66bc6354..3b5785d3 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -26,7 +26,7 @@ Similar to boost::dynamic_bitset / std::bitset #include #include "cbits.h" -int main() { +int main(void) { cbits bset = cbits_with_size(23, true); cbits_reset(&bset, 9); cbits_resize(&bset, 43, false); diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 86d5a6a6..25d41b92 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -47,7 +47,7 @@ void Person_drop(Person* p) { #define i_no_cmp // no cmp/hash is defined #include -int main() { +int main(void) { c_auto (PBox, p, q) { p = PBox_from(Person_from("John Smiths", "josmiths@gmail.com")); @@ -205,4 +205,4 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) { { return c_default_hash(&self->get); } #endif #include "priv/template2.h" -#undef _i_cbox \ No newline at end of file +#undef _i_cbox diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 45c3a360..1f9ea80d 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -85,7 +85,7 @@ typedef long long _llong; #define c_assert(expr) assert(expr) #endif #define c_container_of(p, C, m) ((C*)((char*)(1 ? (p) : &((C*)0)->m) - offsetof(C, m))) -#define c_const_cast(T, p) ((T)(p) + 0*sizeof((T)0 == (p))) +#define c_const_cast(T, p) ((T)(1 ? (p) : (T)0)) #define c_swap(T, xp, yp) do { T *_xp = xp, *_yp = yp, \ _tv = *_xp; *_xp = *_yp; *_yp = _tv; } while (0) #define c_sizeof (intptr_t)sizeof @@ -96,8 +96,8 @@ typedef long long _llong; #define c_memmove(d, s, ilen) memmove(d, s, c_i2u(ilen)) #define c_memset(d, val, ilen) memset(d, val, c_i2u(ilen)) #define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u(ilen)) -#define c_u2i(u) ((intptr_t)((u) + 0*sizeof((u) == 1U))) -#define c_i2u(i) ((size_t)(i) + 0*sizeof((i) == 1)) +#define c_u2i(u) ((intptr_t)(1 ? (u) : (size_t)1)) +#define c_i2u(i) ((size_t)(1 ? (i) : (intptr_t)1)) #define c_LTu(a, b) ((size_t)(a) < (size_t)(b)) // x and y are i_keyraw* type, defaults to i_key*: diff --git a/include/stc/clist.h b/include/stc/clist.h index 9cc1bb39..d7cf30b9 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -32,7 +32,7 @@ #define i_tag ix #include - int main() + int main(void) { c_auto (clist_ix, list) { diff --git a/include/stc/crand.h b/include/stc/crand.h index 89b681cd..0a6aa9e0 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -29,7 +29,7 @@ // crand: Pseudo-random number generator #include "stc/crand.h" -int main() { +int main(void) { uint64_t seed = 123456789; crand_t rng = crand_init(seed); crand_unif_t dist1 = crand_unif_init(1, 6); diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 9b95306e..d08e382f 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -44,7 +44,7 @@ struct MyStruct { #define i_tag i32 #include -int main() { +int main(void) { cvec_i32 vec = {0}; cvec_i32_push(&vec, 123); cvec_i32_drop(&vec); diff --git a/misc/benchmarks/plotbench/cpque_benchmark.cpp b/misc/benchmarks/plotbench/cpque_benchmark.cpp index 2d4c7a28..6c62ae3e 100644 --- a/misc/benchmarks/plotbench/cpque_benchmark.cpp +++ b/misc/benchmarks/plotbench/cpque_benchmark.cpp @@ -58,7 +58,7 @@ void stc_test() } -int main() +int main(void) { puts("STD P.QUEUE:"); std_test(); diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c index 392c9d3f..e3997ff0 100644 --- a/misc/benchmarks/various/cspan_bench.c +++ b/misc/benchmarks/various/cspan_bench.c @@ -114,7 +114,7 @@ static void MDRanges_loop_over_joined(intptr_t state) printf("joined: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); } -int main() +int main(void) { for (int i = 0; i < nx * ny * nz; ++i) Vin[i] = i + 1.23; diff --git a/misc/benchmarks/various/rust_cmap.c b/misc/benchmarks/various/rust_cmap.c index abdb42b0..97047e0b 100644 --- a/misc/benchmarks/various/rust_cmap.c +++ b/misc/benchmarks/various/rust_cmap.c @@ -22,7 +22,7 @@ uint64_t romu_trio(uint64_t s[3]) { return xp; } -int main() +int main(void) { cmap_u64 m = {0}; diff --git a/misc/benchmarks/various/sso_bench.cpp b/misc/benchmarks/various/sso_bench.cpp index 6d3d107a..244c1291 100644 --- a/misc/benchmarks/various/sso_bench.cpp +++ b/misc/benchmarks/various/sso_bench.cpp @@ -112,7 +112,7 @@ int benchmark_lookup(C& container, const int n, const int strsize) { } #include -int main() { +int main(void) { uint64_t seed = time(NULL); // 4321; int sum, n; diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp index 319b0b19..a5dfd901 100644 --- a/misc/benchmarks/various/string_bench_STC.cpp +++ b/misc/benchmarks/various/string_bench_STC.cpp @@ -184,7 +184,7 @@ void benchmark( //const size_t MAX_LOOP = 1000000; const size_t MAX_LOOP = 2000; -int main() +int main(void) { c_auto (cvec_str, vec_string) c_auto (cvec_sv, vec_stringview) diff --git a/misc/benchmarks/various/string_bench_STD.cpp b/misc/benchmarks/various/string_bench_STD.cpp index 07934948..153ac02f 100644 --- a/misc/benchmarks/various/string_bench_STD.cpp +++ b/misc/benchmarks/various/string_bench_STD.cpp @@ -194,7 +194,7 @@ void benchmark( //const size_t MAX_LOOP = 1000000; const size_t MAX_LOOP = 2000; -int main() +int main(void) { std::vector vec_shortstr; std::vector vec_shortstrview; diff --git a/misc/examples/arc_containers.c b/misc/examples/arc_containers.c index 524758e7..2fb04c56 100644 --- a/misc/examples/arc_containers.c +++ b/misc/examples/arc_containers.c @@ -24,7 +24,7 @@ #define i_keyboxed Arc // as above #include -int main() +int main(void) { Stack stack = {0}; List list = {0}; diff --git a/misc/examples/arc_demo.c b/misc/examples/arc_demo.c index 547e1737..87d64e67 100644 --- a/misc/examples/arc_demo.c +++ b/misc/examples/arc_demo.c @@ -20,7 +20,7 @@ void int_drop(int* x) { #define i_keyboxed Arc // note: as above. #include // cvec_Arc (like: std::vector>) -int main() +int main(void) { const int years[] = {2021, 2012, 2022, 2015}; diff --git a/misc/examples/arcvec_erase.c b/misc/examples/arcvec_erase.c index f409258b..addef8b7 100644 --- a/misc/examples/arcvec_erase.c +++ b/misc/examples/arcvec_erase.c @@ -13,7 +13,7 @@ void show_drop(int* x) { printf("drop: %d\n", *x); } #include // Vec: cvec -int main() +int main(void) { Vec vec = c_init(Vec, {2012, 1990, 2012, 2019, 2015}); diff --git a/misc/examples/birthday.c b/misc/examples/birthday.c index 2820c42f..4742cb45 100644 --- a/misc/examples/birthday.c +++ b/misc/examples/birthday.c @@ -60,7 +60,7 @@ void test_distribution(void) cmap_x_drop(&map); } -int main() +int main(void) { seed = (uint64_t)time(NULL); test_distribution(); diff --git a/misc/examples/bits2.c b/misc/examples/bits2.c index 913bd185..de2f16f4 100644 --- a/misc/examples/bits2.c +++ b/misc/examples/bits2.c @@ -5,7 +5,7 @@ #define i_capacity 80 // enable fixed bitset on the stack #include -int main() +int main(void) { Bits s1 = Bits_from("1110100110111"); diff --git a/misc/examples/books.c b/misc/examples/books.c index 7f0660b8..1fd57f27 100644 --- a/misc/examples/books.c +++ b/misc/examples/books.c @@ -7,7 +7,7 @@ // Type inference lets us omit an explicit type signature (which // would be `HashMap` in this example). -int main() +int main(void) { cmap_str book_reviews = {0}; diff --git a/misc/examples/box.c b/misc/examples/box.c index 3f55e15d..94d126c0 100644 --- a/misc/examples/box.c +++ b/misc/examples/box.c @@ -36,7 +36,7 @@ void Person_drop(Person* p) { #define i_keyboxed PBox // "arcbox" informs that PBox is a smart pointer. #include -int main() +int main(void) { Persons vec = {0}; PBox p = PBox_from(Person_make("Laura", "Palmer")); diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index c3c5926a..599ceaab 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -56,7 +56,7 @@ void Use(void) c_drop(IVec, &a, &b); } -int main() +int main(void) { Use(); } diff --git a/misc/examples/complex.c b/misc/examples/complex.c index 405afef3..4eb1574b 100644 --- a/misc/examples/complex.c +++ b/misc/examples/complex.c @@ -28,7 +28,7 @@ #include -int main() +int main(void) { MapMap mmap = {0}; diff --git a/misc/examples/convert.c b/misc/examples/convert.c index 3f2f60f6..fa64560e 100644 --- a/misc/examples/convert.c +++ b/misc/examples/convert.c @@ -11,7 +11,7 @@ #define i_key_str #include -int main() +int main(void) { cmap_str map, mclone; cvec_str keys = {0}, values = {0}; diff --git a/misc/examples/csmap_erase.c b/misc/examples/csmap_erase.c index 9433d370..8d4eeae3 100644 --- a/misc/examples/csmap_erase.c +++ b/misc/examples/csmap_erase.c @@ -16,7 +16,7 @@ void printmap(mymap m) printf("\nsize() == %" c_ZI "\n\n", mymap_size(&m)); } -int main() +int main(void) { mymap m1 = {0}; diff --git a/misc/examples/csmap_find.c b/misc/examples/csmap_find.c index b535e9ad..c392338d 100644 --- a/misc/examples/csmap_find.c +++ b/misc/examples/csmap_find.c @@ -40,7 +40,7 @@ void findit(csmap_istr c, csmap_istr_key val) } } -int main() +int main(void) { csmap_istr m1 = c_init(csmap_istr, {{40, "Zr"}, {45, "Rh"}}); cvec_istr v = {0}; diff --git a/misc/examples/csmap_insert.c b/misc/examples/csmap_insert.c index df638c22..c9f02891 100644 --- a/misc/examples/csmap_insert.c +++ b/misc/examples/csmap_insert.c @@ -29,7 +29,7 @@ void print_istr(csmap_istr map) { puts(""); } -int main() +int main(void) { // insert single values csmap_ii m1 = {0}; diff --git a/misc/examples/csset_erase.c b/misc/examples/csset_erase.c index 649bb1e3..9c7f5e1a 100644 --- a/misc/examples/csset_erase.c +++ b/misc/examples/csset_erase.c @@ -3,7 +3,7 @@ #define i_key int #include -int main() +int main(void) { csset_int set = c_init(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50}); diff --git a/misc/examples/cstr_match.c b/misc/examples/cstr_match.c index 10a843cf..be03e981 100644 --- a/misc/examples/cstr_match.c +++ b/misc/examples/cstr_match.c @@ -3,7 +3,7 @@ #include #include -int main() +int main(void) { cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"); diff --git a/misc/examples/demos.c b/misc/examples/demos.c index 2e91b20c..ecc89f2e 100644 --- a/misc/examples/demos.c +++ b/misc/examples/demos.c @@ -1,7 +1,7 @@ #define i_implement #include -void stringdemo1() +void stringdemo1(void) { cstr cs = cstr_lit("one-nine-three-seven-five"); printf("%s.\n", cstr_str(&cs)); @@ -32,7 +32,7 @@ void stringdemo1() #define i_tag ix #include -void vectordemo1() +void vectordemo1(void) { cvec_ix bignums = cvec_ix_with_capacity(100); cvec_ix_reserve(&bignums, 100); @@ -55,7 +55,7 @@ void vectordemo1() #define i_key_str #include -void vectordemo2() +void vectordemo2(void) { cvec_str names = {0}; cvec_str_emplace_back(&names, "Mary"); @@ -77,7 +77,7 @@ void vectordemo2() #define i_native_cmp #include -void listdemo1() +void listdemo1(void) { clist_ix nums = {0}, nums2 = {0}; for (int i = 0; i < 10; ++i) @@ -109,7 +109,7 @@ void listdemo1() #define i_tag i #include -void setdemo1() +void setdemo1(void) { cset_i nums = {0}; cset_i_insert(&nums, 8); @@ -125,7 +125,7 @@ void setdemo1() #define i_tag ii #include -void mapdemo1() +void mapdemo1(void) { cmap_ii nums = {0}; cmap_ii_insert(&nums, 8, 64); @@ -139,7 +139,7 @@ void mapdemo1() #define i_tag si #include -void mapdemo2() +void mapdemo2(void) { cmap_si nums = {0}; cmap_si_emplace_or_assign(&nums, "Hello", 64); @@ -161,7 +161,7 @@ void mapdemo2() #define i_val_str #include -void mapdemo3() +void mapdemo3(void) { cmap_str table = {0}; cmap_str_emplace(&table, "Map", "test"); @@ -181,7 +181,7 @@ void mapdemo3() cmap_str_drop(&table); // frees key and value cstrs, and hash table. } -int main() +int main(void) { printf("\nSTRINGDEMO1\n"); stringdemo1(); printf("\nVECTORDEMO1\n"); vectordemo1(); diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c index 61fe67fb..a5063a42 100644 --- a/misc/examples/dining_philosophers.c +++ b/misc/examples/dining_philosophers.c @@ -86,7 +86,7 @@ int dining(struct Dining* d) return 0; } -int main() +int main(void) { struct Dining dine; cco_reset(&dine); diff --git a/misc/examples/forloops.c b/misc/examples/forloops.c index 99b12871..47cced8f 100644 --- a/misc/examples/forloops.c +++ b/misc/examples/forloops.c @@ -11,7 +11,7 @@ #include -int main() +int main(void) { puts("c_forrange:"); c_forrange (30) printf(" xx"); diff --git a/misc/examples/functor.c b/misc/examples/functor.c index ea409a56..e3bde1dd 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -30,7 +30,7 @@ static bool int_less(const int* x, const int* y) { return *x < *y; } static bool int_greater(const int* x, const int* y) { return *x > *y; } static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); } -int main() +int main(void) { const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_arraylen(data); printf("data: \t"); diff --git a/misc/examples/gauss2.c b/misc/examples/gauss2.c index 67586181..1ab8ade5 100644 --- a/misc/examples/gauss2.c +++ b/misc/examples/gauss2.c @@ -10,7 +10,7 @@ #define i_val int #include -int main() +int main(void) { enum {N = 5000000}; uint64_t seed = (uint64_t)time(NULL); diff --git a/misc/examples/generator.c b/misc/examples/generator.c index 3ff7a645..a15f9ba5 100644 --- a/misc/examples/generator.c +++ b/misc/examples/generator.c @@ -42,7 +42,7 @@ Triple_iter Triple_begin(Triple* g) { } -int main() +int main(void) { puts("Pythagorean triples with c < 100:"); Triple triple = {.size=30}; // max number of triples diff --git a/misc/examples/intrusive.c b/misc/examples/intrusive.c index 1e3f7b83..4fca654b 100644 --- a/misc/examples/intrusive.c +++ b/misc/examples/intrusive.c @@ -14,7 +14,7 @@ void printList(List list) { puts(""); } -int main() { +int main(void) { List list = {0}; c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8}) List_push_back_node(&list, c_new(List_node, {0, *i.ref})); diff --git a/misc/examples/list.c b/misc/examples/list.c index a0045db9..fa33305a 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -8,7 +8,7 @@ #define i_native_cmp #include -int main() { +int main(void) { const int n = 3000000; DList list = {0}; diff --git a/misc/examples/list_erase.c b/misc/examples/list_erase.c index 357dd75b..211c5a5d 100644 --- a/misc/examples/list_erase.c +++ b/misc/examples/list_erase.c @@ -5,7 +5,7 @@ #define i_key int #include -int main () +int main(void) { IList L = c_init(IList, {10, 20, 30, 40, 50}); diff --git a/misc/examples/list_splice.c b/misc/examples/list_splice.c index 25c2a42d..f1fd6e1f 100644 --- a/misc/examples/list_splice.c +++ b/misc/examples/list_splice.c @@ -13,7 +13,7 @@ void print_ilist(const char* s, clist_i list) puts(""); } -int main () +int main(void) { clist_i list1 = c_init(clist_i, {1, 2, 3, 4, 5}); clist_i list2 = c_init(clist_i, {10, 20, 30, 40, 50}); diff --git a/misc/examples/lower_bound.c b/misc/examples/lower_bound.c index ee32f49b..e5d816e9 100644 --- a/misc/examples/lower_bound.c +++ b/misc/examples/lower_bound.c @@ -7,7 +7,7 @@ #define i_key int #include -int main() +int main(void) { // TEST SORTED VECTOR { diff --git a/misc/examples/mmap.c b/misc/examples/mmap.c index fd00499c..04a605a7 100644 --- a/misc/examples/mmap.c +++ b/misc/examples/mmap.c @@ -30,7 +30,7 @@ void insert(Multimap* mmap, int key, const char* str) clist_str_emplace_back(list, str); } -int main() +int main(void) { Multimap mmap = {0}; diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c index 45b97378..798a1126 100644 --- a/misc/examples/multidim.c +++ b/misc/examples/multidim.c @@ -6,7 +6,7 @@ using_cspan3(ispan, int); -int main() +int main(void) { cstack_int v = c_init(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}); diff --git a/misc/examples/multimap.c b/misc/examples/multimap.c index a89b251b..1068a5dc 100644 --- a/misc/examples/multimap.c +++ b/misc/examples/multimap.c @@ -66,7 +66,7 @@ void OlympicLoc_drop(OlympicLoc* self) { } -int main() +int main(void) { // Define the multimap with destructor defered to when block is completed. csmap_OL multimap = {0}; diff --git a/misc/examples/music_arc.c b/misc/examples/music_arc.c index 49008523..16111b0b 100644 --- a/misc/examples/music_arc.c +++ b/misc/examples/music_arc.c @@ -31,7 +31,7 @@ void Song_drop(Song* s) { #define i_keyboxed SongArc // use i_keyboxed on carc / cbox (instead of i_key) #include -void example3() +void example3(void) { SongVec vec1 = c_init(SongVec, { Song_make("Bob Dylan", "The Times They Are A Changing"), @@ -61,7 +61,7 @@ void example3() c_drop(SongVec, &vec1, &vec2); } -int main() +int main(void) { example3(); } diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index ee250b2b..9676e7b4 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -43,7 +43,7 @@ void MyStruct_drop(MyStruct* s) { } -int main() +int main(void) { MyStruct my = {0}; clist_i32_push_back(&my.intlist, 123); diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c index 277bcbc2..de990040 100644 --- a/misc/examples/new_map.c +++ b/misc/examples/new_map.c @@ -41,7 +41,7 @@ int point_cmp(const Point* a, const Point* b) { #include -int main() +int main(void) { cmap_pnt pmap = c_init(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}}); diff --git a/misc/examples/new_pque.c b/misc/examples/new_pque.c index 3df39e0e..16823bb6 100644 --- a/misc/examples/new_pque.c +++ b/misc/examples/new_pque.c @@ -8,7 +8,7 @@ typedef struct Point { int x, y; } Point; #include -int main() +int main(void) { PointQ pque = c_init(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}}); // print diff --git a/misc/examples/new_queue.c b/misc/examples/new_queue.c index 104871bf..f3592df6 100644 --- a/misc/examples/new_queue.c +++ b/misc/examples/new_queue.c @@ -20,7 +20,7 @@ int point_cmp(const Point* a, const Point* b) { #define i_key int #include -int main() { +int main(void) { int n = 50000000; crand_t rng = crand_init((uint64_t)time(NULL)); crand_unif_t dist = crand_unif_init(0, n); diff --git a/misc/examples/new_smap.c b/misc/examples/new_smap.c index 77c4cdce..ee946c9a 100644 --- a/misc/examples/new_smap.c +++ b/misc/examples/new_smap.c @@ -36,7 +36,7 @@ int point_cmp(const Point* a, const Point* b) { #include -int main() +int main(void) { PMap pmap = c_init(PMap, { {{42, 14}, 1}, diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c index 6d928cfc..88efd55a 100644 --- a/misc/examples/new_vec.c +++ b/misc/examples/new_vec.c @@ -23,7 +23,7 @@ typedef struct Point { int x, y; } Point; #define i_is_forward #include -int main() +int main(void) { MyStruct my = {0}; diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c index 3a759610..38c883a7 100644 --- a/misc/examples/person_arc.c +++ b/misc/examples/person_arc.c @@ -39,7 +39,7 @@ void Person_drop(Person* p) { #include -int main() +int main(void) { PSPtr p = PSPtr_from(Person_make("Laura", "Palmer")); PSPtr q = PSPtr_from(Person_clone(*p.get)); // deep copy diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c index 5084536a..cd3c5f4f 100644 --- a/misc/examples/printspan.c +++ b/misc/examples/printspan.c @@ -20,7 +20,7 @@ void printMe(intspan container) { puts(""); } -int main() +int main(void) { intspan sp1 = cspan_init(intspan, {1, 2}); printMe( sp1 ); diff --git a/misc/examples/priority.c b/misc/examples/priority.c index 148e8fc5..bf2e188a 100644 --- a/misc/examples/priority.c +++ b/misc/examples/priority.c @@ -8,7 +8,7 @@ #define i_tag i #include -int main() { +int main(void) { intptr_t N = 10000000; crand_t rng = crand_init((uint64_t)time(NULL)); crand_unif_t dist = crand_unif_init(0, N * 10); diff --git a/misc/examples/queue.c b/misc/examples/queue.c index 3154f115..56b5beb9 100644 --- a/misc/examples/queue.c +++ b/misc/examples/queue.c @@ -5,7 +5,7 @@ #define i_tag i #include -int main() { +int main(void) { int n = 100000000; crand_unif_t dist; crand_t rng = crand_init(1234); diff --git a/misc/examples/random.c b/misc/examples/random.c index e783fe55..b7c0f277 100644 --- a/misc/examples/random.c +++ b/misc/examples/random.c @@ -2,7 +2,7 @@ #include #include -int main() +int main(void) { const int N = 1000000000; const uint64_t seed = (uint64_t)time(NULL), range = 1000000; diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c index 9c394d8e..694ce12e 100644 --- a/misc/examples/rawptr_elements.c +++ b/misc/examples/rawptr_elements.c @@ -25,7 +25,7 @@ #define i_valboxed IBox // i_valboxed: use properties from IBox automatically #include -int main() +int main(void) { // These have the same behaviour, except IBox has a get member: SIPtrMap map1 = {0}; diff --git a/misc/examples/read.c b/misc/examples/read.c index c25cd740..b12f7409 100644 --- a/misc/examples/read.c +++ b/misc/examples/read.c @@ -15,7 +15,7 @@ cvec_str read_file(const char* name) return vec; } -int main() +int main(void) { int n = 0; c_with (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec)) diff --git a/misc/examples/regex2.c b/misc/examples/regex2.c index 734190cb..a798b1a1 100644 --- a/misc/examples/regex2.c +++ b/misc/examples/regex2.c @@ -1,7 +1,7 @@ #define i_import #include -int main() +int main(void) { struct { const char *pattern, *input; } s[] = { {"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])", diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c index 88d3747b..11426d2d 100644 --- a/misc/examples/regex_match.c +++ b/misc/examples/regex_match.c @@ -6,7 +6,7 @@ #define i_key float #include -int main() +int main(void) { // Lets find the first sequence of digits in a string const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour." diff --git a/misc/examples/regex_replace.c b/misc/examples/regex_replace.c index 76664b1b..f1ea2711 100644 --- a/misc/examples/regex_replace.c +++ b/misc/examples/regex_replace.c @@ -12,7 +12,7 @@ bool add_10_years(int i, csview match, cstr* out) { return false; } -int main() +int main(void) { const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b"; const char* input = "start date: 2015-12-31, end date: 2022-02-28"; diff --git a/misc/examples/replace.c b/misc/examples/replace.c index 9ac26c07..59a56bf7 100644 --- a/misc/examples/replace.c +++ b/misc/examples/replace.c @@ -1,7 +1,7 @@ #define i_implement #include -int main () +int main(void) { const char *base = "this is a test string."; const char *s2 = "n example"; diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index d812ff42..38defd0f 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -68,7 +68,7 @@ void Use(void) Scheduler_drop(&scheduler); } -int main() +int main(void) { Use(); } diff --git a/misc/examples/sidebyside.cpp b/misc/examples/sidebyside.cpp index a7c1008c..9414b691 100644 --- a/misc/examples/sidebyside.cpp +++ b/misc/examples/sidebyside.cpp @@ -13,7 +13,7 @@ #define i_val int #include -int main() { +int main(void) { { std::map hist; hist.emplace(12, 100).first->second += 1; diff --git a/misc/examples/sorted_map.c b/misc/examples/sorted_map.c index ff727632..89381554 100644 --- a/misc/examples/sorted_map.c +++ b/misc/examples/sorted_map.c @@ -5,7 +5,7 @@ #define i_val int #include -int main() +int main(void) { // empty map containers diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c index 32b5f17f..ef7ed174 100644 --- a/misc/examples/splitstr.c +++ b/misc/examples/splitstr.c @@ -4,7 +4,7 @@ #define i_implement #include -int main() +int main(void) { puts("Split with c_fortoken (csview):"); diff --git a/misc/examples/sso_map.c b/misc/examples/sso_map.c index b78dcb2e..4f84b651 100644 --- a/misc/examples/sso_map.c +++ b/misc/examples/sso_map.c @@ -4,7 +4,7 @@ #define i_val_str #include -int main() +int main(void) { cmap_str m = {0}; cmap_str_emplace(&m, "Test short", "This is a short string"); diff --git a/misc/examples/sso_substr.c b/misc/examples/sso_substr.c index 9b062eed..687658df 100644 --- a/misc/examples/sso_substr.c +++ b/misc/examples/sso_substr.c @@ -3,7 +3,7 @@ #define i_implement #include -int main () +int main(void) { cstr str = cstr_lit("We think in generalities, but we live in details."); csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" diff --git a/misc/examples/stack.c b/misc/examples/stack.c index 96bab24b..6297fb6f 100644 --- a/misc/examples/stack.c +++ b/misc/examples/stack.c @@ -10,7 +10,7 @@ #define i_key char #include -int main() { +int main(void) { cstack_i stack = {0}; cstack_c chars = {0}; diff --git a/misc/examples/sview_split.c b/misc/examples/sview_split.c index 782e4096..ac275da0 100644 --- a/misc/examples/sview_split.c +++ b/misc/examples/sview_split.c @@ -3,7 +3,7 @@ #define i_implement #include -int main() +int main(void) { // No memory allocations or string length calculations! const csview date = c_sv("2021/03/12"); diff --git a/misc/examples/triples.c b/misc/examples/triples.c index a8ca6b47..9f2fcc1e 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -52,7 +52,7 @@ int triples_coro(struct triples* t) { return 0; } -int main() +int main(void) { puts("Vanilla triples:"); triples_vanilla(5); diff --git a/misc/examples/unordered_set.c b/misc/examples/unordered_set.c index 14d69ce5..dd899d78 100644 --- a/misc/examples/unordered_set.c +++ b/misc/examples/unordered_set.c @@ -5,7 +5,7 @@ #define i_key_str #include -int main() +int main(void) { // declaring set for storing string data-type cset_str stringSet = {0}; diff --git a/misc/examples/utf8replace_c.c b/misc/examples/utf8replace_c.c index 17352fee..1d54486f 100644 --- a/misc/examples/utf8replace_c.c +++ b/misc/examples/utf8replace_c.c @@ -1,7 +1,7 @@ #define i_implement #include -int main() +int main(void) { cstr hello = cstr_lit("hell😀 w😀rld"); printf("%s\n", cstr_str(&hello)); diff --git a/misc/examples/vikings.c b/misc/examples/vikings.c index d9024052..d6125854 100644 --- a/misc/examples/vikings.c +++ b/misc/examples/vikings.c @@ -41,7 +41,7 @@ static inline RViking Viking_toraw(const Viking* vp) { #define i_val int // mapped type #include -int main() +int main(void) { Vikings vikings = {0}; Vikings_emplace(&vikings, c_LITERAL(RViking){"Einar", "Norway"}, 20); -- cgit v1.2.3 From 23eeedb3fc298602732f394adba6a43c876ca7d8 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 16 Jul 2023 09:07:01 +0200 Subject: Moved _cspan_next2() to header section in cspan.h to allow optimizations. --- include/stc/cspan.h | 22 ++++++++++------------ misc/benchmarks/various/cspan_bench.c | 18 +++++++++--------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 582e1004..dcb02961 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -114,7 +114,7 @@ using_cspan_tuple(5); using_cspan_tuple(6); using_cspan_tuple(7); using_cspan_tuple(8); #define c_END -1 -#define c_ALL 0,-1 +#define c_ALL 0,c_END /* Use cspan_init() for static initialization only. c_init() for non-static init. */ #define cspan_init(SpanType, ...) \ @@ -221,8 +221,16 @@ STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t s return off; } +STC_INLINE intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc) { + intptr_t off = stride[i]; + ++pos[i]; + for (; --rank && pos[i] == shape[i]; i += inc) { + pos[i] = 0; ++pos[i + inc]; + off += stride[i + inc] - stride[i]*shape[i]; + } + return off; +} #define _cspan_next1(pos, shape, stride, rank, i, inc) (++pos[0], stride[0]) -STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc); #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 @@ -254,16 +262,6 @@ STC_DEF int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank) { return shape; } -STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc) { - intptr_t off = stride[i]; - ++pos[i]; - for (; --rank && pos[i] == shape[i]; i += inc) { - pos[i] = 0; ++pos[i + inc]; - off += stride[i + inc] - stride[i]*shape[i]; - } - return off; -} - STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, const int32_t shape[], const int32_t stride[], int rank, const int32_t a[][2]) { diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c index e3997ff0..f4b067f8 100644 --- a/misc/benchmarks/various/cspan_bench.c +++ b/misc/benchmarks/various/cspan_bench.c @@ -13,7 +13,6 @@ enum { }; int lx = 15, ly = 10, lz = 5; int hx = 30, hy = 15, hz = 15; -intptr_t n = 100000; // define the contents of two nx x ny x nz arrays in and out double Vout[nx * ny * nz]; @@ -21,12 +20,12 @@ double Vin[nx * ny * nz]; //, 1.23; // define some slice indices for each dimension -static void MDRanges_setup(intptr_t state) +static void MDRanges_setup(intptr_t n) { double sum = 0; clock_t t = clock(); - for (intptr_t s = 0; s < state; ++s) + for (intptr_t s = 0; s < n; ++s) { MD3 r_in = cspan_md(Vin, nx, ny, nz); MD3 r_out = cspan_md(Vout, nx, ny, nz); @@ -41,12 +40,12 @@ static void MDRanges_setup(intptr_t state) printf("setup: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); } -static void TraditionalForLoop(intptr_t state) +static void TraditionalForLoop(intptr_t n) { clock_t t = clock(); double sum = 0; - for (int s = 0; s < state; ++s) { + for (int s = 0; s < n; ++s) { for (int x = lx; x < hx; ++x) { for (int y = ly; y < hy; ++y) { for (int z = lz; z < hz; ++z) { @@ -62,7 +61,7 @@ static void TraditionalForLoop(intptr_t state) printf("forloop: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); } -static void MDRanges_nested_loop(intptr_t state) +static void MDRanges_nested_loop(intptr_t n) { clock_t t = clock(); MD3 r_in = cspan_md(Vin, nx, ny, nz); @@ -73,7 +72,7 @@ static void MDRanges_nested_loop(intptr_t state) // C++23: for (auto [o, i] : std::views::zip(flat(r_out), flat(r_in))) { o = i; } double sum = 0; - for (intptr_t s = 0; s < state; ++s) { + for (intptr_t s = 0; s < n; ++s) { for (int x = 0; x < r_in.shape[0]; ++x) { for (int y = 0; y < r_in.shape[1]; ++y) { for (int z = 0; z < r_in.shape[2]; ++z) @@ -89,7 +88,7 @@ static void MDRanges_nested_loop(intptr_t state) printf("nested: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); } -static void MDRanges_loop_over_joined(intptr_t state) +static void MDRanges_loop_over_joined(intptr_t n) { MD3 r_in = cspan_md(Vin, nx, ny, nz); MD3 r_out = cspan_md(Vout, nx, ny, nz); @@ -100,7 +99,7 @@ static void MDRanges_loop_over_joined(intptr_t state) double sum = 0; clock_t t = clock(); - for (intptr_t s = 0; s < state; ++s) { + for (intptr_t s = 0; s < n; ++s) { MD3_iter i = MD3_begin(&r_in); MD3_iter o = MD3_begin(&r_out); @@ -116,6 +115,7 @@ static void MDRanges_loop_over_joined(intptr_t state) int main(void) { + intptr_t n = 100000; for (int i = 0; i < nx * ny * nz; ++i) Vin[i] = i + 1.23; -- cgit v1.2.3 From 313c1d7bb9b92e75801429c1f7f132589860292e Mon Sep 17 00:00:00 2001 From: tylov Date: Tue, 18 Jul 2023 01:36:51 +0200 Subject: Renamed i_native_cmp => i_cmp_native Added c_all_of(), c_any_of(), c_none_of() to algo/filter.h --- README.md | 4 ++-- docs/carc_api.md | 24 +++++++++++++-------- docs/cbox_api.md | 29 +++++++++++++++----------- docs/cdeq_api.md | 23 +++++++++++---------- docs/clist_api.md | 21 ++++++++++--------- docs/cmap_api.md | 39 +++++++++++++++++------------------ docs/cpque_api.md | 18 ++++++++-------- docs/cqueue_api.md | 16 +++++++------- docs/cset_api.md | 26 +++++++++++------------ docs/csmap_api.md | 36 ++++++++++++++++---------------- docs/csset_api.md | 18 ++++++++-------- docs/cstack_api.md | 16 +++++++------- docs/cvec_api.md | 23 +++++++++++---------- include/stc/algo/coroutine.h | 13 ++++++++---- include/stc/algo/filter.h | 16 +++++++++++++- include/stc/priv/template.h | 8 +++---- include/stc/priv/template2.h | 2 +- misc/benchmarks/various/csort_bench.c | 2 +- misc/examples/arc_demo.c | 2 +- misc/examples/arcvec_erase.c | 2 +- misc/examples/demos.c | 2 +- misc/examples/intrusive.c | 2 +- misc/examples/list.c | 2 +- misc/examples/lower_bound.c | 2 +- misc/examples/new_list.c | 2 +- misc/examples/new_sptr.c | 2 +- 26 files changed, 191 insertions(+), 159 deletions(-) diff --git a/README.md b/README.md index b7e06790..6bbe50ee 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ struct Point { float x, y; }; #include // cvec_pnt: vector of struct Point #define i_key int -#define i_native_cmp // enable sort/search. Use native `<` and `==` operators +#define i_cmp_native // enable sort/search. Use native `<` and `==` operators #include // clist_int: singly linked list #define i_key int @@ -619,7 +619,7 @@ STC is generally very memory efficient. Memory usage for the different container - cspan: Support for column-major (fortran order) multidim spans and transposed views. - Removed default comparison for clist, cvec and cdeq (as with cstack and cqueue). - Using i_key_str, i_keyclass, i_keyboxed still expects comparisons defined. - - Define i_native_cmp to enable built-in i_key types comparisons (<, ==). + - Define i_cmp_native to enable built-in i_key types comparisons (<, ==). - cstr and csview are now shared linked by default. Static linking by defining i_static. - New cdeq and cqueue implementation(s), using circular buffer. - Renamed i_extern => i_import. diff --git a/docs/carc_api.md b/docs/carc_api.md index 8b7b67a1..fb79019a 100644 --- a/docs/carc_api.md +++ b/docs/carc_api.md @@ -20,15 +20,21 @@ See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory ## Header file and declaration ```c -#define i_type // full typename of the carc -#define i_key // element type: REQUIRED - -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. -#define i_keyfrom // convertion func i_keyraw => i_key - -#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc. -#define i_tag // alternative typename: carc_{i_tag}. i_tag defaults to i_key +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // carc container type name +#define i_cmp // three-way compareison. REQUIRED IF i_key is a non-integral type + // Note that containers of carcs will "inherit" i_cmp + // when using carc in containers with i_valboxed MyArc - ie. the i_type. +#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_keydrop // destroy element func - defaults to empty destruct +#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. + +#define i_keyraw // convertion type (lookup): default to {i_key} +#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. +#define i_keyfrom // from-raw func. + +#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc. +#define i_tag // alternative typename: carc_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cbox_api.md b/docs/cbox_api.md index b6c76d2f..0e6fca64 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -14,18 +14,23 @@ See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory ## Header file and declaration ```c -#define i_type // full typename of the cbox -#define i_key // element type: REQUIRED -#define i_cmp // three-way compare two i_key* : REQUIRED IF i_key is a non-integral type -#define i_keydrop // destroy element func - defaults to empty destruct -#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. - -#define i_keyraw // convertion type (lookup): default to {i_key} -#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. -#define i_keyfrom // from-raw func. - -#define i_keyclass // alt. to i_key: REQUIRES that {i_key}_clone, {i_key}_drop, {i_keyraw}_cmp exist. -#define i_tag // alternative typename: cbox_{i_tag}. i_tag defaults to i_key +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // cbox container type name +#define i_cmp // three-way compareison. REQUIRED IF i_key is a non-integral type + // Note that containers of carcs will "inherit" i_cmp + // when using carc in containers with i_valboxed MyArc - ie. the i_type. +#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_keydrop // destroy element func - defaults to empty destruct +#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. + +#define i_keyraw // convertion type (lookup): default to {i_key} +#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. +#define i_keyfrom // from-raw func. + +#define i_tag // alternative typename: cbox_{i_tag}. i_tag defaults to i_key +#define i_keyclass // Use instead of i_key when functions {i_key}_clone, + // {i_key}_drop and {i_keyraw}_cmp exist. +#define i_keyboxed // Use instead of i_key when key is a carc- or a cbox-type. #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index c6de6cd6..38de7f66 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -10,17 +10,18 @@ See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque ## Header file and declaration ```c -#define i_type // full typename of the container -#define i_key // value: REQUIRED -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw - -#define i_tag // alternative typename: cdeq_{i_tag}. i_tag defaults to i_key +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // cdeq container type name +#define i_cmp // three-way compare of two i_keyraw*. +#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop is defined + +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw + +#define i_tag // alternative typename: cdeq_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/clist_api.md b/docs/clist_api.md index 3d785789..d8d614c2 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -22,16 +22,17 @@ See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list) ## Header file and declaration ```c -#define i_type // container type name (default: clist_{i_key}) -#define i_key // value: REQUIRED -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // convertion "raw" type (default: {i_key}) -#define i_keyto // convertion func i_key* => i_keyraw -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // clist container type name +#define i_cmp // three-way compare two i_keyraw* +#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined + +#define i_keyraw // convertion "raw" type (default: {i_key}) +#define i_keyto // convertion func i_key* => i_keyraw +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key #include ``` diff --git a/docs/cmap_api.md b/docs/cmap_api.md index eca350b4..17f27662 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -17,26 +17,25 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain ## Header file and declaration ```c -#define i_type // container type name (default: cmap_{i_key}) -#define i_key // hash key: REQUIRED -#define i_val // map value: REQUIRED -#define i_hash // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type -#define i_eq // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a - // non-integral type. Three-way i_cmp may alternatively be specified. -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw - -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined -#define i_valraw // convertion "raw" type - defaults to i_val -#define i_valfrom // convertion func i_valraw => i_val -#define i_valto // convertion func i_val* => i_valraw - -#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val -#define i_expandby // default 1. If 2, table expand 2x (else 1.5x) +#define i_key // key type: REQUIRED. +#define i_val // mapped value type: REQUIRED. +#define i_type // container type name (default: cmap_{i_key}) +#define i_hash // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type +#define i_eq // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a + // non-integral type. Three-way i_cmp may alternatively be specified. +#define i_keydrop // destroy key func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw + +#define i_valdrop // destroy value func - defaults to empty destruct +#define i_valclone // REQUIRED IF i_valdrop defined +#define i_valraw // convertion "raw" type - defaults to i_val +#define i_valfrom // convertion func i_valraw => i_val +#define i_valto // convertion func i_val* => i_valraw + +#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cpque_api.md b/docs/cpque_api.md index 5b63dfd1..4cde927b 100644 --- a/docs/cpque_api.md +++ b/docs/cpque_api.md @@ -8,17 +8,17 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai ## Header file and declaration ```c -#define i_type // define type name of the container (default cpque_{i_key}) -#define i_key // value: REQUIRED -#define i_less // compare two i_key* : REQUIRED IF i_key/i_keyraw is a non-integral type -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // cpque container type name +#define i_less // compare two i_key* : REQUIRED IF i_key/i_keyraw is a non-integral type +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // convertion type -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw. +#define i_keyraw // convertion type +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw. -#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key +#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md index b324e5fc..1834baf9 100644 --- a/docs/cqueue_api.md +++ b/docs/cqueue_api.md @@ -7,16 +7,16 @@ See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue ## Header file and declaration ```c -#define i_type // container type name (default: cqueue_{i_key}) -#define i_key // value: REQUIRED -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // cqueue container type name +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw -#define i_tag // alternative typename: cqueue_{i_tag}. i_tag defaults to i_key +#define i_tag // alternative typename: cqueue_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cset_api.md b/docs/cset_api.md index e894ad4f..928d63a8 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -7,19 +7,19 @@ A **cset** is an associative container that contains a set of unique objects of ## Header file and declaration ```c -#define i_type // container type name (default: cset_{i_key}) -#define i_key // hash key: REQUIRED. -#define i_hash // hash func: REQUIRED IF i_keyraw is a non-pod type. -#define i_eq // equality comparison two i_keyraw*: !i_cmp is used if not defined. -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy -#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy - -#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_key -#define i_expandby // default 1. If 2, table expand 2x (else 1.5x) +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // container type name +#define i_hash // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type +#define i_eq // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a + // non-integral type. Three-way i_cmp may alternatively be specified. +#define i_keydrop // destroy key func: defaults to empty destruct +#define i_keyclone // clone func: REQUIRED IF i_keydrop defined + +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy +#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy + +#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 099d7dfc..afaf49f3 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -15,24 +15,24 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo ## Header file and declaration ```c -#define i_type // container type name (default: cmap_{i_key}) -#define i_key // key: REQUIRED -#define i_val // value: REQUIRED -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type - -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_valdrop defined -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw - -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined -#define i_valraw // convertion "raw" type - defaults to i_val -#define i_valfrom // convertion func i_valraw => i_val -#define i_valto // convertion func i_val* => i_valraw - -#define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val +#define i_key // key type: REQUIRED. +#define i_val // mapped value type: REQUIRED. +#define i_type // container type name (default: cmap_{i_key}) +#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type + +#define i_keydrop // destroy key func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_valdrop defined +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw + +#define i_valdrop // destroy value func - defaults to empty destruct +#define i_valclone // REQUIRED IF i_valdrop defined +#define i_valraw // convertion "raw" type - defaults to i_val +#define i_valfrom // convertion func i_valraw => i_val +#define i_valto // convertion func i_val* => i_valraw + +#define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/csset_api.md b/docs/csset_api.md index aef3af3c..21e38f61 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -8,17 +8,17 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo ## Header file and declaration ```c -#define i_type // full typename of the container -#define i_key // key: REQUIRED -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // container type name +#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type +#define i_keydrop // destroy key func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy -#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy +#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy -#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_key +#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cstack_api.md b/docs/cstack_api.md index e799b152..fb629392 100644 --- a/docs/cstack_api.md +++ b/docs/cstack_api.md @@ -8,16 +8,16 @@ See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack ## Header file and declaration ```c -#define i_type // full typename of the container -#define i_key // value: REQUIRED -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // container type name +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw -#define i_tag // alternative typename: cstack_{i_tag}. i_tag defaults to i_key +#define i_tag // alternative typename: cstack_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cvec_api.md b/docs/cvec_api.md index d38ef23f..9cba74b5 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -12,17 +12,18 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect ## Header file and declaration ```c -#define i_type // full typename of the container -#define i_key // value: REQUIRED -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw - -#define i_tag // alternative typename: cvec_{i_tag}. i_tag defaults to i_key +#define i_type // container type name +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_cmp // three-way compare two i_keyraw* +#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined + +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw + +#define i_tag // alternative typename: cvec_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 3a5382f3..e4c0915c 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -178,17 +178,22 @@ typedef struct { intptr_t count; } cco_sem; #ifdef _WIN32 #ifdef __cplusplus - #define _c_LINKC extern "C" __declspec(dllimport) + #define _c_LINKC extern "C" __declspec(dllimport) #else - #define _c_LINKC __declspec(dllimport) + #define _c_LINKC __declspec(dllimport) + #endif + #if _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__ + #define _c_getsystime GetSystemTimeAsFileTime + #else + #define _c_getsystime GetSystemTimePreciseAsFileTime #endif struct _FILETIME; - _c_LINKC void GetSystemTimePreciseAsFileTime(struct _FILETIME*); + _c_LINKC void _c_getsystime(struct _FILETIME*); _c_LINKC void Sleep(unsigned long); static inline double cco_time(void) { /* seconds since epoch */ unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */ - GetSystemTimePreciseAsFileTime((struct _FILETIME*)&quad); + _c_getsystime((struct _FILETIME*)&quad); return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */ } diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index 4a227927..1a62c3e1 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -85,6 +85,21 @@ int main(void) if (it.ref == _endref) it.ref = NULL; \ } while (0) +#define c_all_of(boolptr, it, C, cnt, pred) do { \ + C##_iter it; \ + c_find_if_4(it, C, cnt, !(pred)); \ + *(boolptr) = it.ref == NULL; \ +} while (0) +#define c_any_of(boolptr, it, C, cnt, pred) do { \ + C##_iter it; \ + c_find_if_4(it, C, cnt, pred); \ + *(boolptr) = it.ref != NULL; \ +} while (0) +#define c_none_of(boolptr, it, C, cnt, pred) do { \ + C##_iter it; \ + c_find_if_4(it, C, cnt, pred); \ + *(boolptr) = it.ref == NULL; \ +} while (0) // Use with: clist, cmap, cset, csmap, csset: #define c_erase_if(it, C, cnt, pred) do { \ @@ -95,7 +110,6 @@ int main(void) } \ } while (0) - // Use with: cstack, cvec, cdeq, cqueue: #define c_eraseremove_if(it, C, cnt, pred) do { \ C* _cnt = &cnt; \ diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 30ed5732..ccdce718 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -103,7 +103,7 @@ #define i_no_emplace #endif #if c_option(c_native_cmp) - #define i_native_cmp + #define i_cmp_native #endif #if c_option(c_no_clone) || defined _i_carc #define i_no_clone @@ -203,10 +203,10 @@ #endif #ifndef i_no_cmp - #if defined i_cmp || defined i_less || defined i_native_cmp + #if defined i_cmp || defined i_less || defined i_cmp_native #define _i_has_cmp #endif - #if defined i_eq || defined i_native_cmp + #if defined i_eq || defined i_cmp_native #define _i_has_eq #endif @@ -228,7 +228,7 @@ #endif #endif -#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_native_cmp) +#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_cmp_native) #define i_hash c_default_hash #endif diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index def5d01e..351defde 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -67,7 +67,7 @@ #undef i_realloc #undef i_free -#undef i_native_cmp +#undef i_cmp_native #undef i_no_cmp #undef i_no_hash #undef i_no_clone diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c index f6b7f1db..793a0503 100644 --- a/misc/benchmarks/various/csort_bench.c +++ b/misc/benchmarks/various/csort_bench.c @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) { Ints a = Ints_with_capacity(size); for (i = 0; i < size; i++) - *Ints_push(&a, romutrio(s) & (1U << 30) - 1); + Ints_push(&a, romutrio(s) & (1U << 30) - 1); testsort(&a, size, "random"); for (i = 0; i < 20; i++) printf(" %d", (int)*Ints_at(&a, i)); diff --git a/misc/examples/arc_demo.c b/misc/examples/arc_demo.c index 87d64e67..929a48a1 100644 --- a/misc/examples/arc_demo.c +++ b/misc/examples/arc_demo.c @@ -11,7 +11,7 @@ void int_drop(int* x) { #define i_type Arc // set type name to be defined (instead of 'carc_int') #define i_key int #define i_keydrop int_drop // optional, just to display the elements destroyed -#define i_native_cmp // use int comparison (x < y, x == y). +#define i_cmp_native // use int comparison (x < y, x == y). #include // Arc #define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements diff --git a/misc/examples/arcvec_erase.c b/misc/examples/arcvec_erase.c index addef8b7..ba54c1c7 100644 --- a/misc/examples/arcvec_erase.c +++ b/misc/examples/arcvec_erase.c @@ -5,7 +5,7 @@ void show_drop(int* x) { printf("drop: %d\n", *x); } #define i_type Arc #define i_key int #define i_keydrop show_drop -#define i_native_cmp // enable sort/search for int type +#define i_cmp_native // enable sort/search for int type #include // Shared pointer to int #define i_type Vec diff --git a/misc/examples/demos.c b/misc/examples/demos.c index ecc89f2e..1a604d9f 100644 --- a/misc/examples/demos.c +++ b/misc/examples/demos.c @@ -74,7 +74,7 @@ void vectordemo2(void) #define i_key int #define i_tag ix -#define i_native_cmp +#define i_cmp_native #include void listdemo1(void) diff --git a/misc/examples/intrusive.c b/misc/examples/intrusive.c index 4fca654b..c22ed260 100644 --- a/misc/examples/intrusive.c +++ b/misc/examples/intrusive.c @@ -4,7 +4,7 @@ #define i_type List #define i_key int -#define i_native_cmp +#define i_cmp_native #include void printList(List list) { diff --git a/misc/examples/list.c b/misc/examples/list.c index fa33305a..ad8bebb8 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -5,7 +5,7 @@ #define i_type DList #define i_key double -#define i_native_cmp +#define i_cmp_native #include int main(void) { diff --git a/misc/examples/lower_bound.c b/misc/examples/lower_bound.c index e5d816e9..bea828f2 100644 --- a/misc/examples/lower_bound.c +++ b/misc/examples/lower_bound.c @@ -1,7 +1,7 @@ #include #define i_key int -#define i_native_cmp +#define i_cmp_native #include #define i_key int diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index 9676e7b4..2112bf1f 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -27,7 +27,7 @@ int point_cmp(const Point* a, const Point* b) { #include #define i_key float -#define i_native_cmp // use < and == operators for comparison +#define i_cmp_native // use < and == operators for comparison #include void MyStruct_drop(MyStruct* s); diff --git a/misc/examples/new_sptr.c b/misc/examples/new_sptr.c index 7fef5d1f..3c6fa16c 100644 --- a/misc/examples/new_sptr.c +++ b/misc/examples/new_sptr.c @@ -15,7 +15,7 @@ uint64_t Person_hash(const Person* p); #define i_type IPtr #define i_key int #define i_keydrop(x) printf("drop: %d\n", *x) -#define i_native_cmp +#define i_cmp_native #include #define i_type IPStack -- cgit v1.2.3 From 177418232a2d8a8b0df1667d3e4bd15dc37db59f Mon Sep 17 00:00:00 2001 From: tylov Date: Tue, 18 Jul 2023 02:50:44 +0200 Subject: Final merge fixes. --- misc/examples/prime.c | 2 +- misc/examples/random.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/examples/prime.c b/misc/examples/prime.c index c3db707d..e7b3d993 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -32,7 +32,7 @@ int main(void) llong n = 100000000; printf("Computing prime numbers up to %lld\n", n); - clock_t t = clock(); + clock_t t1 = clock(); cbits primes = sieveOfEratosthenes(n + 1); llong np = cbits_count(&primes); diff --git a/misc/examples/random.c b/misc/examples/random.c index 63c5a306..a36b2389 100644 --- a/misc/examples/random.c +++ b/misc/examples/random.c @@ -4,7 +4,7 @@ int main(void) { - const size_t N = 10000000; + const int N = 10000000; const uint64_t seed = (uint64_t)time(NULL), range = 1000000; crand_t rng = crand_init(seed); -- cgit v1.2.3 From 224a04f7fa7549ed94d2a1415eb25829e39a7cca Mon Sep 17 00:00:00 2001 From: tylov Date: Thu, 20 Jul 2023 14:42:00 +0200 Subject: Added Task-object to coroutines and true stackless execution. --- docs/ccommon_api.md | 5 ++++- docs/cspan_api.md | 14 ++++++------- include/stc/algo/coroutine.h | 50 ++++++++++++++++++++++++++++++-------------- include/stc/cspan.h | 12 +++++------ include/stc/cstr.h | 34 +++++++++++++++--------------- 5 files changed, 68 insertions(+), 47 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index e053f743..1e1ae1aa 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -390,7 +390,10 @@ cco_routine scope; Use `if-else-if` constructs instead. | | `cco_await_v(condition, ret);` | Suspend until condition is true (return ret)| | | `cco_await_on(cocall);` | Await on sub-coroutine to finish (return its ret) | | | `cco_return;` | Return from coroutine (inside cco_routine) | -| | `cco_closure(Closure, ...);` | Define a coroutine closure struct (optional) | +| | Task objects: | | +| | `cco_task_struct(Name, ...);` | Define a coroutine task struct | +| | `cco_await_task(task, ...);` | Await for task to finish or optionally yield a value | +| | `cco_block_task(task);` | Run blocking until task is finished (stackless) | | | Semaphores: | | | | `cco_sem` | Semaphore type | | `cco_sem` | `cco_sem_from(long value)` | Create semaphore | diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 09821450..e1c92bbf 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -26,14 +26,14 @@ i.e., it may be expanded multiple times. However, all index arguments are safe, `cspan_at(&ms3, i++, j++, k++)` is allowed. If the number of arguments does not match the span rank, a compile error is issued. Runtime bounds checks are enabled by default (define `STC_NDEBUG` or `NDEBUG` to disable). ```c -SpanType cspan_init(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values -SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from compatible STC container -SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from C array - +SpanType cspan_init(TYPE SpanType, {v1, v2, ...}); // make a 1-d cspan from values +SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from a cvec, cstack, cpque (heap) +SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from a C array + intptr_t cspan_size(const SpanTypeN* self); // return number of elements intptr_t cspan_rank(const SpanTypeN* self); // dimensions; compile time constant intptr_t cspan_index(const SpanTypeN* self, intptr_t x, ..); // index of element - + ValueType* cspan_at(const SpanTypeN* self, intptr_t x, ...); // #args must match input span rank ValueType* cspan_front(const SpanTypeN* self); ValueType* cspan_back(const SpanTypeN* self); @@ -55,13 +55,13 @@ SpanType2 cspan_subspan2(const SpanType2* span, intptr_t offset, intptr_t SpanType3 cspan_subspan3(const SpanType3* span, intptr_t offset, intptr_t count); // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); -OutSpan1 cspan_submd2(const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span. +OutSpan cspan_submd2(const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span. OutSpanN cspan_submd3(const SpanType3* parent, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span. OutSpanN cspan_submd4(const SpanType4* parent, intptr_t x, ...); // number of args decides rank of output span. // general slicing of an md span. // {i}: reduce rank. {i,c_END}: slice to end. {c_ALL}: use full extent. -OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeN* parent, {x0,x1}, {y0,y1}.., {N0,N1}); +OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeM* parent, {x0,x1}, {y0,y1}.., {N0,N1}); ``` ## TypesPd | Type name | Type definition / usage | Used to represent... | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index e4c0915c..7c6989c3 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -64,9 +64,8 @@ enum { }; typedef enum { CCO_DONE = 0, - CCO_YIELD = 1, - CCO_AWAIT = 2, - CCO_ERROR = -1, + CCO_AWAIT = 1<<0, + CCO_YIELD = 1<<1, } cco_result; #define cco_initial(co) ((co)->cco_state == 0) @@ -132,26 +131,45 @@ typedef enum { (void)((co)->cco_state = 0) /* - * Closure (optional) + * Tasks (optional) */ -#define cco_closure(Name, ...) \ +struct cco_runtime; + +#define cco_task_struct(Name, ...) \ struct Name { \ - int (*cco_fn)(struct Name*); \ - int cco_state; \ + int (*cco_fn)(struct Name*, struct cco_runtime*); \ + int cco_state, cco_expect; \ __VA_ARGS__ \ } -typedef struct cco_base { - int (*cco_fn)(struct cco_base*); - int cco_state; -} cco_base; +typedef cco_task_struct(cco_task, /**/) cco_task; + +typedef struct cco_runtime { + int result, top; + cco_task* stack[]; +} cco_runtime; + +#define cco_cast_task(task) \ + ((cco_task *)(task) + 0*sizeof((task)->cco_fn(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) -#define cco_resume(closure) \ - (closure)->cco_fn(closure) +#define cco_resume(task, rt) \ + (task)->cco_fn(task, rt) -#define cco_cast(closure) \ - ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state))) +#define cco_block_task(...) c_MACRO_OVERLOAD(cco_block_task, __VA_ARGS__) +#define cco_block_task_1(task) cco_block_task_3(task, rt, 16) +#define cco_block_task_3(task, rt, STACKDEPTH) \ + for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ + (((rt.result = cco_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) + +#define cco_await_task(...) c_MACRO_OVERLOAD(cco_await_task, __VA_ARGS__) +#define cco_await_task_2(task, rt) cco_await_task_3(task, rt, CCO_DONE) +#define cco_await_task_3(task, rt, resultbits) \ + do { \ + cco_runtime* _rt = rt; \ + (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = ~(resultbits); \ + cco_yield_v(CCO_AWAIT); \ + } while (0) /* * Semaphore @@ -182,7 +200,7 @@ typedef struct { intptr_t count; } cco_sem; #else #define _c_LINKC __declspec(dllimport) #endif - #if _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__ + #if 1 // _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__ #define _c_getsystime GetSystemTimeAsFileTime #else #define _c_getsystime GetSystemTimePreciseAsFileTime diff --git a/include/stc/cspan.h b/include/stc/cspan.h index dcb02961..08045010 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -80,19 +80,19 @@ int demo2() { STC_INLINE Self Self##_from_n(Self##_raw* raw, const intptr_t n) { \ return (Self){.data=raw, .shape={(int32_t)n}}; \ } \ - STC_INLINE Self Self##_slice_(Self##_value* v, const int32_t shape[], const int32_t stri[], \ + STC_INLINE Self Self##_slice_(Self##_value* d, const int32_t shape[], const int32_t stri[], \ const int rank, const int32_t a[][2]) { \ - Self s; s.data = v; int outrank; \ - s.data += _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ + Self s; int outrank; \ + s.data = d + _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ c_assert(outrank == RANK); \ return s; \ } \ STC_INLINE Self##_iter Self##_begin(const Self* self) { \ - Self##_iter it = {.ref=self->data, .pos={0}, ._s=self}; \ + Self##_iter it = {.ref=self->data, ._s=self}; \ return it; \ } \ STC_INLINE Self##_iter Self##_end(const Self* self) { \ - Self##_iter it = {.ref=NULL}; \ + Self##_iter it = {0}; \ return it; \ } \ STC_INLINE void Self##_next(Self##_iter* it) { \ @@ -120,7 +120,7 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define cspan_init(SpanType, ...) \ {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}, .stride={.d={1}}} -/* create a cspan from a cvec, cstack, cdeq, cqueue, or cpque (heap) */ +/* create a cspan from a cvec, cstack, or cpque (heap) */ #define cspan_from(container) \ {.data=(container)->data, .shape={(int32_t)(container)->_len}, .stride={.d={1}}} diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 17943ad5..2648e267 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -170,14 +170,14 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self) // utf8 methods defined in/depending on src/utf8code.c: -STC_API cstr cstr_casefold_sv(csview sv); -STC_API cstr cstr_tolower_sv(csview sv); -STC_API cstr cstr_toupper_sv(csview sv); -STC_API cstr cstr_tolower(const char* str); -STC_API cstr cstr_toupper(const char* str); -STC_API void cstr_lowercase(cstr* self); -STC_API void cstr_uppercase(cstr* self); -STC_API bool cstr_valid_utf8(const cstr* self); +extern cstr cstr_casefold_sv(csview sv); +extern cstr cstr_tolower_sv(csview sv); +extern cstr cstr_toupper_sv(csview sv); +extern cstr cstr_tolower(const char* str); +extern cstr cstr_toupper(const char* str); +extern void cstr_lowercase(cstr* self); +extern void cstr_uppercase(cstr* self); +extern bool cstr_valid_utf8(const cstr* self); // other utf8 @@ -394,7 +394,7 @@ fn_tocase[] = {{tolower, utf8_casefold}, {tolower, utf8_tolower}, {toupper, utf8_toupper}}; -STC_DEF cstr cstr_tocase(csview sv, int k) { +static cstr cstr_tocase(csview sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); const char *end = sv.str + sv.size; @@ -415,28 +415,28 @@ STC_DEF cstr cstr_tocase(csview sv, int k) { return out; } -STC_DEF cstr cstr_casefold_sv(csview sv) +cstr cstr_casefold_sv(csview sv) { return cstr_tocase(sv, 0); } -STC_DEF cstr cstr_tolower_sv(csview sv) +cstr cstr_tolower_sv(csview sv) { return cstr_tocase(sv, 1); } -STC_DEF cstr cstr_toupper_sv(csview sv) +cstr cstr_toupper_sv(csview sv) { return cstr_tocase(sv, 2); } -STC_DEF cstr cstr_tolower(const char* str) +cstr cstr_tolower(const char* str) { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } -STC_DEF cstr cstr_toupper(const char* str) +cstr cstr_toupper(const char* str) { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } -STC_DEF void cstr_lowercase(cstr* self) +void cstr_lowercase(cstr* self) { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } -STC_DEF void cstr_uppercase(cstr* self) +void cstr_uppercase(cstr* self) { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } -STC_DEF bool cstr_valid_utf8(const cstr* self) +bool cstr_valid_utf8(const cstr* self) { return utf8_valid(cstr_str(self)); } #endif // i_import -- cgit v1.2.3 From 900295256d825fc323149cd223c49787f32a3696 Mon Sep 17 00:00:00 2001 From: tylov Date: Thu, 20 Jul 2023 15:09:10 +0200 Subject: Moved examples to sub-directories. Added cotask1.c cotask2.c examples. --- misc/examples/algorithms/forfilter.c | 149 +++++++++++++++++ misc/examples/algorithms/forloops.c | 69 ++++++++ misc/examples/algorithms/random.c | 45 ++++++ misc/examples/algorithms/shape.c | 158 ++++++++++++++++++ misc/examples/algorithms/shape.cpp | 122 ++++++++++++++ misc/examples/arc_containers.c | 81 ---------- misc/examples/arc_demo.c | 62 -------- misc/examples/arcvec_erase.c | 50 ------ misc/examples/astar.c | 174 -------------------- misc/examples/birthday.c | 68 -------- misc/examples/bits.c | 66 -------- misc/examples/bits2.c | 41 ----- misc/examples/bitsets/bits.c | 66 ++++++++ misc/examples/bitsets/bits2.c | 41 +++++ misc/examples/bitsets/prime.c | 56 +++++++ misc/examples/books.c | 62 -------- misc/examples/box.c | 69 -------- misc/examples/box2.c | 82 ---------- misc/examples/cointerleave.c | 62 -------- misc/examples/complex.c | 49 ------ misc/examples/convert.c | 57 ------- misc/examples/coread.c | 41 ----- misc/examples/coroutines.c | 112 ------------- misc/examples/coroutines/cointerleave.c | 62 ++++++++ misc/examples/coroutines/coread.c | 41 +++++ misc/examples/coroutines/coroutines.c | 112 +++++++++++++ misc/examples/coroutines/cotasks1.c | 100 ++++++++++++ misc/examples/coroutines/cotasks2.c | 103 ++++++++++++ misc/examples/coroutines/dining_philosophers.c | 105 ++++++++++++ misc/examples/coroutines/generator.c | 55 +++++++ misc/examples/coroutines/scheduler.c | 74 +++++++++ misc/examples/coroutines/triples.c | 72 +++++++++ misc/examples/csmap_erase.c | 82 ---------- misc/examples/csmap_find.c | 73 --------- misc/examples/csmap_insert.c | 108 ------------- misc/examples/csset_erase.c | 41 ----- misc/examples/cstr_match.c | 26 --- misc/examples/demos.c | 194 ----------------------- misc/examples/dining_philosophers.c | 105 ------------ misc/examples/forfilter.c | 149 ----------------- misc/examples/forloops.c | 69 -------- misc/examples/functor.c | 57 ------- misc/examples/gauss2.c | 45 ------ misc/examples/generator.c | 55 ------- misc/examples/hashmap.c | 50 ------ misc/examples/hashmaps/birthday.c | 68 ++++++++ misc/examples/hashmaps/books.c | 62 ++++++++ misc/examples/hashmaps/hashmap.c | 50 ++++++ misc/examples/hashmaps/new_map.c | 75 +++++++++ misc/examples/hashmaps/phonebook.c | 72 +++++++++ misc/examples/hashmaps/unordered_set.c | 45 ++++++ misc/examples/hashmaps/vikings.c | 59 +++++++ misc/examples/inits.c | 108 ------------- misc/examples/intrusive.c | 33 ---- misc/examples/linkedlists/intrusive.c | 33 ++++ misc/examples/linkedlists/list.c | 64 ++++++++ misc/examples/linkedlists/list_erase.c | 30 ++++ misc/examples/linkedlists/list_splice.c | 38 +++++ misc/examples/linkedlists/new_list.c | 70 ++++++++ misc/examples/list.c | 64 -------- misc/examples/list_erase.c | 30 ---- misc/examples/list_splice.c | 38 ----- misc/examples/lower_bound.c | 66 -------- misc/examples/make.sh | 18 ++- misc/examples/mapmap.c | 64 -------- misc/examples/mixed/astar.c | 174 ++++++++++++++++++++ misc/examples/mixed/complex.c | 49 ++++++ misc/examples/mixed/convert.c | 57 +++++++ misc/examples/mixed/demos.c | 194 +++++++++++++++++++++++ misc/examples/mixed/inits.c | 108 +++++++++++++ misc/examples/mixed/read.c | 27 ++++ misc/examples/mmap.c | 65 -------- misc/examples/multidim.c | 67 -------- misc/examples/multimap.c | 102 ------------ misc/examples/music_arc.c | 67 -------- misc/examples/new_list.c | 70 -------- misc/examples/new_map.c | 75 --------- misc/examples/new_pque.c | 22 --- misc/examples/new_queue.c | 47 ------ misc/examples/new_smap.c | 67 -------- misc/examples/new_sptr.c | 75 --------- misc/examples/new_vec.c | 43 ----- misc/examples/person_arc.c | 77 --------- misc/examples/phonebook.c | 72 --------- misc/examples/prime.c | 56 ------- misc/examples/printspan.c | 52 ------ misc/examples/priority.c | 37 ----- misc/examples/priorityqueues/functor.c | 57 +++++++ misc/examples/priorityqueues/new_pque.c | 22 +++ misc/examples/priorityqueues/priority.c | 37 +++++ misc/examples/queue.c | 32 ---- misc/examples/queues/new_queue.c | 47 ++++++ misc/examples/queues/queue.c | 32 ++++ misc/examples/random.c | 45 ------ misc/examples/rawptr_elements.c | 59 ------- misc/examples/read.c | 27 ---- misc/examples/regex1.c | 32 ---- misc/examples/regex2.c | 34 ---- misc/examples/regex_match.c | 37 ----- misc/examples/regex_replace.c | 57 ------- misc/examples/regularexpressions/regex1.c | 32 ++++ misc/examples/regularexpressions/regex2.c | 34 ++++ misc/examples/regularexpressions/regex_match.c | 37 +++++ misc/examples/regularexpressions/regex_replace.c | 57 +++++++ misc/examples/replace.c | 36 ----- misc/examples/scheduler.c | 74 --------- misc/examples/shape.c | 158 ------------------ misc/examples/shape.cpp | 122 -------------- misc/examples/sidebyside.cpp | 57 ------- misc/examples/smartpointers/arc_containers.c | 81 ++++++++++ misc/examples/smartpointers/arc_demo.c | 62 ++++++++ misc/examples/smartpointers/arcvec_erase.c | 50 ++++++ misc/examples/smartpointers/box.c | 69 ++++++++ misc/examples/smartpointers/box2.c | 82 ++++++++++ misc/examples/smartpointers/music_arc.c | 67 ++++++++ misc/examples/smartpointers/new_sptr.c | 75 +++++++++ misc/examples/smartpointers/person_arc.c | 77 +++++++++ misc/examples/smartpointers/rawptr_elements.c | 59 +++++++ misc/examples/sorted_map.c | 67 -------- misc/examples/sortedmaps/csmap_erase.c | 82 ++++++++++ misc/examples/sortedmaps/csmap_find.c | 73 +++++++++ misc/examples/sortedmaps/csmap_insert.c | 108 +++++++++++++ misc/examples/sortedmaps/csset_erase.c | 41 +++++ misc/examples/sortedmaps/gauss2.c | 45 ++++++ misc/examples/sortedmaps/listmap.c | 65 ++++++++ misc/examples/sortedmaps/mapmap.c | 64 ++++++++ misc/examples/sortedmaps/multimap.c | 102 ++++++++++++ misc/examples/sortedmaps/new_smap.c | 67 ++++++++ misc/examples/sortedmaps/sorted_map.c | 67 ++++++++ misc/examples/spans/multidim.c | 67 ++++++++ misc/examples/spans/printspan.c | 52 ++++++ misc/examples/splitstr.c | 21 --- misc/examples/sso_map.c | 19 --- misc/examples/sso_substr.c | 21 --- misc/examples/stack.c | 32 ---- misc/examples/strings/cstr_match.c | 26 +++ misc/examples/strings/replace.c | 36 +++++ misc/examples/strings/splitstr.c | 21 +++ misc/examples/strings/sso_map.c | 19 +++ misc/examples/strings/sso_substr.c | 21 +++ misc/examples/strings/sview_split.c | 20 +++ misc/examples/strings/utf8replace_c.c | 25 +++ misc/examples/strings/utf8replace_rs.rs | 22 +++ misc/examples/sview_split.c | 20 --- misc/examples/triples.c | 72 --------- misc/examples/unordered_set.c | 45 ------ misc/examples/utf8replace_c.c | 25 --- misc/examples/utf8replace_rs.rs | 22 --- misc/examples/vectors/lower_bound.c | 66 ++++++++ misc/examples/vectors/new_vec.c | 43 +++++ misc/examples/vectors/stack.c | 32 ++++ misc/examples/vikings.c | 59 ------- 152 files changed, 4856 insertions(+), 4708 deletions(-) create mode 100644 misc/examples/algorithms/forfilter.c create mode 100644 misc/examples/algorithms/forloops.c create mode 100644 misc/examples/algorithms/random.c create mode 100644 misc/examples/algorithms/shape.c create mode 100644 misc/examples/algorithms/shape.cpp delete mode 100644 misc/examples/arc_containers.c delete mode 100644 misc/examples/arc_demo.c delete mode 100644 misc/examples/arcvec_erase.c delete mode 100644 misc/examples/astar.c delete mode 100644 misc/examples/birthday.c delete mode 100644 misc/examples/bits.c delete mode 100644 misc/examples/bits2.c create mode 100644 misc/examples/bitsets/bits.c create mode 100644 misc/examples/bitsets/bits2.c create mode 100644 misc/examples/bitsets/prime.c delete mode 100644 misc/examples/books.c delete mode 100644 misc/examples/box.c delete mode 100644 misc/examples/box2.c delete mode 100644 misc/examples/cointerleave.c delete mode 100644 misc/examples/complex.c delete mode 100644 misc/examples/convert.c delete mode 100644 misc/examples/coread.c delete mode 100644 misc/examples/coroutines.c create mode 100644 misc/examples/coroutines/cointerleave.c create mode 100644 misc/examples/coroutines/coread.c create mode 100644 misc/examples/coroutines/coroutines.c create mode 100644 misc/examples/coroutines/cotasks1.c create mode 100644 misc/examples/coroutines/cotasks2.c create mode 100644 misc/examples/coroutines/dining_philosophers.c create mode 100644 misc/examples/coroutines/generator.c create mode 100644 misc/examples/coroutines/scheduler.c create mode 100644 misc/examples/coroutines/triples.c delete mode 100644 misc/examples/csmap_erase.c delete mode 100644 misc/examples/csmap_find.c delete mode 100644 misc/examples/csmap_insert.c delete mode 100644 misc/examples/csset_erase.c delete mode 100644 misc/examples/cstr_match.c delete mode 100644 misc/examples/demos.c delete mode 100644 misc/examples/dining_philosophers.c delete mode 100644 misc/examples/forfilter.c delete mode 100644 misc/examples/forloops.c delete mode 100644 misc/examples/functor.c delete mode 100644 misc/examples/gauss2.c delete mode 100644 misc/examples/generator.c delete mode 100644 misc/examples/hashmap.c create mode 100644 misc/examples/hashmaps/birthday.c create mode 100644 misc/examples/hashmaps/books.c create mode 100644 misc/examples/hashmaps/hashmap.c create mode 100644 misc/examples/hashmaps/new_map.c create mode 100644 misc/examples/hashmaps/phonebook.c create mode 100644 misc/examples/hashmaps/unordered_set.c create mode 100644 misc/examples/hashmaps/vikings.c delete mode 100644 misc/examples/inits.c delete mode 100644 misc/examples/intrusive.c create mode 100644 misc/examples/linkedlists/intrusive.c create mode 100644 misc/examples/linkedlists/list.c create mode 100644 misc/examples/linkedlists/list_erase.c create mode 100644 misc/examples/linkedlists/list_splice.c create mode 100644 misc/examples/linkedlists/new_list.c delete mode 100644 misc/examples/list.c delete mode 100644 misc/examples/list_erase.c delete mode 100644 misc/examples/list_splice.c delete mode 100644 misc/examples/lower_bound.c delete mode 100644 misc/examples/mapmap.c create mode 100644 misc/examples/mixed/astar.c create mode 100644 misc/examples/mixed/complex.c create mode 100644 misc/examples/mixed/convert.c create mode 100644 misc/examples/mixed/demos.c create mode 100644 misc/examples/mixed/inits.c create mode 100644 misc/examples/mixed/read.c delete mode 100644 misc/examples/mmap.c delete mode 100644 misc/examples/multidim.c delete mode 100644 misc/examples/multimap.c delete mode 100644 misc/examples/music_arc.c delete mode 100644 misc/examples/new_list.c delete mode 100644 misc/examples/new_map.c delete mode 100644 misc/examples/new_pque.c delete mode 100644 misc/examples/new_queue.c delete mode 100644 misc/examples/new_smap.c delete mode 100644 misc/examples/new_sptr.c delete mode 100644 misc/examples/new_vec.c delete mode 100644 misc/examples/person_arc.c delete mode 100644 misc/examples/phonebook.c delete mode 100644 misc/examples/prime.c delete mode 100644 misc/examples/printspan.c delete mode 100644 misc/examples/priority.c create mode 100644 misc/examples/priorityqueues/functor.c create mode 100644 misc/examples/priorityqueues/new_pque.c create mode 100644 misc/examples/priorityqueues/priority.c delete mode 100644 misc/examples/queue.c create mode 100644 misc/examples/queues/new_queue.c create mode 100644 misc/examples/queues/queue.c delete mode 100644 misc/examples/random.c delete mode 100644 misc/examples/rawptr_elements.c delete mode 100644 misc/examples/read.c delete mode 100644 misc/examples/regex1.c delete mode 100644 misc/examples/regex2.c delete mode 100644 misc/examples/regex_match.c delete mode 100644 misc/examples/regex_replace.c create mode 100644 misc/examples/regularexpressions/regex1.c create mode 100644 misc/examples/regularexpressions/regex2.c create mode 100644 misc/examples/regularexpressions/regex_match.c create mode 100644 misc/examples/regularexpressions/regex_replace.c delete mode 100644 misc/examples/replace.c delete mode 100644 misc/examples/scheduler.c delete mode 100644 misc/examples/shape.c delete mode 100644 misc/examples/shape.cpp delete mode 100644 misc/examples/sidebyside.cpp create mode 100644 misc/examples/smartpointers/arc_containers.c create mode 100644 misc/examples/smartpointers/arc_demo.c create mode 100644 misc/examples/smartpointers/arcvec_erase.c create mode 100644 misc/examples/smartpointers/box.c create mode 100644 misc/examples/smartpointers/box2.c create mode 100644 misc/examples/smartpointers/music_arc.c create mode 100644 misc/examples/smartpointers/new_sptr.c create mode 100644 misc/examples/smartpointers/person_arc.c create mode 100644 misc/examples/smartpointers/rawptr_elements.c delete mode 100644 misc/examples/sorted_map.c create mode 100644 misc/examples/sortedmaps/csmap_erase.c create mode 100644 misc/examples/sortedmaps/csmap_find.c create mode 100644 misc/examples/sortedmaps/csmap_insert.c create mode 100644 misc/examples/sortedmaps/csset_erase.c create mode 100644 misc/examples/sortedmaps/gauss2.c create mode 100644 misc/examples/sortedmaps/listmap.c create mode 100644 misc/examples/sortedmaps/mapmap.c create mode 100644 misc/examples/sortedmaps/multimap.c create mode 100644 misc/examples/sortedmaps/new_smap.c create mode 100644 misc/examples/sortedmaps/sorted_map.c create mode 100644 misc/examples/spans/multidim.c create mode 100644 misc/examples/spans/printspan.c delete mode 100644 misc/examples/splitstr.c delete mode 100644 misc/examples/sso_map.c delete mode 100644 misc/examples/sso_substr.c delete mode 100644 misc/examples/stack.c create mode 100644 misc/examples/strings/cstr_match.c create mode 100644 misc/examples/strings/replace.c create mode 100644 misc/examples/strings/splitstr.c create mode 100644 misc/examples/strings/sso_map.c create mode 100644 misc/examples/strings/sso_substr.c create mode 100644 misc/examples/strings/sview_split.c create mode 100644 misc/examples/strings/utf8replace_c.c create mode 100644 misc/examples/strings/utf8replace_rs.rs delete mode 100644 misc/examples/sview_split.c delete mode 100644 misc/examples/triples.c delete mode 100644 misc/examples/unordered_set.c delete mode 100644 misc/examples/utf8replace_c.c delete mode 100644 misc/examples/utf8replace_rs.rs create mode 100644 misc/examples/vectors/lower_bound.c create mode 100644 misc/examples/vectors/new_vec.c create mode 100644 misc/examples/vectors/stack.c delete mode 100644 misc/examples/vikings.c diff --git a/misc/examples/algorithms/forfilter.c b/misc/examples/algorithms/forfilter.c new file mode 100644 index 00000000..f3c008b3 --- /dev/null +++ b/misc/examples/algorithms/forfilter.c @@ -0,0 +1,149 @@ +#include +#define i_import +#include +#define i_implement +#include +#include +#include + +#define i_type IVec +#define i_key int +#include + +// filters and transforms: +#define flt_skipValue(i, x) (*i.ref != (x)) +#define flt_isEven(i) ((*i.ref & 1) == 0) +#define flt_isOdd(i) (*i.ref & 1) +#define flt_square(i) (*i.ref * *i.ref) + +void demo1(void) +{ + IVec vec = c_init(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80, + 10, 11, 12, 13, 14, 15, 80, 16, 17}); + + c_forfilter (i, IVec, vec, flt_skipValue(i, 80)) + printf(" %d", *i.ref); + puts(""); + + int sum = 0; + c_forfilter (i, IVec, vec, + c_flt_skipwhile(i, *i.ref != 80) && + c_flt_skip(i, 1) && + flt_isEven(i) && + flt_skipValue(i, 80) && + c_flt_take(i, 5) // short-circuit + ){ + sum += flt_square(i); + } + + printf("\n sum: %d\n", sum); + IVec_drop(&vec); +} + + +/* Rust: +fn main() { + let vector = (1..) // Infinite range of integers + .skip_while(|x| *x != 11) // Skip initial numbers unequal 11 + .filter(|x| x % 2 != 0) // Collect odd numbers + .take(5) // Only take five numbers + .map(|x| x * x) // Square each number + .collect::>(); // Return as a new Vec + println!("{:?}", vector); // Print result +} +*/ +void demo2(void) +{ + IVec vector = {0}; + crange r = crange_make(INT64_MAX); + c_forfilter (x, crange, r, + c_flt_skipwhile(x, *x.ref != 11) && + (*x.ref % 2) != 0 && + c_flt_take(x, 5) + ){ + IVec_push(&vector, (int)(*x.ref * *x.ref)); + } + c_foreach (x, IVec, vector) printf(" %d", *x.ref); + + puts(""); + IVec_drop(&vector); +} + +/* Rust: +fn main() { + let sentence = "This is a sentence in Rust."; + let words: Vec<&str> = sentence + .split_whitespace() + .collect(); + let words_containing_i: Vec<&str> = words + .into_iter() + .filter(|word| word.contains("i")) + .collect(); + println!("{:?}", words_containing_i); +} +*/ +#define i_type SVec +#define i_keyclass csview +#include + +void demo3(void) +{ + const char* sentence = "This is a sentence in C99."; + SVec words = {0}; + c_fortoken (w, sentence, " ") // split words + SVec_push(&words, *w.ref); + + SVec words_containing_i = {0}; + c_forfilter (w, SVec, words, + csview_contains(*w.ref, "i")) + SVec_push(&words_containing_i, *w.ref); + + c_foreach (w, SVec, words_containing_i) + printf(" %.*s", c_SV(*w.ref)); + + puts(""); + c_drop(SVec, &words, &words_containing_i); +} + +void demo4(void) +{ + // Keep only uppercase letters and convert them to lowercase: + csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte + cstr out = {0}; + + c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) { + char chr[4]; + utf8_encode(chr, utf8_tolower(utf8_peek(i.ref))); + cstr_push(&out, chr); + } + + printf(" %s\n", cstr_str(&out)); + cstr_drop(&out); +} + +void demo5(void) +{ + #define flt_even(i) ((*i.ref & 1) == 0) + #define flt_mid_decade(i) ((*i.ref % 10) != 0) + crange R = crange_make(1963, INT32_MAX); + + c_forfilter (i, crange, R, + c_flt_skip(i,15) && + c_flt_skipwhile(i, flt_mid_decade(i)) && + c_flt_skip(i,30) && + flt_even(i) && + c_flt_take(i,5) + ){ + printf(" %lld", *i.ref); + } + puts(""); +} + +int main(void) +{ + puts("demo1"); demo1(); + puts("demo2"); demo2(); + puts("demo3"); demo3(); + puts("demo4"); demo4(); + puts("demo5"); demo5(); +} diff --git a/misc/examples/algorithms/forloops.c b/misc/examples/algorithms/forloops.c new file mode 100644 index 00000000..72d745f8 --- /dev/null +++ b/misc/examples/algorithms/forloops.c @@ -0,0 +1,69 @@ +#include +#include + +#define i_type IVec +#define i_key int +#include + +#define i_type IMap +#define i_key int +#define i_val int +#include + + +int main(void) +{ + puts("c_forrange:"); + c_forrange (30) printf(" xx"); + puts(""); + + c_forrange (i, 30) printf(" %lld", i); + puts(""); + + c_forrange (i, 30, 60) printf(" %lld", i); + puts(""); + + c_forrange (i, 30, 90, 2) printf(" %lld", i); + + puts("\n\nc_forlist:"); + c_forlist (i, int, {12, 23, 453, 65, 676}) + printf(" %d", *i.ref); + puts(""); + + c_forlist (i, const char*, {"12", "23", "453", "65", "676"}) + printf(" %s", *i.ref); + puts(""); + + IVec vec = c_init(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199}); + IMap map = c_init(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}}); + + puts("\n\nc_foreach:"); + c_foreach (i, IVec, vec) + printf(" %d", *i.ref); + + puts("\n\nc_foreach_r: reverse"); + c_foreach_rv (i, IVec, vec) + printf(" %d", *i.ref); + + puts("\n\nc_foreach in map:"); + c_foreach (i, IMap, map) + printf(" (%d %d)", i.ref->first, i.ref->second); + + puts("\n\nc_forpair:"); + c_forpair (key, val, IMap, map) + printf(" (%d %d)", *_.key, *_.val); + + #define isOdd(i) (*i.ref & 1) + + puts("\n\nc_forfilter:"); + c_forfilter (i, IVec, vec, + isOdd(i) && + c_flt_skip(i, 4) && + c_flt_take(i, 4) + ){ + printf(" %d", *i.ref); + } + + IVec_drop(&vec); + IMap_drop(&map); +} diff --git a/misc/examples/algorithms/random.c b/misc/examples/algorithms/random.c new file mode 100644 index 00000000..b7c0f277 --- /dev/null +++ b/misc/examples/algorithms/random.c @@ -0,0 +1,45 @@ +#include +#include +#include + +int main(void) +{ + const int N = 1000000000; + const uint64_t seed = (uint64_t)time(NULL), range = 1000000; + crand_t rng = crand_init(seed); + + int64_t sum; + clock_t diff, before; + + printf("Compare speed of full and unbiased ranged random numbers...\n"); + sum = 0; + before = clock(); + c_forrange (N) { + sum += (uint32_t)crand_u64(&rng); + } + diff = clock() - before; + printf("full range\t\t: %f secs, %d, avg: %f\n", + (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); + + crand_unif_t dist1 = crand_unif_init(0, range); + rng = crand_init(seed); + sum = 0; + before = clock(); + c_forrange (N) { + sum += crand_unif(&rng, &dist1); // unbiased + } + diff = clock() - before; + printf("unbiased 0-%" PRIu64 "\t: %f secs, %d, avg: %f\n", + range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); + + sum = 0; + rng = crand_init(seed); + before = clock(); + c_forrange (N) { + sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased + } + diff = clock() - before; + printf("biased 0-%" PRIu64 " \t: %f secs, %d, avg: %f\n", + range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); + +} diff --git a/misc/examples/algorithms/shape.c b/misc/examples/algorithms/shape.c new file mode 100644 index 00000000..bd4bdd5a --- /dev/null +++ b/misc/examples/algorithms/shape.c @@ -0,0 +1,158 @@ +// Demo of typesafe polymorphism in C99, using STC. + +#include +#include +#include + +#define DYN_CAST(T, s) \ + (&T##_api == (s)->api ? (T*)(s) : (T*)0) + +// Shape definition +// ============================================================ + +typedef struct { + float x, y; +} Point; + +typedef struct Shape Shape; + +struct ShapeAPI { + void (*drop)(Shape*); + void (*draw)(const Shape*); +}; + +struct Shape { + struct ShapeAPI* api; + uint32_t color; + uint16_t style; + uint8_t thickness; + uint8_t hardness; +}; + +void Shape_drop(Shape* shape) +{ + printf("shape destructed\n"); +} + +void Shape_delete(Shape* shape) +{ + if (shape) { + shape->api->drop(shape); + c_free(shape); + } +} + +// Triangle implementation +// ============================================================ + +typedef struct { + Shape shape; + Point p[3]; +} Triangle; + +extern struct ShapeAPI Triangle_api; + + +Triangle Triangle_from(Point a, Point b, Point c) { + Triangle t = {{&Triangle_api}, {a, b, c}}; + return t; +} + +static void Triangle_draw(const Shape* shape) +{ + const Triangle* self = DYN_CAST(Triangle, shape); + printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n", + (double)self->p[0].x, (double)self->p[0].y, + (double)self->p[1].x, (double)self->p[1].y, + (double)self->p[2].x, (double)self->p[2].y); +} + +struct ShapeAPI Triangle_api = { + .drop = Shape_drop, + .draw = Triangle_draw, +}; + +// Polygon implementation +// ============================================================ + +#define i_type PointVec +#define i_key Point +#include + +typedef struct { + Shape shape; + PointVec points; +} Polygon; + +extern struct ShapeAPI Polygon_api; + + +Polygon Polygon_init(void) { + Polygon p = {{&Polygon_api}, {0}}; + return p; +} + +void Polygon_addPoint(Polygon* self, Point p) +{ + PointVec_push(&self->points, p); +} + +static void Polygon_drop(Shape* shape) +{ + Polygon* self = DYN_CAST(Polygon, shape); + printf("poly destructed\n"); + PointVec_drop(&self->points); +} + +static void Polygon_draw(const Shape* shape) +{ + const Polygon* self = DYN_CAST(Polygon, shape); + printf("Polygon :"); + c_foreach (i, PointVec, self->points) + printf(" (%g,%g)", (double)i.ref->x, (double)i.ref->y); + puts(""); +} + +struct ShapeAPI Polygon_api = { + .drop = Polygon_drop, + .draw = Polygon_draw, +}; + +// Test +// ============================================================ + +#define i_type Shapes +#define i_key Shape* +#define i_keydrop(x) Shape_delete(*x) +#define i_no_clone +#include + +void testShape(const Shape* shape) +{ + shape->api->draw(shape); +} + + +int main(void) +{ + Shapes shapes = {0}; + + Triangle* tri1 = c_new(Triangle, Triangle_from(c_LITERAL(Point){5, 7}, c_LITERAL(Point){12, 7}, c_LITERAL(Point){12, 20})); + Polygon* pol1 = c_new(Polygon, Polygon_init()); + Polygon* pol2 = c_new(Polygon, Polygon_init()); + + c_forlist (i, Point, {{50, 72}, {123, 73}, {127, 201}, {828, 333}}) + Polygon_addPoint(pol1, *i.ref); + + c_forlist (i, Point, {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}) + Polygon_addPoint(pol2, *i.ref); + + Shapes_push(&shapes, &tri1->shape); + Shapes_push(&shapes, &pol1->shape); + Shapes_push(&shapes, &pol2->shape); + + c_foreach (i, Shapes, shapes) + testShape(*i.ref); + + Shapes_drop(&shapes); +} diff --git a/misc/examples/algorithms/shape.cpp b/misc/examples/algorithms/shape.cpp new file mode 100644 index 00000000..ea1f53d2 --- /dev/null +++ b/misc/examples/algorithms/shape.cpp @@ -0,0 +1,122 @@ +// Demo of polymorphism in C++ + +#include +#include +#include + +// Shape definition +// ============================================================ + +struct Point { + float x, y; +}; + +std::ostream& operator<<(std::ostream& os, const Point& p) { + os << " (" << p.x << "," << p.y << ")"; + return os; +} + +struct Shape { + virtual ~Shape(); + virtual void draw() const = 0; + + uint32_t color; + uint16_t style; + uint8_t thickness; + uint8_t hardness; +}; + +Shape::~Shape() +{ + std::cout << "base destructed" << std::endl; +} + +// Triangle implementation +// ============================================================ + +struct Triangle : public Shape +{ + Triangle(Point a, Point b, Point c); + void draw() const override; + + private: Point p[3]; +}; + + +Triangle::Triangle(Point a, Point b, Point c) + : p{a, b, c} {} + +void Triangle::draw() const +{ + std::cout << "Triangle :" + << p[0] << p[1] << p[2] + << std::endl; +} + + +// Polygon implementation +// ============================================================ + + +struct Polygon : public Shape +{ + ~Polygon(); + void draw() const override; + void addPoint(const Point& p); + + private: std::vector points; +}; + + +void Polygon::addPoint(const Point& p) +{ + points.push_back(p); +} + +Polygon::~Polygon() +{ + std::cout << "poly destructed" << std::endl; +} + +void Polygon::draw() const +{ + std::cout << "Polygon :"; + for (auto& p : points) + std::cout << p ; + std::cout << std::endl; +} + + +// Test +// ============================================================ + +void testShape(const Shape* shape) +{ + shape->draw(); +} + +#include + +int main(void) +{ + std::vector> shapes; + + auto tri1 = std::make_unique(Point{5, 7}, Point{12, 7}, Point{12, 20}); + auto pol1 = std::make_unique(); + auto pol2 = std::make_unique(); + + for (auto& p: std::array + {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}}) + pol1->addPoint(p); + + for (auto& p: std::array + {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}}) + pol2->addPoint(p); + + shapes.push_back(std::move(tri1)); + shapes.push_back(std::move(pol1)); + shapes.push_back(std::move(pol2)); + + for (auto& shape: shapes) + testShape(shape.get()); +} diff --git a/misc/examples/arc_containers.c b/misc/examples/arc_containers.c deleted file mode 100644 index 2fb04c56..00000000 --- a/misc/examples/arc_containers.c +++ /dev/null @@ -1,81 +0,0 @@ -// Create a stack and a list of shared pointers to maps, -// and demonstrate sharing and cloning of maps. -#define i_implement -#include -#include -#define i_type Map -#define i_key_str // strings -#define i_val int -#define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p)) -#include - -#define i_type Arc // (atomic) ref. counted type -#define i_key Map -#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) -// no need for atomic ref. count in single thread: -#define i_opt c_no_atomic -#include - -#define i_type Stack -#define i_keyboxed Arc // define i_keyboxed for carc/cbox value (not i_key) -#include - -#define i_type List -#define i_keyboxed Arc // as above -#include - -int main(void) -{ - Stack stack = {0}; - List list = {0}; - c_defer( - Stack_drop(&stack), - List_drop(&list) - ){ - // POPULATE stack with shared pointers to Maps: - Map *map; - map = Stack_push(&stack, Arc_from(Map_init()))->get; - Map_emplace(map, "Joey", 1990); - Map_emplace(map, "Mary", 1995); - Map_emplace(map, "Joanna", 1992); - - map = Stack_push(&stack, Arc_from(Map_init()))->get; - Map_emplace(map, "Rosanna", 2001); - Map_emplace(map, "Brad", 1999); - Map_emplace(map, "Jack", 1980); - - // POPULATE list: - map = List_push_back(&list, Arc_from(Map_init()))->get; - Map_emplace(map, "Steve", 1979); - Map_emplace(map, "Rick", 1974); - Map_emplace(map, "Tracy", 2003); - - // Share two Maps from the stack with the list using emplace (clone the carc): - List_push_back(&list, Arc_clone(stack.data[0])); - List_push_back(&list, Arc_clone(stack.data[1])); - - // Clone (deep copy) a Map from the stack to the list - // List will contain two shared and two unshared maps. - map = List_push_back(&list, Arc_from(Map_clone(*stack.data[1].get)))->get; - - // Add one more element to the cloned map: - Map_emplace_or_assign(map, "CLONED", 2021); - - // Add one more element to the shared map: - Map_emplace_or_assign(stack.data[1].get, "SHARED", 2021); - - puts("STACKS"); - c_foreach (i, Stack, stack) { - c_forpair (name, year, Map, *i.ref->get) - printf(" %s:%d", cstr_str(_.name), *_.year); - puts(""); - } - - puts("LIST"); - c_foreach (i, List, list) { - c_forpair (name, year, Map, *i.ref->get) - printf(" %s:%d", cstr_str(_.name), *_.year); - puts(""); - } - } -} diff --git a/misc/examples/arc_demo.c b/misc/examples/arc_demo.c deleted file mode 100644 index 929a48a1..00000000 --- a/misc/examples/arc_demo.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -void int_drop(int* x) { - printf("drop: %d\n", *x); -} - -// carc implements its own clone method using reference counting, -// so 'i_keyclone' is not required to be defined (ignored). - -#define i_type Arc // set type name to be defined (instead of 'carc_int') -#define i_key int -#define i_keydrop int_drop // optional, just to display the elements destroyed -#define i_cmp_native // use int comparison (x < y, x == y). -#include // Arc - -#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements -#include // csset_Arc (like: std::set>) - -#define i_keyboxed Arc // note: as above. -#include // cvec_Arc (like: std::vector>) - -int main(void) -{ - const int years[] = {2021, 2012, 2022, 2015}; - - cvec_Arc vec = {0}; - c_forrange (i, c_arraylen(years)) { - cvec_Arc_emplace(&vec, years[i]); - // cvec_Arc_push(&vec, Arc_from(years[i])); // alt. - } - - cvec_Arc_sort(&vec); - - printf("vec:"); - c_foreach (i, cvec_Arc, vec) - printf(" %d", *i.ref->get); - puts(""); - - // add odd numbers from vec to set - csset_Arc set = {0}; - c_foreach (i, cvec_Arc, vec) - if (*i.ref->get & 1) - csset_Arc_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter. - - // erase the two last elements in vec - cvec_Arc_pop_back(&vec); - cvec_Arc_pop_back(&vec); - - printf("vec:"); - c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get); - - printf("\nset:"); - c_foreach (i, csset_Arc, set) printf(" %d", *i.ref->get); - - Arc p = Arc_clone(vec.data[0]); - printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count); - - Arc_drop(&p); - cvec_Arc_drop(&vec); - csset_Arc_drop(&set); -} diff --git a/misc/examples/arcvec_erase.c b/misc/examples/arcvec_erase.c deleted file mode 100644 index ba54c1c7..00000000 --- a/misc/examples/arcvec_erase.c +++ /dev/null @@ -1,50 +0,0 @@ -#include - -void show_drop(int* x) { printf("drop: %d\n", *x); } - -#define i_type Arc -#define i_key int -#define i_keydrop show_drop -#define i_cmp_native // enable sort/search for int type -#include // Shared pointer to int - -#define i_type Vec -#define i_keyboxed Arc -#include // Vec: cvec - - -int main(void) -{ - Vec vec = c_init(Vec, {2012, 1990, 2012, 2019, 2015}); - - // clone the second 2012 and push it back. - // note: cloning make sure that vec.data[2] has ref count 2. - Vec_push(&vec, Arc_clone(vec.data[2])); - - printf("vec before erase :"); - c_foreach (i, Vec, vec) - printf(" %d", *i.ref->get); - - printf("\nerase vec.data[2]; or first matching value depending on compare.\n"); - Vec_iter it; - it = Vec_find(&vec, *vec.data[2].get); - if (it.ref) - Vec_erase_at(&vec, it); - - int year = 2015; - it = Vec_find(&vec, year); // Ok as tmp only. - if (it.ref) - Vec_erase_at(&vec, it); - - printf("vec after erase :"); - c_foreach (i, Vec, vec) - printf(" %d", *i.ref->get); - - Vec_sort(&vec); - printf("\nvec after sort :"); - c_foreach (i, Vec, vec) - printf(" %d", *i.ref->get); - - puts("\nDone"); - Vec_drop(&vec); -} diff --git a/misc/examples/astar.c b/misc/examples/astar.c deleted file mode 100644 index 590b7952..00000000 --- a/misc/examples/astar.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// -- An A* pathfinder inspired by the excellent tutorial at Red Blob Games -- -// -// This is a reimplementation of the CTL example to STC: -// https://github.com/glouw/ctl/blob/master/examples/astar.c -// https://www.redblobgames.com/pathfinding/a-star/introduction.html -#define i_implement -#include -#include - -typedef struct -{ - int x; - int y; - int priorty; - int width; -} -point; - -point -point_init(int x, int y, int width) -{ - return c_LITERAL(point){ x, y, 0, width }; -} - -int -point_cmp_priority(const point* a, const point* b) -{ - return c_default_cmp(&a->priorty, &b->priorty); -} - -int -point_equal(const point* a, const point* b) -{ - return a->x == b->x && a->y == b->y; -} - -point -point_from(const cstr* maze, const char* c, int width) -{ - int index = (int)cstr_find(maze, c); - return point_init(index % width, index / width, width); -} - -int -point_index(const point* p) -{ - return p->x + p->width * p->y; -} - -int -point_key_cmp(const point* a, const point* b) -{ - int i = point_index(a); - int j = point_index(b); - return (i == j) ? 0 : (i < j) ? -1 : 1; -} - -#define i_key point -#define i_cmp point_cmp_priority -#include - -#define i_key point -#define i_opt c_no_cmp -#include - -#define i_key point -#define i_val int -#define i_cmp point_key_cmp -#define i_tag pcost -#include - -#define i_key point -#define i_val point -#define i_cmp point_key_cmp -#define i_tag pstep -#include - -cdeq_point -astar(cstr* maze, int width) -{ - cdeq_point ret_path = {0}; - - cpque_point front = {0}; - csmap_pstep from = {0}; - csmap_pcost costs = {0}; - c_defer( - cpque_point_drop(&front), - csmap_pstep_drop(&from), - csmap_pcost_drop(&costs) - ){ - point start = point_from(maze, "@", width); - point goal = point_from(maze, "!", width); - csmap_pcost_insert(&costs, start, 0); - cpque_point_push(&front, start); - while (!cpque_point_empty(&front)) - { - point current = *cpque_point_top(&front); - cpque_point_pop(&front); - if (point_equal(¤t, &goal)) - break; - point deltas[] = { - { -1, +1, 0, width }, { 0, +1, 0, width }, { 1, +1, 0, width }, - { -1, 0, 0, width }, /* ~ ~ ~ ~ ~ ~ ~ */ { 1, 0, 0, width }, - { -1, -1, 0, width }, { 0, -1, 0, width }, { 1, -1, 0, width }, - }; - for (size_t i = 0; i < c_arraylen(deltas); i++) - { - point delta = deltas[i]; - point next = point_init(current.x + delta.x, current.y + delta.y, width); - int new_cost = *csmap_pcost_at(&costs, current); - if (cstr_str(maze)[point_index(&next)] != '#') - { - const csmap_pcost_value *cost = csmap_pcost_get(&costs, next); - if (cost == NULL || new_cost < cost->second) - { - csmap_pcost_insert(&costs, next, new_cost); - next.priorty = new_cost + abs(goal.x - next.x) + abs(goal.y - next.y); - cpque_point_push(&front, next); - csmap_pstep_insert(&from, next, current); - } - } - } - } - point current = goal; - while (!point_equal(¤t, &start)) - { - cdeq_point_push_front(&ret_path, current); - current = *csmap_pstep_at(&from, current); - } - cdeq_point_push_front(&ret_path, start); - } - return ret_path; -} - -int -main(void) -{ - cstr maze = cstr_lit( - "#########################################################################\n" - "# # # # # # #\n" - "# # ######### # ##### ######### ##### ##### ##### # ! #\n" - "# # # # # # # # # #\n" - "######### # ######### ######### ##### # # # ######### #\n" - "# # # # # # # # # # #\n" - "# # ############# # # ######### ##### # ######### # #\n" - "# # # # # # # # # #\n" - "# ############# ##### ##### # ##### ######### # ##### #\n" - "# # # # # # # # # #\n" - "# ##### ##### # ##### # ######### # # # #############\n" - "# # # # # # # # # # # #\n" - "############# # # # ######### # ##### # ##### ##### #\n" - "# # # # # # # # # #\n" - "# ##### # ######### ##### # ##### ##### ############# #\n" - "# # # # # # # # # #\n" - "# # ######### # ##### ######### # # ############# # #\n" - "# # # # # # # # # # #\n" - "# ######### # # # ##### ######### ######### # #########\n" - "# # # # # # # # # #\n" - "# @ # ##### ##### ##### ######### ##### # ######### # #\n" - "# # # # # # #\n" - "#########################################################################\n" - ); - int width = (int)cstr_find(&maze, "\n") + 1; - cdeq_point ret_path = astar(&maze, width); - - c_foreach (it, cdeq_point, ret_path) - cstr_data(&maze)[point_index(it.ref)] = 'x'; - - printf("%s", cstr_str(&maze)); - - cdeq_point_drop(&ret_path); - cstr_drop(&maze); -} diff --git a/misc/examples/birthday.c b/misc/examples/birthday.c deleted file mode 100644 index 4742cb45..00000000 --- a/misc/examples/birthday.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include -#include - -#define i_tag ic -#define i_key uint64_t -#define i_val int -#include - -static uint64_t seed = 12345; - -static void test_repeats(void) -{ - enum {BITS = 46, BITS_TEST = BITS/2 + 2}; - static const uint64_t N = 1ull << BITS_TEST; - static const uint64_t mask = (1ull << BITS) - 1; - - printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST); - crand_t rng = crand_init(seed); - - cmap_ic m = cmap_ic_with_capacity(N); - c_forrange (i, N) { - uint64_t k = crand_u64(&rng) & mask; - int v = cmap_ic_insert(&m, k, 0).ref->second += 1; - if (v > 1) printf("repeated value %" PRIu64 " (%d) at 2^%d\n", - k, v, (int)log2((double)i)); - } - cmap_ic_drop(&m); -} - -#define i_key uint32_t -#define i_val uint64_t -#define i_tag x -#include - -void test_distribution(void) -{ - enum {BITS = 26}; - printf("distribution test: 2^%d values\n", BITS); - crand_t rng = crand_init(seed); - const size_t N = 1ull << BITS ; - - cmap_x map = {0}; - c_forrange (N) { - uint64_t k = crand_u64(&rng); - cmap_x_insert(&map, k & 0xf, 0).ref->second += 1; - } - - uint64_t sum = 0; - c_foreach (i, cmap_x, map) sum += i.ref->second; - sum /= (uint64_t)map.size; - - c_foreach (i, cmap_x, map) { - printf("%4" PRIu32 ": %" PRIu64 " - %" PRIu64 ": %11.8f\n", - i.ref->first, i.ref->second, sum, - (1.0 - (double)i.ref->second / (double)sum)); - } - - cmap_x_drop(&map); -} - -int main(void) -{ - seed = (uint64_t)time(NULL); - test_distribution(); - test_repeats(); -} diff --git a/misc/examples/bits.c b/misc/examples/bits.c deleted file mode 100644 index e0a11346..00000000 --- a/misc/examples/bits.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include - -int main(void) -{ - cbits set = cbits_with_size(23, true); - cbits s2; - c_defer( - cbits_drop(&set), - cbits_drop(&s2) - ){ - printf("count %lld, %lld\n", cbits_count(&set), cbits_size(&set)); - cbits s1 = cbits_from("1110100110111"); - char buf[256]; - cbits_to_str(&s1, buf, 0, 255); - printf("buf: %s: %lld\n", buf, cbits_count(&s1)); - cbits_drop(&s1); - - cbits_reset(&set, 9); - cbits_resize(&set, 43, false); - printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255)); - - printf("%4lld: ", cbits_size(&set)); - c_forrange (i, cbits_size(&set)) - printf("%d", cbits_test(&set, i)); - puts(""); - - cbits_set(&set, 28); - cbits_resize(&set, 77, true); - cbits_resize(&set, 93, false); - cbits_resize(&set, 102, true); - cbits_set_value(&set, 99, false); - printf("%4lld: ", cbits_size(&set)); - c_forrange (i, cbits_size(&set)) - printf("%d", cbits_test(&set, i)); - - puts("\nIterate:"); - printf("%4lld: ", cbits_size(&set)); - c_forrange (i, cbits_size(&set)) - printf("%d", cbits_test(&set, i)); - puts(""); - - // Make a clone - s2 = cbits_clone(set); - cbits_flip_all(&s2); - cbits_set(&s2, 16); - cbits_set(&s2, 17); - cbits_set(&s2, 18); - printf(" new: "); - c_forrange (i, cbits_size(&s2)) - printf("%d", cbits_test(&s2, i)); - puts(""); - - printf(" xor: "); - cbits_xor(&set, &s2); - c_forrange (i, cbits_size(&set)) - printf("%d", cbits_test(&set, i)); - puts(""); - - cbits_set_all(&set, false); - printf("%4lld: ", cbits_size(&set)); - c_forrange (i, cbits_size(&set)) - printf("%d", cbits_test(&set, i)); - puts(""); - } -} diff --git a/misc/examples/bits2.c b/misc/examples/bits2.c deleted file mode 100644 index de2f16f4..00000000 --- a/misc/examples/bits2.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -// Example of static sized (stack allocated) bitsets - -#define i_type Bits -#define i_capacity 80 // enable fixed bitset on the stack -#include - -int main(void) -{ - Bits s1 = Bits_from("1110100110111"); - - printf("size %lld\n", Bits_size(&s1)); - char buf[256]; - Bits_to_str(&s1, buf, 0, 256); - printf("buf: %s: count=%lld\n", buf, Bits_count(&s1)); - - Bits_reset(&s1, 8); - printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256)); - - Bits s2 = Bits_clone(s1); - - Bits_flip_all(&s2); - Bits_reset(&s2, 66); - Bits_reset(&s2, 67); - printf(" s2: "); - c_forrange (i, Bits_size(&s2)) - printf("%d", Bits_test(&s2, i)); - puts(""); - - printf("xor: "); - Bits_xor(&s1, &s2); - c_forrange (i, Bits_size(&s1)) - printf("%d", Bits_test(&s1, i)); - puts(""); - - printf("all: "); - Bits_set_pattern(&s1, 0x3333333333333333); - c_forrange (i, Bits_size(&s1)) - printf("%d", Bits_test(&s1, i)); - puts(""); -} diff --git a/misc/examples/bitsets/bits.c b/misc/examples/bitsets/bits.c new file mode 100644 index 00000000..e0a11346 --- /dev/null +++ b/misc/examples/bitsets/bits.c @@ -0,0 +1,66 @@ +#include +#include + +int main(void) +{ + cbits set = cbits_with_size(23, true); + cbits s2; + c_defer( + cbits_drop(&set), + cbits_drop(&s2) + ){ + printf("count %lld, %lld\n", cbits_count(&set), cbits_size(&set)); + cbits s1 = cbits_from("1110100110111"); + char buf[256]; + cbits_to_str(&s1, buf, 0, 255); + printf("buf: %s: %lld\n", buf, cbits_count(&s1)); + cbits_drop(&s1); + + cbits_reset(&set, 9); + cbits_resize(&set, 43, false); + printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255)); + + printf("%4lld: ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + + cbits_set(&set, 28); + cbits_resize(&set, 77, true); + cbits_resize(&set, 93, false); + cbits_resize(&set, 102, true); + cbits_set_value(&set, 99, false); + printf("%4lld: ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + + puts("\nIterate:"); + printf("%4lld: ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + + // Make a clone + s2 = cbits_clone(set); + cbits_flip_all(&s2); + cbits_set(&s2, 16); + cbits_set(&s2, 17); + cbits_set(&s2, 18); + printf(" new: "); + c_forrange (i, cbits_size(&s2)) + printf("%d", cbits_test(&s2, i)); + puts(""); + + printf(" xor: "); + cbits_xor(&set, &s2); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + + cbits_set_all(&set, false); + printf("%4lld: ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + } +} diff --git a/misc/examples/bitsets/bits2.c b/misc/examples/bitsets/bits2.c new file mode 100644 index 00000000..de2f16f4 --- /dev/null +++ b/misc/examples/bitsets/bits2.c @@ -0,0 +1,41 @@ +#include +// Example of static sized (stack allocated) bitsets + +#define i_type Bits +#define i_capacity 80 // enable fixed bitset on the stack +#include + +int main(void) +{ + Bits s1 = Bits_from("1110100110111"); + + printf("size %lld\n", Bits_size(&s1)); + char buf[256]; + Bits_to_str(&s1, buf, 0, 256); + printf("buf: %s: count=%lld\n", buf, Bits_count(&s1)); + + Bits_reset(&s1, 8); + printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256)); + + Bits s2 = Bits_clone(s1); + + Bits_flip_all(&s2); + Bits_reset(&s2, 66); + Bits_reset(&s2, 67); + printf(" s2: "); + c_forrange (i, Bits_size(&s2)) + printf("%d", Bits_test(&s2, i)); + puts(""); + + printf("xor: "); + Bits_xor(&s1, &s2); + c_forrange (i, Bits_size(&s1)) + printf("%d", Bits_test(&s1, i)); + puts(""); + + printf("all: "); + Bits_set_pattern(&s1, 0x3333333333333333); + c_forrange (i, Bits_size(&s1)) + printf("%d", Bits_test(&s1, i)); + puts(""); +} diff --git a/misc/examples/bitsets/prime.c b/misc/examples/bitsets/prime.c new file mode 100644 index 00000000..cb3b095a --- /dev/null +++ b/misc/examples/bitsets/prime.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include + + +cbits sieveOfEratosthenes(int64_t n) +{ + cbits bits = cbits_with_size(n/2 + 1, true); + int64_t q = (int64_t)sqrt((double) n) + 1; + for (int64_t i = 3; i < q; i += 2) { + int64_t j = i; + for (; j < n; j += 2) { + if (cbits_test(&bits, j>>1)) { + i = j; + break; + } + } + for (int64_t j = i*i; j < n; j += i*2) + cbits_reset(&bits, j>>1); + } + return bits; +} + +int main(void) +{ + int n = 1000000000; + printf("Computing prime numbers up to %d\n", n); + + clock_t t = clock(); + cbits primes = sieveOfEratosthenes(n + 1); + int np = (int)cbits_count(&primes); + t = clock() - t; + + puts("Show all the primes in the range [2, 1000):"); + printf("2"); + c_forrange (i, 3, 1000, 2) + if (cbits_test(&primes, i>>1)) printf(" %lld", i); + puts("\n"); + + puts("Show the last 50 primes using a temporary crange generator:"); + crange range = crange_make(n - 1, 0, -2); + + c_forfilter (i, crange, range, + cbits_test(&primes, *i.ref/2) && + c_flt_take(i, 50) + ){ + printf("%lld ", *i.ref); + if (c_flt_getcount(i) % 10 == 0) puts(""); + } + printf("Number of primes: %d, time: %.2f\n\n", np, (double)t/CLOCKS_PER_SEC); + + cbits_drop(&primes); +} diff --git a/misc/examples/books.c b/misc/examples/books.c deleted file mode 100644 index 1fd57f27..00000000 --- a/misc/examples/books.c +++ /dev/null @@ -1,62 +0,0 @@ -// https://doc.rust-lang.org/std/collections/struct.HashMap.html -#define i_implement -#include -#define i_key_str -#define i_val_str -#include - -// Type inference lets us omit an explicit type signature (which -// would be `HashMap` in this example). -int main(void) -{ - cmap_str book_reviews = {0}; - - // Review some books. - cmap_str_emplace(&book_reviews, - "Adventures of Huckleberry Finn", - "My favorite book." - ); - cmap_str_emplace(&book_reviews, - "Grimms' Fairy Tales", - "Masterpiece." - ); - cmap_str_emplace(&book_reviews, - "Pride and Prejudice", - "Very enjoyable" - ); - cmap_str_insert(&book_reviews, - cstr_lit("The Adventures of Sherlock Holmes"), - cstr_lit("Eye lyked it alot.") - ); - - // Check for a specific one. - // When collections store owned values (String), they can still be - // queried using references (&str). - if (cmap_str_contains(&book_reviews, "Les Misérables")) { - printf("We've got %" c_ZI " reviews, but Les Misérables ain't one.", - cmap_str_size(&book_reviews)); - } - - // oops, this review has a lot of spelling mistakes, let's delete it. - cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes"); - - // Look up the values associated with some keys. - const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"}; - c_forrange (i, c_arraylen(to_find)) { - const cmap_str_value* b = cmap_str_get(&book_reviews, to_find[i]); - if (b) - printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second)); - else - printf("%s is unreviewed.\n", to_find[i]); - } - - // Look up the value for a key (will panic if the key is not found). - printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice"))); - - // Iterate over everything. - c_forpair (book, review, cmap_str, book_reviews) { - printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review)); - } - - cmap_str_drop(&book_reviews); -} diff --git a/misc/examples/box.c b/misc/examples/box.c deleted file mode 100644 index 94d126c0..00000000 --- a/misc/examples/box.c +++ /dev/null @@ -1,69 +0,0 @@ -/* cbox: heap allocated boxed type */ -#define i_implement -#include - -typedef struct { cstr name, last; } Person; - -Person Person_make(const char* name, const char* last) { - return c_LITERAL(Person){.name = cstr_from(name), .last = cstr_from(last)}; -} - -uint64_t Person_hash(const Person* a) { - return cstr_hash(&a->name) ^ cstr_hash(&a->last); -} - -int Person_cmp(const Person* a, const Person* b) { - int c = cstr_cmp(&a->name, &b->name); - return c ? c : cstr_cmp(&a->last, &b->last); -} - -Person Person_clone(Person p) { - p.name = cstr_clone(p.name); - p.last = cstr_clone(p.last); - return p; -} - -void Person_drop(Person* p) { - printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); - c_drop(cstr, &p->name, &p->last); -} - -#define i_type PBox -#define i_keyclass Person // "class" binds _cmp, _clone, _drop functions. -#include - -#define i_type Persons -#define i_keyboxed PBox // "arcbox" informs that PBox is a smart pointer. -#include - -int main(void) -{ - Persons vec = {0}; - PBox p = PBox_from(Person_make("Laura", "Palmer")); - PBox q = PBox_clone(p); - cstr_assign(&q.get->name, "Leland"); - - printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); - printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); - - Persons_emplace(&vec, Person_make("Dale", "Cooper")); - Persons_emplace(&vec, Person_make("Audrey", "Home")); - - // NB! Clone/share p and q in the Persons container. - Persons_push(&vec, PBox_clone(p)); - Persons_push(&vec, PBox_clone(q)); - - c_foreach (i, Persons, vec) - printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); - puts(""); - - // Look-up Audrey! Create a temporary Person for lookup. - Person a = Person_make("Audrey", "Home"); - const PBox *v = Persons_get(&vec, a); // lookup - if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); - - Person_drop(&a); - PBox_drop(&p); - PBox_drop(&q); - Persons_drop(&vec); -} diff --git a/misc/examples/box2.c b/misc/examples/box2.c deleted file mode 100644 index eaab1c47..00000000 --- a/misc/examples/box2.c +++ /dev/null @@ -1,82 +0,0 @@ -// example: https://doc.rust-lang.org/rust-by-example/std/box.html -#include - -typedef struct { - double x; - double y; -} Point; - -// A Rectangle can be specified by where its top left and bottom right -// corners are in space -typedef struct { - Point top_left; - Point bottom_right; -} Rectangle; - -#define i_key Point -#include // cbox_Point - -#define i_key Rectangle -#include // cbox_Rectangle - -// Box in box: -#define i_type BoxBoxPoint -#define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc! -#define i_no_cmp -#include // BoxBoxPoint - -Point origin(void) { - return c_LITERAL(Point){ .x=1.0, .y=2.0 }; -} - -cbox_Point boxed_origin(void) { - // Allocate this point on the heap, and return a pointer to it - return cbox_Point_make(c_LITERAL(Point){ .x=1.0, .y=2.0 }); -} - - -int main(void) { - // Stack allocated variables - Point point = origin(); - Rectangle rectangle = { - .top_left = origin(), - .bottom_right = { .x=3.0, .y=-4.0 } - }; - - // Heap allocated rectangle - cbox_Rectangle boxed_rectangle = cbox_Rectangle_make(c_LITERAL(Rectangle){ - .top_left = origin(), - .bottom_right = { .x=3.0, .y=-4.0 } - }); - // The output of functions can be boxed - cbox_Point boxed_point = cbox_Point_make(origin()); - - // Can use from(raw) and toraw instead: - BoxBoxPoint box_in_a_box = BoxBoxPoint_from(origin()); - - c_defer( - BoxBoxPoint_drop(&box_in_a_box), - cbox_Point_drop(&boxed_point), - cbox_Rectangle_drop(&boxed_rectangle) - ){ - printf("box_in_a_box: x = %g\n", BoxBoxPoint_toraw(&box_in_a_box).x); - - printf("Point occupies %d bytes on the stack\n", - (int)sizeof(point)); - printf("Rectangle occupies %d bytes on the stack\n", - (int)sizeof(rectangle)); - - // box size == pointer size - printf("Boxed point occupies %d bytes on the stack\n", - (int)sizeof(boxed_point)); - printf("Boxed rectangle occupies %d bytes on the stack\n", - (int)sizeof(boxed_rectangle)); - printf("Boxed box occupies %d bytes on the stack\n", - (int)sizeof(box_in_a_box)); - - // Copy the data contained in `boxed_point` into `unboxed_point` - Point unboxed_point = *boxed_point.get; - printf("Unboxed point occupies %d bytes on the stack\n", - (int)sizeof(unboxed_point)); - } -} diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c deleted file mode 100644 index 599ceaab..00000000 --- a/misc/examples/cointerleave.c +++ /dev/null @@ -1,62 +0,0 @@ -// https://www.youtube.com/watch?v=8sEe-4tig_A -#include -#include -#define i_type IVec -#define i_key int -#include - -struct GenValue { - IVec *v; - IVec_iter it; - int cco_state; -}; - -static int get_value(struct GenValue* g) -{ - cco_routine(g) { - for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) - cco_yield_v(*g->it.ref); - } - return -1; -} - -struct Generator { - struct GenValue x, y; - int cco_state; - int value; -}; - -cco_result interleaved(struct Generator* g) -{ - cco_routine(g) { - while (!(cco_done(&g->x) & cco_done(&g->y))) { - g->value = get_value(&g->x); - if (!cco_done(&g->x)) - cco_yield(); - - g->value = get_value(&g->y); - if (!cco_done(&g->y)) - cco_yield(); - } - } - return CCO_DONE; -} - -void Use(void) -{ - IVec a = c_init(IVec, {2, 4, 6, 8, 10, 11}); - IVec b = c_init(IVec, {3, 5, 7, 9}); - - struct Generator g = {{&a}, {&b}}; - - cco_block_on(interleaved(&g)) { - printf("%d ", g.value); - } - puts(""); - c_drop(IVec, &a, &b); -} - -int main(void) -{ - Use(); -} diff --git a/misc/examples/complex.c b/misc/examples/complex.c deleted file mode 100644 index 4eb1574b..00000000 --- a/misc/examples/complex.c +++ /dev/null @@ -1,49 +0,0 @@ - -// Define similar c++ data types: -// -// using FloatStack = std::stack; -// using StackList = std::stack; -// using ListMap = std::unordered_map>; -// using MapMap = std::unordered_map; -#define i_implement -#include - -#define i_type FloatStack -#define i_key float -#include - -#define i_type StackList -#define i_keyclass FloatStack // "class" picks up _clone, _drop, _cmp -#define i_opt c_no_cmp // exclude FloatStack_cmp(): not defined -#include - -#define i_type ListMap -#define i_key int -#define i_valclass StackList // "class" picks up _clone, _drop -#include - -#define i_type MapMap -#define i_key_str -#define i_valclass ListMap -#include - - -int main(void) -{ - MapMap mmap = {0}; - - // Put in some data in the structures - ListMap* lmap = &MapMap_emplace(&mmap, "first", ListMap_init()).ref->second; - StackList* list = &ListMap_insert(lmap, 42, StackList_init()).ref->second; - FloatStack* stack = StackList_push_back(list, FloatStack_with_size(10, 0)); - stack->data[3] = 3.1415927f; - printf("stack size: %" c_ZI "\n", FloatStack_size(stack)); - - // Access the data entry - const ListMap* lmap_p = MapMap_at(&mmap, "first"); - const StackList* list_p = ListMap_at(lmap_p, 42); - const FloatStack* stack_p = StackList_back(list_p); - printf("value is: %f\n", (double)*FloatStack_at(stack_p, 3)); // pi - - MapMap_drop(&mmap); -} diff --git a/misc/examples/convert.c b/misc/examples/convert.c deleted file mode 100644 index fa64560e..00000000 --- a/misc/examples/convert.c +++ /dev/null @@ -1,57 +0,0 @@ -#define i_implement -#include - -#define i_key_str -#define i_val_str -#include - -#define i_key_str -#include - -#define i_key_str -#include - -int main(void) -{ - cmap_str map, mclone; - cvec_str keys = {0}, values = {0}; - clist_str list = {0}; - - c_defer( - cmap_str_drop(&map), - cmap_str_drop(&mclone), - cvec_str_drop(&keys), - cvec_str_drop(&values), - clist_str_drop(&list) - ){ - map = c_init(cmap_str, { - {"green", "#00ff00"}, - {"blue", "#0000ff"}, - {"yellow", "#ffff00"}, - }); - - puts("MAP:"); - c_foreach (i, cmap_str, map) - printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); - - puts("\nCLONE MAP:"); - mclone = cmap_str_clone(map); - c_foreach (i, cmap_str, mclone) - printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); - - puts("\nCOPY MAP TO VECS:"); - c_foreach (i, cmap_str, mclone) { - cvec_str_emplace_back(&keys, cstr_str(&i.ref->first)); - cvec_str_emplace_back(&values, cstr_str(&i.ref->second)); - } - c_forrange (i, cvec_str_size(&keys)) - printf(" %s: %s\n", cstr_str(keys.data + i), cstr_str(values.data + i)); - - puts("\nCOPY VEC TO LIST:"); - c_foreach (i, cvec_str, keys) - clist_str_emplace_back(&list, cstr_str(i.ref)); - - c_foreach (i, clist_str, list) - printf(" %s\n", cstr_str(i.ref)); - } -} diff --git a/misc/examples/coread.c b/misc/examples/coread.c deleted file mode 100644 index a13f6be5..00000000 --- a/misc/examples/coread.c +++ /dev/null @@ -1,41 +0,0 @@ -#define i_implement -#include -#include -#include - -// Read file line by line using coroutines: - -struct file_read { - const char* filename; - int cco_state; - FILE* fp; - cstr line; -}; - -int file_read(struct file_read* g) -{ - cco_routine(g) { - g->fp = fopen(g->filename, "r"); - if (!g->fp) cco_return; - g->line = cstr_init(); - - cco_await(!cstr_getline(&g->line, g->fp)); - - cco_cleanup: - printf("finish\n"); - cstr_drop(&g->line); - if (g->fp) fclose(g->fp); - } - return 0; -} - -int main(void) -{ - struct file_read g = {__FILE__}; - int n = 0; - cco_block_on(file_read(&g)) - { - printf("%3d %s\n", ++n, cstr_str(&g.line)); - //if (n == 10) cco_stop(&g); - } -} diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c deleted file mode 100644 index b8dfaa13..00000000 --- a/misc/examples/coroutines.c +++ /dev/null @@ -1,112 +0,0 @@ -#include -#include -#include - -// Demonstrate to call another coroutine from a coroutine: -// First create prime generator, then call fibonacci sequence: - -bool is_prime(long long i) { - for (long long j=2; j*j <= i; ++j) - if (i % j == 0) return false; - return true; -} - -struct prime { - int count, idx; - long long result, pos; - int cco_state; -}; - -int prime(struct prime* g) { - cco_routine(g) { - if (g->result < 2) g->result = 2; - if (g->result == 2) { - if (g->count-- == 0) cco_return; - ++g->idx; - cco_yield(); - } - g->result += !(g->result & 1); - for (g->pos = g->result; g->count > 0; g->pos += 2) { - if (is_prime(g->pos)) { - --g->count; - ++g->idx; - g->result = g->pos; - cco_yield(); - } - } - cco_cleanup: - printf("final prm\n"); - } - return 0; -} - - -// Use coroutine to create a fibonacci sequence generator: - -struct fibonacci { - int count, idx; - long long result, b; - int cco_state; -}; - -int fibonacci(struct fibonacci* g) { - assert(g->count < 94); - - long long sum; - cco_routine(g) { - g->idx = 0; - g->result = 0; - g->b = 1; - for (;;) { - if (g->count-- == 0) - cco_return; - if (++g->idx > 1) { - // NB! locals lasts only until next yield/await! - sum = g->result + g->b; - g->result = g->b; - g->b = sum; - } - cco_yield(); - } - cco_cleanup: - printf("final fib\n"); - } - return 0; -} - -// Combine - -struct combined { - struct prime prm; - struct fibonacci fib; - int cco_state; -}; - -int combined(struct combined* g) { - cco_routine(g) { - cco_await_on(prime(&g->prm)); - cco_await_on(fibonacci(&g->fib)); - - // Reuse the g->prm context and extend the count: - g->prm.count = 8, g->prm.result += 2; - cco_reset(&g->prm); - cco_await_on(prime(&g->prm)); - - cco_cleanup: - puts("final combined"); - } - return 0; -} - -int main(void) -{ - struct combined c = {.prm={.count=8}, .fib={14}}; - int res; - - cco_block_on(combined(&c), &res) { - if (res == CCO_YIELD) - printf("Prime(%d)=%lld, Fib(%d)=%lld\n", - c.prm.idx, c.prm.result, - c.fib.idx, c.fib.result); - } -} diff --git a/misc/examples/coroutines/cointerleave.c b/misc/examples/coroutines/cointerleave.c new file mode 100644 index 00000000..599ceaab --- /dev/null +++ b/misc/examples/coroutines/cointerleave.c @@ -0,0 +1,62 @@ +// https://www.youtube.com/watch?v=8sEe-4tig_A +#include +#include +#define i_type IVec +#define i_key int +#include + +struct GenValue { + IVec *v; + IVec_iter it; + int cco_state; +}; + +static int get_value(struct GenValue* g) +{ + cco_routine(g) { + for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) + cco_yield_v(*g->it.ref); + } + return -1; +} + +struct Generator { + struct GenValue x, y; + int cco_state; + int value; +}; + +cco_result interleaved(struct Generator* g) +{ + cco_routine(g) { + while (!(cco_done(&g->x) & cco_done(&g->y))) { + g->value = get_value(&g->x); + if (!cco_done(&g->x)) + cco_yield(); + + g->value = get_value(&g->y); + if (!cco_done(&g->y)) + cco_yield(); + } + } + return CCO_DONE; +} + +void Use(void) +{ + IVec a = c_init(IVec, {2, 4, 6, 8, 10, 11}); + IVec b = c_init(IVec, {3, 5, 7, 9}); + + struct Generator g = {{&a}, {&b}}; + + cco_block_on(interleaved(&g)) { + printf("%d ", g.value); + } + puts(""); + c_drop(IVec, &a, &b); +} + +int main(void) +{ + Use(); +} diff --git a/misc/examples/coroutines/coread.c b/misc/examples/coroutines/coread.c new file mode 100644 index 00000000..a13f6be5 --- /dev/null +++ b/misc/examples/coroutines/coread.c @@ -0,0 +1,41 @@ +#define i_implement +#include +#include +#include + +// Read file line by line using coroutines: + +struct file_read { + const char* filename; + int cco_state; + FILE* fp; + cstr line; +}; + +int file_read(struct file_read* g) +{ + cco_routine(g) { + g->fp = fopen(g->filename, "r"); + if (!g->fp) cco_return; + g->line = cstr_init(); + + cco_await(!cstr_getline(&g->line, g->fp)); + + cco_cleanup: + printf("finish\n"); + cstr_drop(&g->line); + if (g->fp) fclose(g->fp); + } + return 0; +} + +int main(void) +{ + struct file_read g = {__FILE__}; + int n = 0; + cco_block_on(file_read(&g)) + { + printf("%3d %s\n", ++n, cstr_str(&g.line)); + //if (n == 10) cco_stop(&g); + } +} diff --git a/misc/examples/coroutines/coroutines.c b/misc/examples/coroutines/coroutines.c new file mode 100644 index 00000000..b8dfaa13 --- /dev/null +++ b/misc/examples/coroutines/coroutines.c @@ -0,0 +1,112 @@ +#include +#include +#include + +// Demonstrate to call another coroutine from a coroutine: +// First create prime generator, then call fibonacci sequence: + +bool is_prime(long long i) { + for (long long j=2; j*j <= i; ++j) + if (i % j == 0) return false; + return true; +} + +struct prime { + int count, idx; + long long result, pos; + int cco_state; +}; + +int prime(struct prime* g) { + cco_routine(g) { + if (g->result < 2) g->result = 2; + if (g->result == 2) { + if (g->count-- == 0) cco_return; + ++g->idx; + cco_yield(); + } + g->result += !(g->result & 1); + for (g->pos = g->result; g->count > 0; g->pos += 2) { + if (is_prime(g->pos)) { + --g->count; + ++g->idx; + g->result = g->pos; + cco_yield(); + } + } + cco_cleanup: + printf("final prm\n"); + } + return 0; +} + + +// Use coroutine to create a fibonacci sequence generator: + +struct fibonacci { + int count, idx; + long long result, b; + int cco_state; +}; + +int fibonacci(struct fibonacci* g) { + assert(g->count < 94); + + long long sum; + cco_routine(g) { + g->idx = 0; + g->result = 0; + g->b = 1; + for (;;) { + if (g->count-- == 0) + cco_return; + if (++g->idx > 1) { + // NB! locals lasts only until next yield/await! + sum = g->result + g->b; + g->result = g->b; + g->b = sum; + } + cco_yield(); + } + cco_cleanup: + printf("final fib\n"); + } + return 0; +} + +// Combine + +struct combined { + struct prime prm; + struct fibonacci fib; + int cco_state; +}; + +int combined(struct combined* g) { + cco_routine(g) { + cco_await_on(prime(&g->prm)); + cco_await_on(fibonacci(&g->fib)); + + // Reuse the g->prm context and extend the count: + g->prm.count = 8, g->prm.result += 2; + cco_reset(&g->prm); + cco_await_on(prime(&g->prm)); + + cco_cleanup: + puts("final combined"); + } + return 0; +} + +int main(void) +{ + struct combined c = {.prm={.count=8}, .fib={14}}; + int res; + + cco_block_on(combined(&c), &res) { + if (res == CCO_YIELD) + printf("Prime(%d)=%lld, Fib(%d)=%lld\n", + c.prm.idx, c.prm.result, + c.fib.idx, c.fib.result); + } +} diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c new file mode 100644 index 00000000..c87582f1 --- /dev/null +++ b/misc/examples/coroutines/cotasks1.c @@ -0,0 +1,100 @@ +// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/ + +#include +#include +#define i_static +#include +#include + +struct next_value { + int val; + int cco_state; + cco_timer tm; +}; + +int next_value(struct next_value* co) +{ + cco_routine (co) { + while (true) { + cco_timer_await(&co->tm, 1 + rand() % 2); + co->val = rand(); + cco_yield(); + } + } + return 0; +} + +void print_time() +{ + time_t now = time(NULL); + char mbstr[64]; + strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now)); + printf("%s ", mbstr); +} + +// PRODUCER + +struct produce_items { + struct next_value next; + cstr str; + int cco_state; +}; + +int produce_items(struct produce_items* p) +{ + cco_routine (p) { + p->str = cstr_null; + while (true) + { + cco_await(next_value(&p->next) != CCO_AWAIT); + cstr_printf(&p->str, "item %d", p->next.val); + print_time(); + printf("produced %s\n", cstr_str(&p->str)); + cco_yield(); + } + cco_cleanup: + cstr_drop(&p->str); + puts("done produce"); + } + return 0; +} + +// CONSUMER + +struct consume_items { + int n, i; + int cco_state; +}; + +int consume_items(struct consume_items* c, struct produce_items* p) +{ + cco_routine (c) { + for (c->i = 1; c->i <= c->n; ++c->i) + { + printf("consume #%d\n", c->i); + cco_await(produce_items(p) != CCO_AWAIT); + print_time(); + printf("consumed %s\n", cstr_str(&p->str)); + } + cco_cleanup: + puts("done consume"); + } + return 0; +} + +int main(void) +{ + struct produce_items produce = {0}; + struct consume_items consume = {.n=5}; + int count = 0; + + cco_block_on(consume_items(&consume, &produce)) + { + ++count; + //cco_sleep(0.001); + //if (consume.i == 3) cco_stop(&consume); + } + cco_stop(&produce); + produce_items(&produce); + printf("count: %d\n", count); +} \ No newline at end of file diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c new file mode 100644 index 00000000..293583bc --- /dev/null +++ b/misc/examples/coroutines/cotasks2.c @@ -0,0 +1,103 @@ +// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/ + +#include +#include +#define i_static +#include +#include + +cco_task_struct (next_value, + int val; + cco_timer tm; +); + +int next_value(struct next_value* co, cco_runtime* rt) +{ + cco_routine (co) { + while (true) { + cco_timer_await(&co->tm, 1 + rand() % 2); + co->val = rand(); + cco_yield(); + } + } + return 0; +} + +void print_time() +{ + time_t now = time(NULL); + char mbstr[64]; + strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now)); + printf("%s ", mbstr); +} + +// PRODUCER + +cco_task_struct (produce_items, + struct next_value next; + cstr str; +); + +int produce_items(struct produce_items* p, cco_runtime* rt) +{ + cco_routine (p) { + p->str = cstr_null; + while (true) + { + // await for next CCO_YIELD in next_value() + cco_await_task(&p->next, rt, CCO_YIELD); + cstr_printf(&p->str, "item %d", p->next.val); + print_time(); + printf("produced %s\n", cstr_str(&p->str)); + cco_yield(); + } + cco_cleanup: + cstr_drop(&p->str); + puts("done produce"); + } + return 0; +} + +// CONSUMER + +cco_task_struct (consume_items, + int n, i; + struct produce_items produce; +); + +int consume_items(struct consume_items* c, cco_runtime* rt) +{ + cco_routine (c) { + for (c->i = 1; c->i <= c->n; ++c->i) + { + printf("consume #%d\n", c->i); + cco_await_task(&c->produce, rt, CCO_YIELD); + print_time(); + printf("consumed %s\n", cstr_str(&c->produce.str)); + } + cco_cleanup: + cco_stop(&c->produce); + cco_resume(&c->produce, rt); + puts("done consume"); + } + return 0; +} + +int main(void) +{ + struct consume_items consume = { + .n=5, + .cco_fn=consume_items, + .produce={.cco_fn=produce_items, .next={.cco_fn=next_value}}, + }; + int count = 0; + + cco_block_task(&consume) + { + ++count; + //cco_sleep(0.001); + //if (consume.i == 3) + // cco_stop(&consume); + } + printf("count: %d\n", count); +} \ No newline at end of file diff --git a/misc/examples/coroutines/dining_philosophers.c b/misc/examples/coroutines/dining_philosophers.c new file mode 100644 index 00000000..a5063a42 --- /dev/null +++ b/misc/examples/coroutines/dining_philosophers.c @@ -0,0 +1,105 @@ +// https://en.wikipedia.org/wiki/Dining_philosophers_problem +#include +#include +#include +#include + +// Define the number of philosophers and forks +enum { + num_philosophers = 5, + num_forks = num_philosophers, +}; + +struct Philosopher { + int id; + cco_timer tm; + cco_sem* left_fork; + cco_sem* right_fork; + int cco_state; // required +}; + +struct Dining { + // Define semaphores for the forks + cco_sem forks[num_forks]; + struct Philosopher ph[num_philosophers]; + int cco_state; // required +}; + + +// Philosopher coroutine +int philosopher(struct Philosopher* p) +{ + double duration; + cco_routine(p) { + while (1) { + duration = 1.0 + crandf()*2.0; + printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10); + cco_timer_await(&p->tm, duration); + + printf("Philosopher %d is hungry...\n", p->id); + cco_sem_await(p->left_fork); + cco_sem_await(p->right_fork); + + duration = 0.5 + crandf(); + printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10); + cco_timer_await(&p->tm, duration); + + cco_sem_release(p->left_fork); + cco_sem_release(p->right_fork); + } + + cco_cleanup: + printf("Philosopher %d finished\n", p->id); + } + return 0; +} + + +// Dining coroutine +int dining(struct Dining* d) +{ + cco_routine(d) { + for (int i = 0; i < num_forks; ++i) + cco_sem_set(&d->forks[i], 1); // all forks available + for (int i = 0; i < num_philosophers; ++i) { + cco_reset(&d->ph[i]); + d->ph[i].id = i + 1; + d->ph[i].left_fork = &d->forks[i]; + d->ph[i].right_fork = &d->forks[(i + 1) % num_forks]; + } + + while (1) { + // per-"frame" logic resume each philosopher + for (int i = 0; i < num_philosophers; ++i) { + philosopher(&d->ph[i]); + } + cco_yield(); // suspend, return control back to main + } + + cco_cleanup: + for (int i = 0; i < num_philosophers; ++i) { + cco_stop(&d->ph[i]); + philosopher(&d->ph[i]); + } + puts("Dining finished"); + } + return 0; +} + +int main(void) +{ + struct Dining dine; + cco_reset(&dine); + int n=0; + cco_timer tm = cco_timer_from(15.0); // seconds + csrand((uint64_t)time(NULL)); + + while (!cco_done(&dine)) { + if (cco_timer_expired(&tm)) + cco_stop(&dine); + dining(&dine); // resume + cco_sleep(0.001); + ++n; + } + printf("n=%d\n", n); +} diff --git a/misc/examples/coroutines/generator.c b/misc/examples/coroutines/generator.c new file mode 100644 index 00000000..a15f9ba5 --- /dev/null +++ b/misc/examples/coroutines/generator.c @@ -0,0 +1,55 @@ +// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ + +#include +#include + +typedef struct { + int size; + int a, b, c; +} Triple, Triple_value; + +typedef struct { + Triple_value* ref; + int count; + int cco_state; +} Triple_iter; + +int Triple_next(Triple_iter* it) { + Triple_value* g = it->ref; + cco_routine(it) + { + for (g->c = 5; g->size; ++g->c) { + for (g->a = 1; g->a < g->c; ++g->a) { + for (g->b = g->a; g->b < g->c; ++g->b) { + if (g->a*g->a + g->b*g->b == g->c*g->c) { + if (it->count++ == g->size) + cco_return; + cco_yield(); + } + } + } + } + cco_cleanup: + it->ref = NULL; + } + return 0; +} + +Triple_iter Triple_begin(Triple* g) { + Triple_iter it = {.ref=g}; + Triple_next(&it); + return it; +} + + +int main(void) +{ + puts("Pythagorean triples with c < 100:"); + Triple triple = {.size=30}; // max number of triples + c_foreach (i, Triple, triple) { + if (i.ref->c < 100) + printf("%u: (%d, %d, %d)\n", i.count, i.ref->a, i.ref->b, i.ref->c); + else + cco_stop(&i); + } +} diff --git a/misc/examples/coroutines/scheduler.c b/misc/examples/coroutines/scheduler.c new file mode 100644 index 00000000..38defd0f --- /dev/null +++ b/misc/examples/coroutines/scheduler.c @@ -0,0 +1,74 @@ +// https://www.youtube.com/watch?v=8sEe-4tig_A +#include +#include + +struct Task { + int (*fn)(struct Task*); + int cco_state; + struct Scheduler* sched; +}; + +#define i_type Scheduler +#define i_key struct Task +#include + +static bool schedule(Scheduler* sched) +{ + struct Task task = *Scheduler_front(sched); + Scheduler_pop(sched); + + if (!cco_done(&task)) + task.fn(&task); + + return !Scheduler_empty(sched); +} + +static int push_task(const struct Task* task) +{ + Scheduler_push(task->sched, *task); + return CCO_YIELD; +} + + +static int taskA(struct Task* task) +{ + cco_routine(task) { + puts("Hello, from task A"); + cco_yield_v(push_task(task)); + puts("A is back doing work"); + cco_yield_v(push_task(task)); + puts("A is back doing more work"); + cco_yield_v(push_task(task)); + puts("A is back doing even more work"); + } + return 0; +} + +static int taskB(struct Task* task) +{ + cco_routine(task) { + puts("Hello, from task B"); + cco_yield_v(push_task(task)); + puts("B is back doing work"); + cco_yield_v(push_task(task)); + puts("B is back doing more work"); + } + return 0; +} + +void Use(void) +{ + Scheduler scheduler = c_init(Scheduler, { + {.fn=taskA, .sched=&scheduler}, + {.fn=taskB, .sched=&scheduler}, + }); + + while (schedule(&scheduler)) {} + + Scheduler_drop(&scheduler); +} + +int main(void) +{ + Use(); +} diff --git a/misc/examples/coroutines/triples.c b/misc/examples/coroutines/triples.c new file mode 100644 index 00000000..9f2fcc1e --- /dev/null +++ b/misc/examples/coroutines/triples.c @@ -0,0 +1,72 @@ +// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ + +#include +#include + +int gcd(int a, int b) { + while (b) { + int t = a % b; + a = b; + b = t; + } + return a; +} + +void triples_vanilla(int n) { + for (int c = 5, i = 0; n; ++c) { + for (int a = 1; a < c; ++a) { + for (int b = a + 1; b < c; ++b) { + if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c && gcd(a, b) == 1) { + printf("%d: {%d, %d, %d}\n", ++i, a, b, c); + if (--n == 0) goto done; + } + } + } + } + done:; +} + +struct triples { + int size, count; + int a, b, c; + int cco_state; +}; + +int triples_coro(struct triples* t) { + cco_routine(t) { + t->count = 0; + for (t->c = 5; t->size; ++t->c) { + for (t->a = 1; t->a < t->c; ++t->a) { + for (t->b = t->a + 1; t->b < t->c; ++t->b) { + if ((int64_t)t->a*t->a + (int64_t)t->b*t->b == (int64_t)t->c*t->c) { + if (t->count++ == t->size) + cco_return; + cco_yield(); + } + } + } + } + cco_cleanup: + puts("done"); + } + return 0; +} + +int main(void) +{ + puts("Vanilla triples:"); + triples_vanilla(5); + + puts("\nCoroutine triples:"); + struct triples t = {.size=INT32_MAX}; + int n = 0; + + while (triples_coro(&t)) { + if (gcd(t.a, t.b) > 1) + continue; + if (t.c < 100) + printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c); + else + cco_stop(&t); + } +} diff --git a/misc/examples/csmap_erase.c b/misc/examples/csmap_erase.c deleted file mode 100644 index 8d4eeae3..00000000 --- a/misc/examples/csmap_erase.c +++ /dev/null @@ -1,82 +0,0 @@ -// map_erase.c -// From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16 -#define i_implement -#include -#include - -#define i_key int -#define i_val_str -#define i_type mymap -#include - -void printmap(mymap m) -{ - c_foreach (elem, mymap, m) - printf(" [%d, %s]", elem.ref->first, cstr_str(&elem.ref->second)); - printf("\nsize() == %" c_ZI "\n\n", mymap_size(&m)); -} - -int main(void) -{ - mymap m1 = {0}; - - // Fill in some data to test with, one at a time - mymap_insert(&m1, 1, cstr_lit("A")); - mymap_insert(&m1, 2, cstr_lit("B")); - mymap_insert(&m1, 3, cstr_lit("C")); - mymap_insert(&m1, 4, cstr_lit("D")); - mymap_insert(&m1, 5, cstr_lit("E")); - - puts("Starting data of map m1 is:"); - printmap(m1); - // The 1st member function removes an element at a given position - mymap_erase_at(&m1, mymap_advance(mymap_begin(&m1), 1)); - puts("After the 2nd element is deleted, the map m1 is:"); - printmap(m1); - - // Fill in some data to test with - mymap m2 = c_init(mymap, { - {10, "Bob"}, - {11, "Rob"}, - {12, "Robert"}, - {13, "Bert"}, - {14, "Bobby"}, - }); - - puts("Starting data of map m2 is:"); - printmap(m2); - mymap_iter it1 = mymap_advance(mymap_begin(&m2), 1); - mymap_iter it2 = mymap_find(&m2, mymap_back(&m2)->first); - - puts("to remove:"); - c_foreach (i, mymap, it1, it2) - printf(" [%d, %s]", i.ref->first, cstr_str(&i.ref->second)); - puts(""); - // The 2nd member function removes elements - // in the range [First, Last) - mymap_erase_range(&m2, it1, it2); - puts("After the middle elements are deleted, the map m2 is:"); - printmap(m2); - - mymap m3 = {0}; - - // Fill in some data to test with, one at a time, using emplace - mymap_emplace(&m3, 1, "red"); - mymap_emplace(&m3, 2, "yellow"); - mymap_emplace(&m3, 3, "blue"); - mymap_emplace(&m3, 4, "green"); - mymap_emplace(&m3, 5, "orange"); - mymap_emplace(&m3, 6, "purple"); - mymap_emplace(&m3, 7, "pink"); - - puts("Starting data of map m3 is:"); - printmap(m3); - // The 3rd member function removes elements with a given Key - int count = mymap_erase(&m3, 2); - // The 3rd member function also returns the number of elements removed - printf("The number of elements removed from m3 is: %d\n", count); - puts("After the element with a key of 2 is deleted, the map m3 is:"); - printmap(m3); - - c_drop(mymap, &m1, &m2, &m3); -} diff --git a/misc/examples/csmap_find.c b/misc/examples/csmap_find.c deleted file mode 100644 index c392338d..00000000 --- a/misc/examples/csmap_find.c +++ /dev/null @@ -1,73 +0,0 @@ -// This implements the c++ std::map::find example at: -// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17 -#define i_implement -#include - -#define i_key int -#define i_val_str -#define i_tag istr -#include - -#define i_key csmap_istr_raw -#define i_tag istr -#include - -void print_elem(csmap_istr_raw p) { - printf("(%d, %s) ", p.first, p.second); -} - -#define using_print_collection(CX) \ - void print_collection_##CX(const CX* t) { \ - printf("%" c_ZI " elements: ", CX##_size(t)); \ - \ - c_foreach (p, CX, *t) { \ - print_elem(CX##_value_toraw(p.ref)); \ - } \ - puts(""); \ - } - -using_print_collection(csmap_istr) -using_print_collection(cvec_istr) - -void findit(csmap_istr c, csmap_istr_key val) -{ - printf("Trying find() on value %d\n", val); - csmap_istr_iter result = csmap_istr_find(&c, val); // prefer contains() or get() - if (result.ref) { - printf("Element found: "); print_elem(csmap_istr_value_toraw(result.ref)); puts(""); - } else { - puts("Element not found."); - } -} - -int main(void) -{ - csmap_istr m1 = c_init(csmap_istr, {{40, "Zr"}, {45, "Rh"}}); - cvec_istr v = {0}; - - puts("The starting map m1 is (key, value):"); - print_collection_csmap_istr(&m1); - - typedef cvec_istr_value pair; - cvec_istr_push(&v, c_LITERAL(pair){43, "Tc"}); - cvec_istr_push(&v, c_LITERAL(pair){41, "Nb"}); - cvec_istr_push(&v, c_LITERAL(pair){46, "Pd"}); - cvec_istr_push(&v, c_LITERAL(pair){42, "Mo"}); - cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); - cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); // attempt a duplicate - - puts("Inserting the following vector data into m1:"); - print_collection_cvec_istr(&v); - - c_foreach (i, cvec_istr, cvec_istr_begin(&v), cvec_istr_end(&v)) - csmap_istr_emplace(&m1, i.ref->first, i.ref->second); - - puts("The modified map m1 is (key, value):"); - print_collection_csmap_istr(&m1); - puts(""); - findit(m1, 45); - findit(m1, 6); - - csmap_istr_drop(&m1); - cvec_istr_drop(&v); -} diff --git a/misc/examples/csmap_insert.c b/misc/examples/csmap_insert.c deleted file mode 100644 index c9f02891..00000000 --- a/misc/examples/csmap_insert.c +++ /dev/null @@ -1,108 +0,0 @@ -// This implements the std::map insert c++ example at: -// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19 -#define i_key int -#define i_val int -#define i_tag ii // Map of int => int -#include - -#define i_implement -#include -#define i_key int -#define i_val_str -#define i_tag istr // Map of int => cstr -#include - -#define i_key csmap_ii_raw -#define i_opt c_no_cmp -#define i_tag ii -#include - -void print_ii(csmap_ii map) { - c_foreach (e, csmap_ii, map) - printf("(%d, %d) ", e.ref->first, e.ref->second); - puts(""); -} - -void print_istr(csmap_istr map) { - c_foreach (e, csmap_istr, map) - printf("(%d, %s) ", e.ref->first, cstr_str(&e.ref->second)); - puts(""); -} - -int main(void) -{ - // insert single values - csmap_ii m1 = {0}; - csmap_ii_insert(&m1, 1, 10); - csmap_ii_push(&m1, c_LITERAL(csmap_ii_value){2, 20}); - - puts("The original key and mapped values of m1 are:"); - print_ii(m1); - - // intentionally attempt a duplicate, single element - csmap_ii_result ret = csmap_ii_insert(&m1, 1, 111); - if (!ret.inserted) { - csmap_ii_value pr = *ret.ref; - puts("Insert failed, element with key value 1 already exists."); - printf(" The existing element is (%d, %d)\n", pr.first, pr.second); - } - else { - puts("The modified key and mapped values of m1 are:"); - print_ii(m1); - } - puts(""); - - csmap_ii_insert(&m1, 3, 30); - puts("The modified key and mapped values of m1 are:"); - print_ii(m1); - puts(""); - - // The templatized version inserting a jumbled range - csmap_ii m2 = {0}; - cvec_ii v = {0}; - typedef cvec_ii_value ipair; - cvec_ii_push(&v, c_LITERAL(ipair){43, 294}); - cvec_ii_push(&v, c_LITERAL(ipair){41, 262}); - cvec_ii_push(&v, c_LITERAL(ipair){45, 330}); - cvec_ii_push(&v, c_LITERAL(ipair){42, 277}); - cvec_ii_push(&v, c_LITERAL(ipair){44, 311}); - - puts("Inserting the following vector data into m2:"); - c_foreach (e, cvec_ii, v) - printf("(%d, %d) ", e.ref->first, e.ref->second); - puts(""); - - c_foreach (e, cvec_ii, v) - csmap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second); - - puts("The modified key and mapped values of m2 are:"); - c_foreach (e, csmap_ii, m2) - printf("(%d, %d) ", e.ref->first, e.ref->second); - puts("\n"); - - // The templatized versions move-constructing elements - csmap_istr m3 = {0}; - csmap_istr_value ip1 = {475, cstr_lit("blue")}, ip2 = {510, cstr_lit("green")}; - - // single element - csmap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second)); - puts("After the first move insertion, m3 contains:"); - print_istr(m3); - - // single element - csmap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second)); - puts("After the second move insertion, m3 contains:"); - print_istr(m3); - puts(""); - - csmap_ii m4 = {0}; - // Insert the elements from an initializer_list - m4 = c_init(csmap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}}); - puts("After initializer_list insertion, m4 contains:"); - print_ii(m4); - puts(""); - - cvec_ii_drop(&v); - csmap_istr_drop(&m3); - c_drop(csmap_ii, &m1, &m2, &m4); -} diff --git a/misc/examples/csset_erase.c b/misc/examples/csset_erase.c deleted file mode 100644 index 9c7f5e1a..00000000 --- a/misc/examples/csset_erase.c +++ /dev/null @@ -1,41 +0,0 @@ -#include - -#define i_key int -#include - -int main(void) -{ - csset_int set = c_init(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50}); - - c_foreach (k, csset_int, set) - printf(" %d", *k.ref); - puts(""); - - int val = 64; - csset_int_iter it; - printf("Show values >= %d:\n", val); - it = csset_int_lower_bound(&set, val); - - c_foreach (k, csset_int, it, csset_int_end(&set)) - printf(" %d", *k.ref); - puts(""); - - printf("Erase values >= %d:\n", val); - while (it.ref) - it = csset_int_erase_at(&set, it); - - c_foreach (k, csset_int, set) - printf(" %d", *k.ref); - puts(""); - - val = 40; - printf("Erase values < %d:\n", val); - it = csset_int_lower_bound(&set, val); - csset_int_erase_range(&set, csset_int_begin(&set), it); - - c_foreach (k, csset_int, set) - printf(" %d", *k.ref); - puts(""); - - csset_int_drop(&set); -} diff --git a/misc/examples/cstr_match.c b/misc/examples/cstr_match.c deleted file mode 100644 index be03e981..00000000 --- a/misc/examples/cstr_match.c +++ /dev/null @@ -1,26 +0,0 @@ -#define i_implement -#include -#include -#include - -int main(void) -{ - cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"); - - intptr_t pos = cstr_find_at(&ss, 0, "brown"); - printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "" : cstr_str(&ss) + pos); - printf("equals: %d\n", cstr_equals(&ss, "The quick brown fox jumps over the lazy dog.JPG")); - printf("contains: %d\n", cstr_contains(&ss, "umps ove")); - printf("starts_with: %d\n", cstr_starts_with(&ss, "The quick brown")); - printf("ends_with: %d\n", cstr_ends_with(&ss, ".jpg")); - printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); - - cstr s1 = cstr_lit("hell😀 w😀rl🐨"); - csview ch1 = cstr_u8_chr(&s1, 7); - csview ch2 = cstr_u8_chr(&s1, 10); - printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); - printf("ch1: %.*s\n", c_SV(ch1)); - printf("ch2: %.*s\n", c_SV(ch2)); - - c_drop(cstr, &ss, &s1); -} diff --git a/misc/examples/demos.c b/misc/examples/demos.c deleted file mode 100644 index 1a604d9f..00000000 --- a/misc/examples/demos.c +++ /dev/null @@ -1,194 +0,0 @@ -#define i_implement -#include - -void stringdemo1(void) -{ - cstr cs = cstr_lit("one-nine-three-seven-five"); - printf("%s.\n", cstr_str(&cs)); - - cstr_insert(&cs, 3, "-two"); - printf("%s.\n", cstr_str(&cs)); - - cstr_erase(&cs, 7, 5); // -nine - printf("%s.\n", cstr_str(&cs)); - - cstr_replace(&cs, "seven", "four", 1); - printf("%s.\n", cstr_str(&cs)); - - cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs))); - printf("%s.\n", cstr_str(&cs)); - - printf("find \"four\": %s\n", cstr_str(&cs) + cstr_find(&cs, "four")); - - // reassign: - cstr_assign(&cs, "one two three four five six seven"); - cstr_append(&cs, " eight"); - printf("append: %s\n", cstr_str(&cs)); - - cstr_drop(&cs); -} - -#define i_key int64_t -#define i_tag ix -#include - -void vectordemo1(void) -{ - cvec_ix bignums = cvec_ix_with_capacity(100); - cvec_ix_reserve(&bignums, 100); - for (int i = 10; i <= 100; i += 10) - cvec_ix_push(&bignums, i * i); - - printf("erase - %d: %" PRIu64 "\n", 3, bignums.data[3]); - cvec_ix_erase_n(&bignums, 3, 1); // erase index 3 - - cvec_ix_pop(&bignums); // erase the last - cvec_ix_erase_n(&bignums, 0, 1); // erase the first - - for (int i = 0; i < cvec_ix_size(&bignums); ++i) { - printf("%d: %" PRIu64 "\n", i, bignums.data[i]); - } - - cvec_ix_drop(&bignums); -} - -#define i_key_str -#include - -void vectordemo2(void) -{ - cvec_str names = {0}; - cvec_str_emplace_back(&names, "Mary"); - cvec_str_emplace_back(&names, "Joe"); - cvec_str_emplace_back(&names, "Chris"); - cstr_assign(&names.data[1], "Jane"); // replace Joe - printf("names[1]: %s\n", cstr_str(&names.data[1])); - - cvec_str_sort(&names); // Sort the array - - c_foreach (i, cvec_str, names) - printf("sorted: %s\n", cstr_str(i.ref)); - - cvec_str_drop(&names); -} - -#define i_key int -#define i_tag ix -#define i_cmp_native -#include - -void listdemo1(void) -{ - clist_ix nums = {0}, nums2 = {0}; - for (int i = 0; i < 10; ++i) - clist_ix_push_back(&nums, i); - for (int i = 100; i < 110; ++i) - clist_ix_push_back(&nums2, i); - - /* splice nums2 to front of nums */ - clist_ix_splice(&nums, clist_ix_begin(&nums), &nums2); - c_foreach (i, clist_ix, nums) - printf("spliced: %d\n", *i.ref); - puts(""); - - *clist_ix_find(&nums, 104).ref += 50; - clist_ix_remove(&nums, 103); - clist_ix_iter it = clist_ix_begin(&nums); - clist_ix_erase_range(&nums, clist_ix_advance(it, 5), clist_ix_advance(it, 15)); - clist_ix_pop_front(&nums); - clist_ix_push_back(&nums, -99); - clist_ix_sort(&nums); - - c_foreach (i, clist_ix, nums) - printf("sorted: %d\n", *i.ref); - - c_drop(clist_ix, &nums, &nums2); -} - -#define i_key int -#define i_tag i -#include - -void setdemo1(void) -{ - cset_i nums = {0}; - cset_i_insert(&nums, 8); - cset_i_insert(&nums, 11); - - c_foreach (i, cset_i, nums) - printf("set: %d\n", *i.ref); - cset_i_drop(&nums); -} - -#define i_key int -#define i_val int -#define i_tag ii -#include - -void mapdemo1(void) -{ - cmap_ii nums = {0}; - cmap_ii_insert(&nums, 8, 64); - cmap_ii_insert(&nums, 11, 121); - printf("val 8: %d\n", *cmap_ii_at(&nums, 8)); - cmap_ii_drop(&nums); -} - -#define i_key_str -#define i_val int -#define i_tag si -#include - -void mapdemo2(void) -{ - cmap_si nums = {0}; - cmap_si_emplace_or_assign(&nums, "Hello", 64); - cmap_si_emplace_or_assign(&nums, "Groovy", 121); - cmap_si_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous - - // iterate the map: - for (cmap_si_iter i = cmap_si_begin(&nums); i.ref; cmap_si_next(&i)) - printf("long: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); - - // or rather use the short form: - c_foreach (i, cmap_si, nums) - printf("short: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); - - cmap_si_drop(&nums); -} - -#define i_key_str -#define i_val_str -#include - -void mapdemo3(void) -{ - cmap_str table = {0}; - cmap_str_emplace(&table, "Map", "test"); - cmap_str_emplace(&table, "Make", "my"); - cmap_str_emplace(&table, "Sunny", "day"); - cmap_str_iter it = cmap_str_find(&table, "Make"); - c_foreach (i, cmap_str, table) - printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); - printf("size %" c_ZI ": remove: Make: %s\n", cmap_str_size(&table), cstr_str(&it.ref->second)); - //cmap_str_erase(&table, "Make"); - cmap_str_erase_at(&table, it); - - printf("size %" c_ZI "\n", cmap_str_size(&table)); - c_foreach (i, cmap_str, table) - printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); - - cmap_str_drop(&table); // frees key and value cstrs, and hash table. -} - -int main(void) -{ - printf("\nSTRINGDEMO1\n"); stringdemo1(); - printf("\nVECTORDEMO1\n"); vectordemo1(); - printf("\nVECTORDEMO2\n"); vectordemo2(); - printf("\nLISTDEMO1\n"); listdemo1(); - printf("\nSETDEMO1\n"); setdemo1(); - printf("\nMAPDEMO1\n"); mapdemo1(); - printf("\nMAPDEMO2\n"); mapdemo2(); - printf("\nMAPDEMO3\n"); mapdemo3(); -} diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c deleted file mode 100644 index a5063a42..00000000 --- a/misc/examples/dining_philosophers.c +++ /dev/null @@ -1,105 +0,0 @@ -// https://en.wikipedia.org/wiki/Dining_philosophers_problem -#include -#include -#include -#include - -// Define the number of philosophers and forks -enum { - num_philosophers = 5, - num_forks = num_philosophers, -}; - -struct Philosopher { - int id; - cco_timer tm; - cco_sem* left_fork; - cco_sem* right_fork; - int cco_state; // required -}; - -struct Dining { - // Define semaphores for the forks - cco_sem forks[num_forks]; - struct Philosopher ph[num_philosophers]; - int cco_state; // required -}; - - -// Philosopher coroutine -int philosopher(struct Philosopher* p) -{ - double duration; - cco_routine(p) { - while (1) { - duration = 1.0 + crandf()*2.0; - printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10); - cco_timer_await(&p->tm, duration); - - printf("Philosopher %d is hungry...\n", p->id); - cco_sem_await(p->left_fork); - cco_sem_await(p->right_fork); - - duration = 0.5 + crandf(); - printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10); - cco_timer_await(&p->tm, duration); - - cco_sem_release(p->left_fork); - cco_sem_release(p->right_fork); - } - - cco_cleanup: - printf("Philosopher %d finished\n", p->id); - } - return 0; -} - - -// Dining coroutine -int dining(struct Dining* d) -{ - cco_routine(d) { - for (int i = 0; i < num_forks; ++i) - cco_sem_set(&d->forks[i], 1); // all forks available - for (int i = 0; i < num_philosophers; ++i) { - cco_reset(&d->ph[i]); - d->ph[i].id = i + 1; - d->ph[i].left_fork = &d->forks[i]; - d->ph[i].right_fork = &d->forks[(i + 1) % num_forks]; - } - - while (1) { - // per-"frame" logic resume each philosopher - for (int i = 0; i < num_philosophers; ++i) { - philosopher(&d->ph[i]); - } - cco_yield(); // suspend, return control back to main - } - - cco_cleanup: - for (int i = 0; i < num_philosophers; ++i) { - cco_stop(&d->ph[i]); - philosopher(&d->ph[i]); - } - puts("Dining finished"); - } - return 0; -} - -int main(void) -{ - struct Dining dine; - cco_reset(&dine); - int n=0; - cco_timer tm = cco_timer_from(15.0); // seconds - csrand((uint64_t)time(NULL)); - - while (!cco_done(&dine)) { - if (cco_timer_expired(&tm)) - cco_stop(&dine); - dining(&dine); // resume - cco_sleep(0.001); - ++n; - } - printf("n=%d\n", n); -} diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c deleted file mode 100644 index f3c008b3..00000000 --- a/misc/examples/forfilter.c +++ /dev/null @@ -1,149 +0,0 @@ -#include -#define i_import -#include -#define i_implement -#include -#include -#include - -#define i_type IVec -#define i_key int -#include - -// filters and transforms: -#define flt_skipValue(i, x) (*i.ref != (x)) -#define flt_isEven(i) ((*i.ref & 1) == 0) -#define flt_isOdd(i) (*i.ref & 1) -#define flt_square(i) (*i.ref * *i.ref) - -void demo1(void) -{ - IVec vec = c_init(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80, - 10, 11, 12, 13, 14, 15, 80, 16, 17}); - - c_forfilter (i, IVec, vec, flt_skipValue(i, 80)) - printf(" %d", *i.ref); - puts(""); - - int sum = 0; - c_forfilter (i, IVec, vec, - c_flt_skipwhile(i, *i.ref != 80) && - c_flt_skip(i, 1) && - flt_isEven(i) && - flt_skipValue(i, 80) && - c_flt_take(i, 5) // short-circuit - ){ - sum += flt_square(i); - } - - printf("\n sum: %d\n", sum); - IVec_drop(&vec); -} - - -/* Rust: -fn main() { - let vector = (1..) // Infinite range of integers - .skip_while(|x| *x != 11) // Skip initial numbers unequal 11 - .filter(|x| x % 2 != 0) // Collect odd numbers - .take(5) // Only take five numbers - .map(|x| x * x) // Square each number - .collect::>(); // Return as a new Vec - println!("{:?}", vector); // Print result -} -*/ -void demo2(void) -{ - IVec vector = {0}; - crange r = crange_make(INT64_MAX); - c_forfilter (x, crange, r, - c_flt_skipwhile(x, *x.ref != 11) && - (*x.ref % 2) != 0 && - c_flt_take(x, 5) - ){ - IVec_push(&vector, (int)(*x.ref * *x.ref)); - } - c_foreach (x, IVec, vector) printf(" %d", *x.ref); - - puts(""); - IVec_drop(&vector); -} - -/* Rust: -fn main() { - let sentence = "This is a sentence in Rust."; - let words: Vec<&str> = sentence - .split_whitespace() - .collect(); - let words_containing_i: Vec<&str> = words - .into_iter() - .filter(|word| word.contains("i")) - .collect(); - println!("{:?}", words_containing_i); -} -*/ -#define i_type SVec -#define i_keyclass csview -#include - -void demo3(void) -{ - const char* sentence = "This is a sentence in C99."; - SVec words = {0}; - c_fortoken (w, sentence, " ") // split words - SVec_push(&words, *w.ref); - - SVec words_containing_i = {0}; - c_forfilter (w, SVec, words, - csview_contains(*w.ref, "i")) - SVec_push(&words_containing_i, *w.ref); - - c_foreach (w, SVec, words_containing_i) - printf(" %.*s", c_SV(*w.ref)); - - puts(""); - c_drop(SVec, &words, &words_containing_i); -} - -void demo4(void) -{ - // Keep only uppercase letters and convert them to lowercase: - csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte - cstr out = {0}; - - c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) { - char chr[4]; - utf8_encode(chr, utf8_tolower(utf8_peek(i.ref))); - cstr_push(&out, chr); - } - - printf(" %s\n", cstr_str(&out)); - cstr_drop(&out); -} - -void demo5(void) -{ - #define flt_even(i) ((*i.ref & 1) == 0) - #define flt_mid_decade(i) ((*i.ref % 10) != 0) - crange R = crange_make(1963, INT32_MAX); - - c_forfilter (i, crange, R, - c_flt_skip(i,15) && - c_flt_skipwhile(i, flt_mid_decade(i)) && - c_flt_skip(i,30) && - flt_even(i) && - c_flt_take(i,5) - ){ - printf(" %lld", *i.ref); - } - puts(""); -} - -int main(void) -{ - puts("demo1"); demo1(); - puts("demo2"); demo2(); - puts("demo3"); demo3(); - puts("demo4"); demo4(); - puts("demo5"); demo5(); -} diff --git a/misc/examples/forloops.c b/misc/examples/forloops.c deleted file mode 100644 index 47cced8f..00000000 --- a/misc/examples/forloops.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include - -#define i_type IVec -#define i_key int -#include - -#define i_type IMap -#define i_key int -#define i_val int -#include - - -int main(void) -{ - puts("c_forrange:"); - c_forrange (30) printf(" xx"); - puts(""); - - c_forrange (i, 30) printf(" %lld", i); - puts(""); - - c_forrange (i, 30, 60) printf(" %lld", i); - puts(""); - - c_forrange (i, 30, 90, 2) printf(" %lld", i); - - puts("\n\nc_forlist:"); - c_forlist (i, int, {12, 23, 453, 65, 676}) - printf(" %d", *i.ref); - puts(""); - - c_forlist (i, const char*, {"12", "23", "453", "65", "676"}) - printf(" %s", *i.ref); - puts(""); - - IVec vec = c_init(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199}); - IMap map = c_init(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}}); - - puts("\n\nc_foreach:"); - c_foreach (i, IVec, vec) - printf(" %d", *i.ref); - - puts("\n\nc_foreach_r: reverse"); - c_foreach_rv (i, IVec, vec) - printf(" %d", *i.ref); - - puts("\n\nc_foreach in map:"); - c_foreach (i, IMap, map) - printf(" (%d %d)", i.ref->first, i.ref->second); - - puts("\n\nc_forpair:"); - c_forpair (key, val, IMap, map) - printf(" (%d %d)", *_.key, *_.val); - - #define isOdd(i) (*i.ref & 1) - - puts("\n\nc_forfilter:"); - c_forfilter (i, IVec, vec, - isOdd(i) && - c_flt_skip(i, 4) && - c_flt_take(i, 4) - ){ - printf(" %d", *i.ref); - } - - IVec_drop(&vec); - IMap_drop(&map); -} diff --git a/misc/examples/functor.c b/misc/examples/functor.c deleted file mode 100644 index e3bde1dd..00000000 --- a/misc/examples/functor.c +++ /dev/null @@ -1,57 +0,0 @@ -// Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue -// Example of per-instance less-function on a single priority queue type -// - -#include - -#define i_type IPQue -#define i_base cpque -#define i_key int -#define i_extend bool(*less)(const int*, const int*); -#define i_less(x, y) c_extend()->less(x, y) -// Note: i_less: c_extend() accessible for cpque types -// i_cmp: c_extend() accessible for csmap and csset types -// i_hash/i_eq: c_extend() accessible for cmap and cset types -#include - -void print_queue(const char* name, IPQue_ext q) { - // NB: make a clone because there is no way to traverse - // priority queue's content without erasing the queue. - IPQue_ext copy = {q.less, IPQue_clone(q.get)}; - - for (printf("%s: \t", name); !IPQue_empty(©.get); IPQue_pop(©.get)) - printf("%d ", *IPQue_top(©.get)); - puts(""); - - IPQue_drop(©.get); -} - -static bool int_less(const int* x, const int* y) { return *x < *y; } -static bool int_greater(const int* x, const int* y) { return *x > *y; } -static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); } - -int main(void) -{ - const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_arraylen(data); - printf("data: \t"); - c_forrange (i, n) printf("%d ", data[i]); - puts(""); - - - // Max priority queue - IPQue_ext q1 = {.less=int_less}; - IPQue_put_n(&q1.get, data, n); - print_queue("q1", q1); - - // Min priority queue - IPQue_ext minq1 = {.less=int_greater}; - IPQue_put_n(&minq1.get, data, n); - print_queue("minq1", minq1); - - // Using lambda to compare elements. - IPQue_ext q5 = {.less=int_lambda}; - IPQue_put_n(&q5.get, data, n); - print_queue("q5", q5); - - c_drop(IPQue, &q1.get, &minq1.get, &q5.get); -} diff --git a/misc/examples/gauss2.c b/misc/examples/gauss2.c deleted file mode 100644 index 1ab8ade5..00000000 --- a/misc/examples/gauss2.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -#define i_implement -#include -#include - -// Declare int -> int sorted map. -#define i_key int -#define i_val int -#include - -int main(void) -{ - enum {N = 5000000}; - uint64_t seed = (uint64_t)time(NULL); - crand_t rng = crand_init(seed); - const double Mean = round(crand_f64(&rng)*98.0 - 49.0), StdDev = crand_f64(&rng)*10.0 + 1.0, Scale = 74.0; - - printf("Demo of gaussian / normal distribution of %d random samples\n", N); - printf("Mean %f, StdDev %f\n", Mean, StdDev); - - // Setup random engine with normal distribution. - crand_norm_t dist = crand_norm_init(Mean, StdDev); - - // Create and init histogram map with defered destruct - csmap_int hist = {0}; - cstr bar = {0}; - - c_forrange (N) { - int index = (int)round(crand_norm(&rng, &dist)); - csmap_int_insert(&hist, index, 0).ref->second += 1; - } - - // Print the gaussian bar chart - c_forpair (index, count, csmap_int, hist) { - int n = (int)round((double)*_.count * StdDev * Scale * 2.5 / (double)N); - if (n > 0) { - cstr_resize(&bar, n, '*'); - printf("%4d %s\n", *_.index, cstr_str(&bar)); - } - } - cstr_drop(&bar); - csmap_int_drop(&hist); -} diff --git a/misc/examples/generator.c b/misc/examples/generator.c deleted file mode 100644 index a15f9ba5..00000000 --- a/misc/examples/generator.c +++ /dev/null @@ -1,55 +0,0 @@ -// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ - -#include -#include - -typedef struct { - int size; - int a, b, c; -} Triple, Triple_value; - -typedef struct { - Triple_value* ref; - int count; - int cco_state; -} Triple_iter; - -int Triple_next(Triple_iter* it) { - Triple_value* g = it->ref; - cco_routine(it) - { - for (g->c = 5; g->size; ++g->c) { - for (g->a = 1; g->a < g->c; ++g->a) { - for (g->b = g->a; g->b < g->c; ++g->b) { - if (g->a*g->a + g->b*g->b == g->c*g->c) { - if (it->count++ == g->size) - cco_return; - cco_yield(); - } - } - } - } - cco_cleanup: - it->ref = NULL; - } - return 0; -} - -Triple_iter Triple_begin(Triple* g) { - Triple_iter it = {.ref=g}; - Triple_next(&it); - return it; -} - - -int main(void) -{ - puts("Pythagorean triples with c < 100:"); - Triple triple = {.size=30}; // max number of triples - c_foreach (i, Triple, triple) { - if (i.ref->c < 100) - printf("%u: (%d, %d, %d)\n", i.count, i.ref->a, i.ref->b, i.ref->c); - else - cco_stop(&i); - } -} diff --git a/misc/examples/hashmap.c b/misc/examples/hashmap.c deleted file mode 100644 index cf11b7f7..00000000 --- a/misc/examples/hashmap.c +++ /dev/null @@ -1,50 +0,0 @@ -// https://doc.rust-lang.org/rust-by-example/std/hash.html -#define i_implement -#include -#define i_key_str -#define i_val_str -#include -#include - -const char* call(const char* number) { - if (!strcmp(number, "798-1364")) - return "We're sorry, the call cannot be completed as dialed." - " Please hang up and try again."; - else if (!strcmp(number, "645-7689")) - return "Hello, this is Mr. Awesome's Pizza. My name is Fred." - " What can I get for you today?"; - else - return "Hi! Who is this again?"; -} - -int main(void) { - cmap_str contacts = {0}; - - cmap_str_emplace(&contacts, "Daniel", "798-1364"); - cmap_str_emplace(&contacts, "Ashley", "645-7689"); - cmap_str_emplace(&contacts, "Katie", "435-8291"); - cmap_str_emplace(&contacts, "Robert", "956-1745"); - - const cmap_str_value* v; - if ((v = cmap_str_get(&contacts, "Daniel"))) - printf("Calling Daniel: %s\n", call(cstr_str(&v->second))); - else - printf("Don't have Daniel's number."); - - cmap_str_emplace_or_assign(&contacts, "Daniel", "164-6743"); - - if ((v = cmap_str_get(&contacts, "Ashley"))) - printf("Calling Ashley: %s\n", call(cstr_str(&v->second))); - else - printf("Don't have Ashley's number."); - - cmap_str_erase(&contacts, "Ashley"); - - puts(""); - c_forpair (contact, number, cmap_str, contacts) { - printf("Calling %s: %s\n", cstr_str(_.contact), call(cstr_str(_.number))); - } - puts(""); - - cmap_str_drop(&contacts); -} diff --git a/misc/examples/hashmaps/birthday.c b/misc/examples/hashmaps/birthday.c new file mode 100644 index 00000000..4742cb45 --- /dev/null +++ b/misc/examples/hashmaps/birthday.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +#define i_tag ic +#define i_key uint64_t +#define i_val int +#include + +static uint64_t seed = 12345; + +static void test_repeats(void) +{ + enum {BITS = 46, BITS_TEST = BITS/2 + 2}; + static const uint64_t N = 1ull << BITS_TEST; + static const uint64_t mask = (1ull << BITS) - 1; + + printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST); + crand_t rng = crand_init(seed); + + cmap_ic m = cmap_ic_with_capacity(N); + c_forrange (i, N) { + uint64_t k = crand_u64(&rng) & mask; + int v = cmap_ic_insert(&m, k, 0).ref->second += 1; + if (v > 1) printf("repeated value %" PRIu64 " (%d) at 2^%d\n", + k, v, (int)log2((double)i)); + } + cmap_ic_drop(&m); +} + +#define i_key uint32_t +#define i_val uint64_t +#define i_tag x +#include + +void test_distribution(void) +{ + enum {BITS = 26}; + printf("distribution test: 2^%d values\n", BITS); + crand_t rng = crand_init(seed); + const size_t N = 1ull << BITS ; + + cmap_x map = {0}; + c_forrange (N) { + uint64_t k = crand_u64(&rng); + cmap_x_insert(&map, k & 0xf, 0).ref->second += 1; + } + + uint64_t sum = 0; + c_foreach (i, cmap_x, map) sum += i.ref->second; + sum /= (uint64_t)map.size; + + c_foreach (i, cmap_x, map) { + printf("%4" PRIu32 ": %" PRIu64 " - %" PRIu64 ": %11.8f\n", + i.ref->first, i.ref->second, sum, + (1.0 - (double)i.ref->second / (double)sum)); + } + + cmap_x_drop(&map); +} + +int main(void) +{ + seed = (uint64_t)time(NULL); + test_distribution(); + test_repeats(); +} diff --git a/misc/examples/hashmaps/books.c b/misc/examples/hashmaps/books.c new file mode 100644 index 00000000..1fd57f27 --- /dev/null +++ b/misc/examples/hashmaps/books.c @@ -0,0 +1,62 @@ +// https://doc.rust-lang.org/std/collections/struct.HashMap.html +#define i_implement +#include +#define i_key_str +#define i_val_str +#include + +// Type inference lets us omit an explicit type signature (which +// would be `HashMap` in this example). +int main(void) +{ + cmap_str book_reviews = {0}; + + // Review some books. + cmap_str_emplace(&book_reviews, + "Adventures of Huckleberry Finn", + "My favorite book." + ); + cmap_str_emplace(&book_reviews, + "Grimms' Fairy Tales", + "Masterpiece." + ); + cmap_str_emplace(&book_reviews, + "Pride and Prejudice", + "Very enjoyable" + ); + cmap_str_insert(&book_reviews, + cstr_lit("The Adventures of Sherlock Holmes"), + cstr_lit("Eye lyked it alot.") + ); + + // Check for a specific one. + // When collections store owned values (String), they can still be + // queried using references (&str). + if (cmap_str_contains(&book_reviews, "Les Misérables")) { + printf("We've got %" c_ZI " reviews, but Les Misérables ain't one.", + cmap_str_size(&book_reviews)); + } + + // oops, this review has a lot of spelling mistakes, let's delete it. + cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes"); + + // Look up the values associated with some keys. + const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"}; + c_forrange (i, c_arraylen(to_find)) { + const cmap_str_value* b = cmap_str_get(&book_reviews, to_find[i]); + if (b) + printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second)); + else + printf("%s is unreviewed.\n", to_find[i]); + } + + // Look up the value for a key (will panic if the key is not found). + printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice"))); + + // Iterate over everything. + c_forpair (book, review, cmap_str, book_reviews) { + printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review)); + } + + cmap_str_drop(&book_reviews); +} diff --git a/misc/examples/hashmaps/hashmap.c b/misc/examples/hashmaps/hashmap.c new file mode 100644 index 00000000..cf11b7f7 --- /dev/null +++ b/misc/examples/hashmaps/hashmap.c @@ -0,0 +1,50 @@ +// https://doc.rust-lang.org/rust-by-example/std/hash.html +#define i_implement +#include +#define i_key_str +#define i_val_str +#include +#include + +const char* call(const char* number) { + if (!strcmp(number, "798-1364")) + return "We're sorry, the call cannot be completed as dialed." + " Please hang up and try again."; + else if (!strcmp(number, "645-7689")) + return "Hello, this is Mr. Awesome's Pizza. My name is Fred." + " What can I get for you today?"; + else + return "Hi! Who is this again?"; +} + +int main(void) { + cmap_str contacts = {0}; + + cmap_str_emplace(&contacts, "Daniel", "798-1364"); + cmap_str_emplace(&contacts, "Ashley", "645-7689"); + cmap_str_emplace(&contacts, "Katie", "435-8291"); + cmap_str_emplace(&contacts, "Robert", "956-1745"); + + const cmap_str_value* v; + if ((v = cmap_str_get(&contacts, "Daniel"))) + printf("Calling Daniel: %s\n", call(cstr_str(&v->second))); + else + printf("Don't have Daniel's number."); + + cmap_str_emplace_or_assign(&contacts, "Daniel", "164-6743"); + + if ((v = cmap_str_get(&contacts, "Ashley"))) + printf("Calling Ashley: %s\n", call(cstr_str(&v->second))); + else + printf("Don't have Ashley's number."); + + cmap_str_erase(&contacts, "Ashley"); + + puts(""); + c_forpair (contact, number, cmap_str, contacts) { + printf("Calling %s: %s\n", cstr_str(_.contact), call(cstr_str(_.number))); + } + puts(""); + + cmap_str_drop(&contacts); +} diff --git a/misc/examples/hashmaps/new_map.c b/misc/examples/hashmaps/new_map.c new file mode 100644 index 00000000..de990040 --- /dev/null +++ b/misc/examples/hashmaps/new_map.c @@ -0,0 +1,75 @@ +#define i_implement +#include +#include + +forward_cmap(cmap_pnt, struct Point, int); + +typedef struct MyStruct { + cmap_pnt pntmap; + cstr name; +} MyStruct; + +// int => int map +#define i_key int +#define i_val int +#include + +// Point => int map +typedef struct Point { int x, y; } Point; + +int point_cmp(const Point* a, const Point* b) { + int c = a->x - b->x; + return c ? c : a->y - b->y; +} + +// Point => int map +#define i_key Point +#define i_val int +#define i_cmp point_cmp +#define i_hash c_default_hash +#define i_is_forward +#define i_tag pnt +#include + +// cstr => cstr map +#define i_key_str +#define i_val_str +#include + +// string set +#define i_key_str +#include + + +int main(void) +{ + cmap_pnt pmap = c_init(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}}); + + c_foreach (i, cmap_pnt, pmap) + printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second); + puts(""); + + cmap_str smap = c_init(cmap_str, { + {"Hello, friend", "long time no see"}, + {"So long", "see you around"}, + }); + + cset_str sset = c_init(cset_str, { + "Hello, friend", + "Nice to see you again", + "So long", + }); + + cmap_int map = {0}; + cmap_int_insert(&map, 123, 321); + cmap_int_insert(&map, 456, 654); + cmap_int_insert(&map, 789, 987); + + c_foreach (i, cset_str, sset) + printf(" %s\n", cstr_str(i.ref)); + + cmap_int_drop(&map); + cset_str_drop(&sset); + cmap_str_drop(&smap); + cmap_pnt_drop(&pmap); +} diff --git a/misc/examples/hashmaps/phonebook.c b/misc/examples/hashmaps/phonebook.c new file mode 100644 index 00000000..faf7566e --- /dev/null +++ b/misc/examples/hashmaps/phonebook.c @@ -0,0 +1,72 @@ +// The MIT License (MIT) +// Copyright (c) 2018 Maksim Andrianov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// Program to emulates the phone book. +#define i_implement +#include + +#define i_key_str +#define i_val_str +#include + +#define i_key_str +#include + +void print_phone_book(cmap_str phone_book) +{ + c_foreach (i, cmap_str, phone_book) + printf("%s\t- %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); +} + +int main(int argc, char **argv) +{ + cmap_str phone_book = c_init(cmap_str, { + {"Lilia Friedman", "(892) 670-4739"}, + {"Tariq Beltran", "(489) 600-7575"}, + {"Laiba Juarez", "(303) 885-5692"}, + {"Elliott Mooney", "(945) 616-4482"}, + }); + + printf("Phone book:\n"); + print_phone_book(phone_book); + + cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1880"); + cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1990"); + + printf("\nPhone book after adding Zak Byers:\n"); + print_phone_book(phone_book); + + if (cmap_str_contains(&phone_book, "Tariq Beltran")) + printf("\nTariq Beltran is in phone book\n"); + + cmap_str_erase(&phone_book, "Tariq Beltran"); + cmap_str_erase(&phone_book, "Elliott Mooney"); + + printf("\nPhone book after erasing Tariq and Elliott:\n"); + print_phone_book(phone_book); + + cmap_str_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188"); + + printf("\nPhone book after update phone of Zak Byers:\n"); + print_phone_book(phone_book); + + cmap_str_drop(&phone_book); +} diff --git a/misc/examples/hashmaps/unordered_set.c b/misc/examples/hashmaps/unordered_set.c new file mode 100644 index 00000000..dd899d78 --- /dev/null +++ b/misc/examples/hashmaps/unordered_set.c @@ -0,0 +1,45 @@ +// https://iq.opengenus.org/containers-cpp-stl/ +// C program to demonstrate various function of stc cset +#define i_implement +#include +#define i_key_str +#include + +int main(void) +{ + // declaring set for storing string data-type + cset_str stringSet = {0}; + c_defer( + cset_str_drop(&stringSet) + ){ + // inserting various string, same string will be stored + // once in set + cset_str_emplace(&stringSet, "code"); + cset_str_emplace(&stringSet, "in"); + cset_str_emplace(&stringSet, "C"); + cset_str_emplace(&stringSet, "is"); + cset_str_emplace(&stringSet, "fast"); + + const char* key = "slow"; + + // find returns end iterator if key is not found, + // else it returns iterator to that key + + if (cset_str_find(&stringSet, key).ref == NULL) + printf("\"%s\" not found\n", key); + else + printf("Found \"%s\"\n", key); + + key = "C"; + if (!cset_str_contains(&stringSet, key)) + printf("\"%s\" not found\n", key); + else + printf("Found \"%s\"\n", key); + + // now iterating over whole set and printing its + // content + printf("All elements :\n"); + c_foreach (itr, cset_str, stringSet) + printf("%s\n", cstr_str(itr.ref)); + } +} diff --git a/misc/examples/hashmaps/vikings.c b/misc/examples/hashmaps/vikings.c new file mode 100644 index 00000000..d6125854 --- /dev/null +++ b/misc/examples/hashmaps/vikings.c @@ -0,0 +1,59 @@ +#define i_implement +#include + +typedef struct Viking { + cstr name; + cstr country; +} Viking; + +void Viking_drop(Viking* vk) { + cstr_drop(&vk->name); + cstr_drop(&vk->country); +} + +// Define Viking lookup struct with hash, cmp, and convertion functions between Viking and RViking structs: + +typedef struct RViking { + const char* name; + const char* country; +} RViking; + +static inline int RViking_cmp(const RViking* rx, const RViking* ry) { + int c = strcmp(rx->name, ry->name); + return c ? c : strcmp(rx->country, ry->country); +} + +static inline Viking Viking_from(RViking raw) { // note: parameter is by value + return c_LITERAL(Viking){cstr_from(raw.name), cstr_from(raw.country)}; +} + +static inline RViking Viking_toraw(const Viking* vp) { + return c_LITERAL(RViking){cstr_str(&vp->name), cstr_str(&vp->country)}; +} + +// With this in place, we define the Viking => int hash map type: +#define i_type Vikings +#define i_keyclass Viking // key type +#define i_rawclass RViking // lookup type +#define i_keyfrom Viking_from +#define i_opt c_no_clone +#define i_hash(rp) cstrhash(rp->name) ^ cstrhash(rp->country) +#define i_val int // mapped type +#include + +int main(void) +{ + Vikings vikings = {0}; + Vikings_emplace(&vikings, c_LITERAL(RViking){"Einar", "Norway"}, 20); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Olaf", "Denmark"}, 24); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Harald", "Iceland"}, 12); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Björn", "Sweden"}, 10); + + Vikings_value* v = Vikings_get_mut(&vikings, c_LITERAL(RViking){"Einar", "Norway"}); + v->second += 3; // add 3 hp points to Einar + + c_forpair (vk, hp, Vikings, vikings) { + printf("%s of %s has %d hp\n", cstr_str(&_.vk->name), cstr_str(&_.vk->country), *_.hp); + } + Vikings_drop(&vikings); +} diff --git a/misc/examples/inits.c b/misc/examples/inits.c deleted file mode 100644 index 53a49f1f..00000000 --- a/misc/examples/inits.c +++ /dev/null @@ -1,108 +0,0 @@ -#define i_implement -#include - -#define i_key int -#define i_val_str -#define i_tag id // Map of int => cstr -#include - -#define i_key_str -#define i_val int -#define i_tag cnt // Map of cstr => int -#include - -typedef struct {int x, y;} ipair_t; -inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) { - int c = c_default_cmp(&a->x, &b->x); - return c ? c : c_default_cmp(&a->y, &b->y); -} - - -#define i_key ipair_t -#define i_cmp ipair_cmp -#define i_tag ip -#include - -#define i_key ipair_t -#define i_cmp ipair_cmp -#define i_tag ip -#include - -#define i_key float -#define i_tag f -#include - -int main(void) -{ - // CVEC FLOAT / PRIORITY QUEUE - - cpque_f floats = {0}; - const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f}; - - // PRIORITY QUEUE - c_forrange (i, c_arraylen(nums)) - cpque_f_push(&floats, nums[i]); - - puts("\npop and show high priorites first:"); - while (! cpque_f_empty(&floats)) { - printf("%.1f ", (double)*cpque_f_top(&floats)); - cpque_f_pop(&floats); - } - puts("\n"); - cpque_f_drop(&floats); - - // CMAP ID - - int year = 2020; - cmap_id idnames = {0}; - cmap_id_emplace(&idnames, 100, "Hello"); - cmap_id_insert(&idnames, 110, cstr_lit("World")); - cmap_id_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year)); - - c_foreach (i, cmap_id, idnames) - printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second)); - puts(""); - cmap_id_drop(&idnames); - - // CMAP CNT - - cmap_cnt countries = c_init(cmap_cnt, { - {"Norway", 100}, - {"Denmark", 50}, - {"Iceland", 10}, - {"Belgium", 10}, - {"Italy", 10}, - {"Germany", 10}, - {"Spain", 10}, - {"France", 10}, - }); - cmap_cnt_emplace(&countries, "Greenland", 0).ref->second += 20; - cmap_cnt_emplace(&countries, "Sweden", 0).ref->second += 20; - cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20; - cmap_cnt_emplace(&countries, "Finland", 0).ref->second += 20; - - c_forpair (country, health, cmap_cnt, countries) - printf("%s: %d\n", cstr_str(_.country), *_.health); - puts(""); - cmap_cnt_drop(&countries); - - // CVEC PAIR - - cvec_ip pairs1 = c_init(cvec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); - cvec_ip_sort(&pairs1); - - c_foreach (i, cvec_ip, pairs1) - printf("(%d %d) ", i.ref->x, i.ref->y); - puts(""); - cvec_ip_drop(&pairs1); - - // CLIST PAIR - - clist_ip pairs2 = c_init(clist_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); - clist_ip_sort(&pairs2); - - c_foreach (i, clist_ip, pairs2) - printf("(%d %d) ", i.ref->x, i.ref->y); - puts(""); - clist_ip_drop(&pairs2); -} diff --git a/misc/examples/intrusive.c b/misc/examples/intrusive.c deleted file mode 100644 index c22ed260..00000000 --- a/misc/examples/intrusive.c +++ /dev/null @@ -1,33 +0,0 @@ -// Example of clist using the node API. - -#include - -#define i_type List -#define i_key int -#define i_cmp_native -#include - -void printList(List list) { - printf("list:"); - c_foreach (i, List, list) - printf(" %d", *i.ref); - puts(""); -} - -int main(void) { - List list = {0}; - c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8}) - List_push_back_node(&list, c_new(List_node, {0, *i.ref})); - - printList(list); - - puts("Sort list"); - List_sort(&list); - printList(list); - - puts("Remove nodes from list"); - while (!List_empty(&list)) - c_free(List_unlink_after_node(&list, list.last)); - - printList(list); -} diff --git a/misc/examples/linkedlists/intrusive.c b/misc/examples/linkedlists/intrusive.c new file mode 100644 index 00000000..c22ed260 --- /dev/null +++ b/misc/examples/linkedlists/intrusive.c @@ -0,0 +1,33 @@ +// Example of clist using the node API. + +#include + +#define i_type List +#define i_key int +#define i_cmp_native +#include + +void printList(List list) { + printf("list:"); + c_foreach (i, List, list) + printf(" %d", *i.ref); + puts(""); +} + +int main(void) { + List list = {0}; + c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8}) + List_push_back_node(&list, c_new(List_node, {0, *i.ref})); + + printList(list); + + puts("Sort list"); + List_sort(&list); + printList(list); + + puts("Remove nodes from list"); + while (!List_empty(&list)) + c_free(List_unlink_after_node(&list, list.last)); + + printList(list); +} diff --git a/misc/examples/linkedlists/list.c b/misc/examples/linkedlists/list.c new file mode 100644 index 00000000..ad8bebb8 --- /dev/null +++ b/misc/examples/linkedlists/list.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#define i_type DList +#define i_key double +#define i_cmp_native +#include + +int main(void) { + const int n = 3000000; + DList list = {0}; + + crand_t rng = crand_init(1234567); + int m = 0; + c_forrange (n) + DList_push_back(&list, crand_f64(&rng)*n + 100), ++m; + + double sum = 0.0; + printf("sumarize %d:\n", m); + c_foreach (i, DList, list) + sum += *i.ref; + printf("sum %f\n\n", sum); + + c_forfilter (i, DList, list, c_flt_take(i, 10)) + printf("%8d: %10f\n", c_flt_getcount(i), *i.ref); + + puts("sort"); + DList_sort(&list); // qsort O(n*log n) + puts("sorted"); + + c_forfilter (i, DList, list, c_flt_take(i, 10)) + printf("%8d: %10f\n", c_flt_getcount(i), *i.ref); + puts(""); + + DList_drop(&list); + list = c_init(DList, {10, 20, 30, 40, 30, 50}); + + const double* v = DList_get(&list, 30); + printf("found: %f\n", *v); + + c_foreach (i, DList, list) + printf(" %g", *i.ref); + puts(""); + + DList_remove(&list, 30); + DList_insert_at(&list, DList_begin(&list), 5); // same as push_front() + DList_push_back(&list, 500); + DList_push_front(&list, 1964); + + printf("Full: "); + c_foreach (i, DList, list) + printf(" %g", *i.ref); + + printf("\nSubs: "); + DList_iter it = DList_begin(&list); + + c_foreach (i, DList, DList_advance(it, 4), DList_end(&list)) + printf(" %g", *i.ref); + puts(""); + + DList_drop(&list); +} diff --git a/misc/examples/linkedlists/list_erase.c b/misc/examples/linkedlists/list_erase.c new file mode 100644 index 00000000..211c5a5d --- /dev/null +++ b/misc/examples/linkedlists/list_erase.c @@ -0,0 +1,30 @@ +// erasing from clist +#include + +#define i_type IList +#define i_key int +#include + +int main(void) +{ + IList L = c_init(IList, {10, 20, 30, 40, 50}); + + c_foreach (x, IList, L) + printf("%d ", *x.ref); + puts(""); + // 10 20 30 40 50 + IList_iter it = IList_begin(&L); // ^ + IList_next(&it); + it = IList_erase_at(&L, it); // 10 30 40 50 + // ^ + IList_iter end = IList_end(&L); // + IList_next(&it); + it = IList_erase_range(&L, it, end); // 10 30 + // ^ + printf("list contains:"); + c_foreach (x, IList, L) + printf(" %d", *x.ref); + puts(""); + + IList_drop(&L); +} diff --git a/misc/examples/linkedlists/list_splice.c b/misc/examples/linkedlists/list_splice.c new file mode 100644 index 00000000..f1fd6e1f --- /dev/null +++ b/misc/examples/linkedlists/list_splice.c @@ -0,0 +1,38 @@ +#include + +#define i_key int +#define i_tag i +#include + +void print_ilist(const char* s, clist_i list) +{ + printf("%s", s); + c_foreach (i, clist_i, list) { + printf(" %d", *i.ref); + } + puts(""); +} + +int main(void) +{ + clist_i list1 = c_init(clist_i, {1, 2, 3, 4, 5}); + clist_i list2 = c_init(clist_i, {10, 20, 30, 40, 50}); + + print_ilist("list1:", list1); + print_ilist("list2:", list2); + + clist_i_iter it = clist_i_advance(clist_i_begin(&list1), 2); + it = clist_i_splice(&list1, it, &list2); + + puts("After splice"); + print_ilist("list1:", list1); + print_ilist("list2:", list2); + + clist_i_splice_range(&list2, clist_i_begin(&list2), &list1, it, clist_i_end(&list1)); + + puts("After splice_range"); + print_ilist("list1:", list1); + print_ilist("list2:", list2); + + c_drop(clist_i, &list1, &list2); +} diff --git a/misc/examples/linkedlists/new_list.c b/misc/examples/linkedlists/new_list.c new file mode 100644 index 00000000..2112bf1f --- /dev/null +++ b/misc/examples/linkedlists/new_list.c @@ -0,0 +1,70 @@ +#include +#include + +forward_clist(clist_i32, int); +forward_clist(clist_pnt, struct Point); + +typedef struct { + clist_i32 intlist; + clist_pnt pntlist; +} MyStruct; + +#define i_key int +#define i_tag i32 +#define i_is_forward +#include + +typedef struct Point { int x, y; } Point; +int point_cmp(const Point* a, const Point* b) { + int c = a->x - b->x; + return c ? c : a->y - b->y; +} + +#define i_key Point +#define i_cmp point_cmp +#define i_is_forward +#define i_tag pnt +#include + +#define i_key float +#define i_cmp_native // use < and == operators for comparison +#include + +void MyStruct_drop(MyStruct* s); +#define i_type MyList +#define i_key MyStruct +#define i_keydrop MyStruct_drop // define drop function +#define i_no_clone // must explicitely exclude or define cloning support because of drop. +#include + +void MyStruct_drop(MyStruct* s) { + clist_i32_drop(&s->intlist); + clist_pnt_drop(&s->pntlist); +} + + +int main(void) +{ + MyStruct my = {0}; + clist_i32_push_back(&my.intlist, 123); + clist_pnt_push_back(&my.pntlist, c_LITERAL(Point){123, 456}); + MyStruct_drop(&my); + + clist_pnt plist = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); + clist_pnt_sort(&plist); + + c_foreach (i, clist_pnt, plist) + printf(" (%d %d)", i.ref->x, i.ref->y); + puts(""); + clist_pnt_drop(&plist); + + + clist_float flist = c_init(clist_float, {123.3f, 321.2f, -32.2f, 78.2f}); + clist_float_sort(&flist); + + c_foreach (i, clist_float, flist) + printf(" %g", (double)*i.ref); + + puts(""); + clist_float_drop(&flist); +} diff --git a/misc/examples/list.c b/misc/examples/list.c deleted file mode 100644 index ad8bebb8..00000000 --- a/misc/examples/list.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include - -#define i_type DList -#define i_key double -#define i_cmp_native -#include - -int main(void) { - const int n = 3000000; - DList list = {0}; - - crand_t rng = crand_init(1234567); - int m = 0; - c_forrange (n) - DList_push_back(&list, crand_f64(&rng)*n + 100), ++m; - - double sum = 0.0; - printf("sumarize %d:\n", m); - c_foreach (i, DList, list) - sum += *i.ref; - printf("sum %f\n\n", sum); - - c_forfilter (i, DList, list, c_flt_take(i, 10)) - printf("%8d: %10f\n", c_flt_getcount(i), *i.ref); - - puts("sort"); - DList_sort(&list); // qsort O(n*log n) - puts("sorted"); - - c_forfilter (i, DList, list, c_flt_take(i, 10)) - printf("%8d: %10f\n", c_flt_getcount(i), *i.ref); - puts(""); - - DList_drop(&list); - list = c_init(DList, {10, 20, 30, 40, 30, 50}); - - const double* v = DList_get(&list, 30); - printf("found: %f\n", *v); - - c_foreach (i, DList, list) - printf(" %g", *i.ref); - puts(""); - - DList_remove(&list, 30); - DList_insert_at(&list, DList_begin(&list), 5); // same as push_front() - DList_push_back(&list, 500); - DList_push_front(&list, 1964); - - printf("Full: "); - c_foreach (i, DList, list) - printf(" %g", *i.ref); - - printf("\nSubs: "); - DList_iter it = DList_begin(&list); - - c_foreach (i, DList, DList_advance(it, 4), DList_end(&list)) - printf(" %g", *i.ref); - puts(""); - - DList_drop(&list); -} diff --git a/misc/examples/list_erase.c b/misc/examples/list_erase.c deleted file mode 100644 index 211c5a5d..00000000 --- a/misc/examples/list_erase.c +++ /dev/null @@ -1,30 +0,0 @@ -// erasing from clist -#include - -#define i_type IList -#define i_key int -#include - -int main(void) -{ - IList L = c_init(IList, {10, 20, 30, 40, 50}); - - c_foreach (x, IList, L) - printf("%d ", *x.ref); - puts(""); - // 10 20 30 40 50 - IList_iter it = IList_begin(&L); // ^ - IList_next(&it); - it = IList_erase_at(&L, it); // 10 30 40 50 - // ^ - IList_iter end = IList_end(&L); // - IList_next(&it); - it = IList_erase_range(&L, it, end); // 10 30 - // ^ - printf("list contains:"); - c_foreach (x, IList, L) - printf(" %d", *x.ref); - puts(""); - - IList_drop(&L); -} diff --git a/misc/examples/list_splice.c b/misc/examples/list_splice.c deleted file mode 100644 index f1fd6e1f..00000000 --- a/misc/examples/list_splice.c +++ /dev/null @@ -1,38 +0,0 @@ -#include - -#define i_key int -#define i_tag i -#include - -void print_ilist(const char* s, clist_i list) -{ - printf("%s", s); - c_foreach (i, clist_i, list) { - printf(" %d", *i.ref); - } - puts(""); -} - -int main(void) -{ - clist_i list1 = c_init(clist_i, {1, 2, 3, 4, 5}); - clist_i list2 = c_init(clist_i, {10, 20, 30, 40, 50}); - - print_ilist("list1:", list1); - print_ilist("list2:", list2); - - clist_i_iter it = clist_i_advance(clist_i_begin(&list1), 2); - it = clist_i_splice(&list1, it, &list2); - - puts("After splice"); - print_ilist("list1:", list1); - print_ilist("list2:", list2); - - clist_i_splice_range(&list2, clist_i_begin(&list2), &list1, it, clist_i_end(&list1)); - - puts("After splice_range"); - print_ilist("list1:", list1); - print_ilist("list2:", list2); - - c_drop(clist_i, &list1, &list2); -} diff --git a/misc/examples/lower_bound.c b/misc/examples/lower_bound.c deleted file mode 100644 index bea828f2..00000000 --- a/misc/examples/lower_bound.c +++ /dev/null @@ -1,66 +0,0 @@ -#include - -#define i_key int -#define i_cmp_native -#include - -#define i_key int -#include - -int main(void) -{ - // TEST SORTED VECTOR - { - int key, *res; - cvec_int vec = c_init(cvec_int, {40, 600, 1, 7000, 2, 500, 30}); - - cvec_int_sort(&vec); - - key = 100; - res = cvec_int_lower_bound(&vec, key).ref; - if (res) - printf("Sorted Vec %d: lower bound: %d\n", key, *res); // 500 - - key = 10; - cvec_int_iter it1 = cvec_int_lower_bound(&vec, key); - if (it1.ref) - printf("Sorted Vec %3d: lower_bound: %d\n", key, *it1.ref); // 30 - - key = 600; - cvec_int_iter it2 = cvec_int_binary_search(&vec, key); - if (it2.ref) - printf("Sorted Vec %d: bin. search: %d\n", key, *it2.ref); // 600 - - c_foreach (i, cvec_int, it1, it2) - printf(" %d\n", *i.ref); - - puts(""); - cvec_int_drop(&vec); - } - - // TEST SORTED SET - { - int key, *res; - csset_int set = c_init(csset_int, {40, 600, 1, 7000, 2, 500, 30}); - - key = 100; - res = csset_int_lower_bound(&set, key).ref; - if (res) - printf("Sorted Set %d: lower bound: %d\n", key, *res); // 500 - - key = 10; - csset_int_iter it1 = csset_int_lower_bound(&set, key); - if (it1.ref) - printf("Sorted Set %3d: lower bound: %d\n", key, *it1.ref); // 30 - - key = 600; - csset_int_iter it2 = csset_int_find(&set, key); - if (it2.ref) - printf("Sorted Set %d: find : %d\n", key, *it2.ref); // 600 - - c_foreach (i, csset_int, it1, it2) - printf(" %d\n", *i.ref); - - csset_int_drop(&set); - } -} diff --git a/misc/examples/make.sh b/misc/examples/make.sh index cf224950..7135ffdf 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -37,18 +37,20 @@ else fi if [ $run = 0 ] ; then - for i in *.c ; do - echo $comp -I../../include $i $clibs $oflag$(basename $i .c).exe - $comp -I../../include $i $clibs $oflag$(basename $i .c).exe + for i in */*.c ; do + #out=$(basename $i .c).exe + out=$(dirname $i)/$(basename $i .c).exe + echo $comp -I../../include $i $clibs $oflag$out + $comp -I../../include $i $clibs $oflag$out done else - for i in *.c ; do + for i in */*.c ; do echo $comp -I../../include $i $clibs $comp -I../../include $i $clibs - if [ -f $(basename -s .c $i).exe ]; then ./$(basename -s .c $i).exe; fi - if [ -f ./a.exe ]; then ./a.exe; fi - if [ -f ./a.out ]; then ./a.out; fi + #out=$(basename $i .c).exe + out=$(dirname $i)/$(basename $i .c).exe + if [ -f $out ]; then ./$out; fi done fi -rm -f a.out *.o *.obj # *.exe +#rm -f a.out *.o *.obj # *.exe diff --git a/misc/examples/mapmap.c b/misc/examples/mapmap.c deleted file mode 100644 index d3065659..00000000 --- a/misc/examples/mapmap.c +++ /dev/null @@ -1,64 +0,0 @@ -// create a structure like: std::map>: -#define i_implement -#include - -// People: std::map -#define i_type People -#define i_key_str // name -#define i_val_str // email -#define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override -#include - -// Departments: std::map -#define i_type Departments -#define i_key_str // dep. name -#define i_valclass People -#include - - -void add(Departments* deps, const char* name, const char* email, const char* dep) -{ - People *people = &Departments_emplace(deps, dep, People_init()).ref->second; - People_emplace_or_assign(people, name, email); -} - -int contains(Departments* map, const char* name) -{ - int count = 0; - c_foreach (i, Departments, *map) - if (People_contains(&i.ref->second, name)) - ++count; - return count; -} - -int main(void) -{ - Departments map = {0}; - - add(&map, "Anna Kendro", "Anna@myplace.com", "Support"); - add(&map, "Terry Dane", "Terry@myplace.com", "Development"); - add(&map, "Kik Winston", "Kik@myplace.com", "Finance"); - add(&map, "Nancy Drew", "Nancy@live.com", "Development"); - add(&map, "Nick Denton", "Nick@myplace.com", "Finance"); - add(&map, "Stan Whiteword", "Stan@myplace.com", "Marketing"); - add(&map, "Serena Bath", "Serena@myplace.com", "Support"); - add(&map, "Patrick Dust", "Patrick@myplace.com", "Finance"); - add(&map, "Red Winger", "Red@gmail.com", "Marketing"); - add(&map, "Nick Denton", "Nick@yahoo.com", "Support"); - add(&map, "Colin Turth", "Colin@myplace.com", "Support"); - add(&map, "Dennis Kay", "Dennis@mail.com", "Marketing"); - add(&map, "Anne Dickens", "Anne@myplace.com", "Development"); - - c_foreach (i, Departments, map) - c_forpair (name, email, People, i.ref->second) - printf("%s: %s - %s\n", cstr_str(&i.ref->first), cstr_str(_.name), cstr_str(_.email)); - puts(""); - - printf("found Nick Denton: %d\n", contains(&map, "Nick Denton")); - printf("found Patrick Dust: %d\n", contains(&map, "Patrick Dust")); - printf("found Dennis Kay: %d\n", contains(&map, "Dennis Kay")); - printf("found Serena Bath: %d\n", contains(&map, "Serena Bath")); - puts("Done"); - - Departments_drop(&map); -} diff --git a/misc/examples/mixed/astar.c b/misc/examples/mixed/astar.c new file mode 100644 index 00000000..590b7952 --- /dev/null +++ b/misc/examples/mixed/astar.c @@ -0,0 +1,174 @@ +// +// -- An A* pathfinder inspired by the excellent tutorial at Red Blob Games -- +// +// This is a reimplementation of the CTL example to STC: +// https://github.com/glouw/ctl/blob/master/examples/astar.c +// https://www.redblobgames.com/pathfinding/a-star/introduction.html +#define i_implement +#include +#include + +typedef struct +{ + int x; + int y; + int priorty; + int width; +} +point; + +point +point_init(int x, int y, int width) +{ + return c_LITERAL(point){ x, y, 0, width }; +} + +int +point_cmp_priority(const point* a, const point* b) +{ + return c_default_cmp(&a->priorty, &b->priorty); +} + +int +point_equal(const point* a, const point* b) +{ + return a->x == b->x && a->y == b->y; +} + +point +point_from(const cstr* maze, const char* c, int width) +{ + int index = (int)cstr_find(maze, c); + return point_init(index % width, index / width, width); +} + +int +point_index(const point* p) +{ + return p->x + p->width * p->y; +} + +int +point_key_cmp(const point* a, const point* b) +{ + int i = point_index(a); + int j = point_index(b); + return (i == j) ? 0 : (i < j) ? -1 : 1; +} + +#define i_key point +#define i_cmp point_cmp_priority +#include + +#define i_key point +#define i_opt c_no_cmp +#include + +#define i_key point +#define i_val int +#define i_cmp point_key_cmp +#define i_tag pcost +#include + +#define i_key point +#define i_val point +#define i_cmp point_key_cmp +#define i_tag pstep +#include + +cdeq_point +astar(cstr* maze, int width) +{ + cdeq_point ret_path = {0}; + + cpque_point front = {0}; + csmap_pstep from = {0}; + csmap_pcost costs = {0}; + c_defer( + cpque_point_drop(&front), + csmap_pstep_drop(&from), + csmap_pcost_drop(&costs) + ){ + point start = point_from(maze, "@", width); + point goal = point_from(maze, "!", width); + csmap_pcost_insert(&costs, start, 0); + cpque_point_push(&front, start); + while (!cpque_point_empty(&front)) + { + point current = *cpque_point_top(&front); + cpque_point_pop(&front); + if (point_equal(¤t, &goal)) + break; + point deltas[] = { + { -1, +1, 0, width }, { 0, +1, 0, width }, { 1, +1, 0, width }, + { -1, 0, 0, width }, /* ~ ~ ~ ~ ~ ~ ~ */ { 1, 0, 0, width }, + { -1, -1, 0, width }, { 0, -1, 0, width }, { 1, -1, 0, width }, + }; + for (size_t i = 0; i < c_arraylen(deltas); i++) + { + point delta = deltas[i]; + point next = point_init(current.x + delta.x, current.y + delta.y, width); + int new_cost = *csmap_pcost_at(&costs, current); + if (cstr_str(maze)[point_index(&next)] != '#') + { + const csmap_pcost_value *cost = csmap_pcost_get(&costs, next); + if (cost == NULL || new_cost < cost->second) + { + csmap_pcost_insert(&costs, next, new_cost); + next.priorty = new_cost + abs(goal.x - next.x) + abs(goal.y - next.y); + cpque_point_push(&front, next); + csmap_pstep_insert(&from, next, current); + } + } + } + } + point current = goal; + while (!point_equal(¤t, &start)) + { + cdeq_point_push_front(&ret_path, current); + current = *csmap_pstep_at(&from, current); + } + cdeq_point_push_front(&ret_path, start); + } + return ret_path; +} + +int +main(void) +{ + cstr maze = cstr_lit( + "#########################################################################\n" + "# # # # # # #\n" + "# # ######### # ##### ######### ##### ##### ##### # ! #\n" + "# # # # # # # # # #\n" + "######### # ######### ######### ##### # # # ######### #\n" + "# # # # # # # # # # #\n" + "# # ############# # # ######### ##### # ######### # #\n" + "# # # # # # # # # #\n" + "# ############# ##### ##### # ##### ######### # ##### #\n" + "# # # # # # # # # #\n" + "# ##### ##### # ##### # ######### # # # #############\n" + "# # # # # # # # # # # #\n" + "############# # # # ######### # ##### # ##### ##### #\n" + "# # # # # # # # # #\n" + "# ##### # ######### ##### # ##### ##### ############# #\n" + "# # # # # # # # # #\n" + "# # ######### # ##### ######### # # ############# # #\n" + "# # # # # # # # # # #\n" + "# ######### # # # ##### ######### ######### # #########\n" + "# # # # # # # # # #\n" + "# @ # ##### ##### ##### ######### ##### # ######### # #\n" + "# # # # # # #\n" + "#########################################################################\n" + ); + int width = (int)cstr_find(&maze, "\n") + 1; + cdeq_point ret_path = astar(&maze, width); + + c_foreach (it, cdeq_point, ret_path) + cstr_data(&maze)[point_index(it.ref)] = 'x'; + + printf("%s", cstr_str(&maze)); + + cdeq_point_drop(&ret_path); + cstr_drop(&maze); +} diff --git a/misc/examples/mixed/complex.c b/misc/examples/mixed/complex.c new file mode 100644 index 00000000..4eb1574b --- /dev/null +++ b/misc/examples/mixed/complex.c @@ -0,0 +1,49 @@ + +// Define similar c++ data types: +// +// using FloatStack = std::stack; +// using StackList = std::stack; +// using ListMap = std::unordered_map>; +// using MapMap = std::unordered_map; +#define i_implement +#include + +#define i_type FloatStack +#define i_key float +#include + +#define i_type StackList +#define i_keyclass FloatStack // "class" picks up _clone, _drop, _cmp +#define i_opt c_no_cmp // exclude FloatStack_cmp(): not defined +#include + +#define i_type ListMap +#define i_key int +#define i_valclass StackList // "class" picks up _clone, _drop +#include + +#define i_type MapMap +#define i_key_str +#define i_valclass ListMap +#include + + +int main(void) +{ + MapMap mmap = {0}; + + // Put in some data in the structures + ListMap* lmap = &MapMap_emplace(&mmap, "first", ListMap_init()).ref->second; + StackList* list = &ListMap_insert(lmap, 42, StackList_init()).ref->second; + FloatStack* stack = StackList_push_back(list, FloatStack_with_size(10, 0)); + stack->data[3] = 3.1415927f; + printf("stack size: %" c_ZI "\n", FloatStack_size(stack)); + + // Access the data entry + const ListMap* lmap_p = MapMap_at(&mmap, "first"); + const StackList* list_p = ListMap_at(lmap_p, 42); + const FloatStack* stack_p = StackList_back(list_p); + printf("value is: %f\n", (double)*FloatStack_at(stack_p, 3)); // pi + + MapMap_drop(&mmap); +} diff --git a/misc/examples/mixed/convert.c b/misc/examples/mixed/convert.c new file mode 100644 index 00000000..fa64560e --- /dev/null +++ b/misc/examples/mixed/convert.c @@ -0,0 +1,57 @@ +#define i_implement +#include + +#define i_key_str +#define i_val_str +#include + +#define i_key_str +#include + +#define i_key_str +#include + +int main(void) +{ + cmap_str map, mclone; + cvec_str keys = {0}, values = {0}; + clist_str list = {0}; + + c_defer( + cmap_str_drop(&map), + cmap_str_drop(&mclone), + cvec_str_drop(&keys), + cvec_str_drop(&values), + clist_str_drop(&list) + ){ + map = c_init(cmap_str, { + {"green", "#00ff00"}, + {"blue", "#0000ff"}, + {"yellow", "#ffff00"}, + }); + + puts("MAP:"); + c_foreach (i, cmap_str, map) + printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); + + puts("\nCLONE MAP:"); + mclone = cmap_str_clone(map); + c_foreach (i, cmap_str, mclone) + printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); + + puts("\nCOPY MAP TO VECS:"); + c_foreach (i, cmap_str, mclone) { + cvec_str_emplace_back(&keys, cstr_str(&i.ref->first)); + cvec_str_emplace_back(&values, cstr_str(&i.ref->second)); + } + c_forrange (i, cvec_str_size(&keys)) + printf(" %s: %s\n", cstr_str(keys.data + i), cstr_str(values.data + i)); + + puts("\nCOPY VEC TO LIST:"); + c_foreach (i, cvec_str, keys) + clist_str_emplace_back(&list, cstr_str(i.ref)); + + c_foreach (i, clist_str, list) + printf(" %s\n", cstr_str(i.ref)); + } +} diff --git a/misc/examples/mixed/demos.c b/misc/examples/mixed/demos.c new file mode 100644 index 00000000..1a604d9f --- /dev/null +++ b/misc/examples/mixed/demos.c @@ -0,0 +1,194 @@ +#define i_implement +#include + +void stringdemo1(void) +{ + cstr cs = cstr_lit("one-nine-three-seven-five"); + printf("%s.\n", cstr_str(&cs)); + + cstr_insert(&cs, 3, "-two"); + printf("%s.\n", cstr_str(&cs)); + + cstr_erase(&cs, 7, 5); // -nine + printf("%s.\n", cstr_str(&cs)); + + cstr_replace(&cs, "seven", "four", 1); + printf("%s.\n", cstr_str(&cs)); + + cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs))); + printf("%s.\n", cstr_str(&cs)); + + printf("find \"four\": %s\n", cstr_str(&cs) + cstr_find(&cs, "four")); + + // reassign: + cstr_assign(&cs, "one two three four five six seven"); + cstr_append(&cs, " eight"); + printf("append: %s\n", cstr_str(&cs)); + + cstr_drop(&cs); +} + +#define i_key int64_t +#define i_tag ix +#include + +void vectordemo1(void) +{ + cvec_ix bignums = cvec_ix_with_capacity(100); + cvec_ix_reserve(&bignums, 100); + for (int i = 10; i <= 100; i += 10) + cvec_ix_push(&bignums, i * i); + + printf("erase - %d: %" PRIu64 "\n", 3, bignums.data[3]); + cvec_ix_erase_n(&bignums, 3, 1); // erase index 3 + + cvec_ix_pop(&bignums); // erase the last + cvec_ix_erase_n(&bignums, 0, 1); // erase the first + + for (int i = 0; i < cvec_ix_size(&bignums); ++i) { + printf("%d: %" PRIu64 "\n", i, bignums.data[i]); + } + + cvec_ix_drop(&bignums); +} + +#define i_key_str +#include + +void vectordemo2(void) +{ + cvec_str names = {0}; + cvec_str_emplace_back(&names, "Mary"); + cvec_str_emplace_back(&names, "Joe"); + cvec_str_emplace_back(&names, "Chris"); + cstr_assign(&names.data[1], "Jane"); // replace Joe + printf("names[1]: %s\n", cstr_str(&names.data[1])); + + cvec_str_sort(&names); // Sort the array + + c_foreach (i, cvec_str, names) + printf("sorted: %s\n", cstr_str(i.ref)); + + cvec_str_drop(&names); +} + +#define i_key int +#define i_tag ix +#define i_cmp_native +#include + +void listdemo1(void) +{ + clist_ix nums = {0}, nums2 = {0}; + for (int i = 0; i < 10; ++i) + clist_ix_push_back(&nums, i); + for (int i = 100; i < 110; ++i) + clist_ix_push_back(&nums2, i); + + /* splice nums2 to front of nums */ + clist_ix_splice(&nums, clist_ix_begin(&nums), &nums2); + c_foreach (i, clist_ix, nums) + printf("spliced: %d\n", *i.ref); + puts(""); + + *clist_ix_find(&nums, 104).ref += 50; + clist_ix_remove(&nums, 103); + clist_ix_iter it = clist_ix_begin(&nums); + clist_ix_erase_range(&nums, clist_ix_advance(it, 5), clist_ix_advance(it, 15)); + clist_ix_pop_front(&nums); + clist_ix_push_back(&nums, -99); + clist_ix_sort(&nums); + + c_foreach (i, clist_ix, nums) + printf("sorted: %d\n", *i.ref); + + c_drop(clist_ix, &nums, &nums2); +} + +#define i_key int +#define i_tag i +#include + +void setdemo1(void) +{ + cset_i nums = {0}; + cset_i_insert(&nums, 8); + cset_i_insert(&nums, 11); + + c_foreach (i, cset_i, nums) + printf("set: %d\n", *i.ref); + cset_i_drop(&nums); +} + +#define i_key int +#define i_val int +#define i_tag ii +#include + +void mapdemo1(void) +{ + cmap_ii nums = {0}; + cmap_ii_insert(&nums, 8, 64); + cmap_ii_insert(&nums, 11, 121); + printf("val 8: %d\n", *cmap_ii_at(&nums, 8)); + cmap_ii_drop(&nums); +} + +#define i_key_str +#define i_val int +#define i_tag si +#include + +void mapdemo2(void) +{ + cmap_si nums = {0}; + cmap_si_emplace_or_assign(&nums, "Hello", 64); + cmap_si_emplace_or_assign(&nums, "Groovy", 121); + cmap_si_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous + + // iterate the map: + for (cmap_si_iter i = cmap_si_begin(&nums); i.ref; cmap_si_next(&i)) + printf("long: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); + + // or rather use the short form: + c_foreach (i, cmap_si, nums) + printf("short: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); + + cmap_si_drop(&nums); +} + +#define i_key_str +#define i_val_str +#include + +void mapdemo3(void) +{ + cmap_str table = {0}; + cmap_str_emplace(&table, "Map", "test"); + cmap_str_emplace(&table, "Make", "my"); + cmap_str_emplace(&table, "Sunny", "day"); + cmap_str_iter it = cmap_str_find(&table, "Make"); + c_foreach (i, cmap_str, table) + printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); + printf("size %" c_ZI ": remove: Make: %s\n", cmap_str_size(&table), cstr_str(&it.ref->second)); + //cmap_str_erase(&table, "Make"); + cmap_str_erase_at(&table, it); + + printf("size %" c_ZI "\n", cmap_str_size(&table)); + c_foreach (i, cmap_str, table) + printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); + + cmap_str_drop(&table); // frees key and value cstrs, and hash table. +} + +int main(void) +{ + printf("\nSTRINGDEMO1\n"); stringdemo1(); + printf("\nVECTORDEMO1\n"); vectordemo1(); + printf("\nVECTORDEMO2\n"); vectordemo2(); + printf("\nLISTDEMO1\n"); listdemo1(); + printf("\nSETDEMO1\n"); setdemo1(); + printf("\nMAPDEMO1\n"); mapdemo1(); + printf("\nMAPDEMO2\n"); mapdemo2(); + printf("\nMAPDEMO3\n"); mapdemo3(); +} diff --git a/misc/examples/mixed/inits.c b/misc/examples/mixed/inits.c new file mode 100644 index 00000000..53a49f1f --- /dev/null +++ b/misc/examples/mixed/inits.c @@ -0,0 +1,108 @@ +#define i_implement +#include + +#define i_key int +#define i_val_str +#define i_tag id // Map of int => cstr +#include + +#define i_key_str +#define i_val int +#define i_tag cnt // Map of cstr => int +#include + +typedef struct {int x, y;} ipair_t; +inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) { + int c = c_default_cmp(&a->x, &b->x); + return c ? c : c_default_cmp(&a->y, &b->y); +} + + +#define i_key ipair_t +#define i_cmp ipair_cmp +#define i_tag ip +#include + +#define i_key ipair_t +#define i_cmp ipair_cmp +#define i_tag ip +#include + +#define i_key float +#define i_tag f +#include + +int main(void) +{ + // CVEC FLOAT / PRIORITY QUEUE + + cpque_f floats = {0}; + const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f}; + + // PRIORITY QUEUE + c_forrange (i, c_arraylen(nums)) + cpque_f_push(&floats, nums[i]); + + puts("\npop and show high priorites first:"); + while (! cpque_f_empty(&floats)) { + printf("%.1f ", (double)*cpque_f_top(&floats)); + cpque_f_pop(&floats); + } + puts("\n"); + cpque_f_drop(&floats); + + // CMAP ID + + int year = 2020; + cmap_id idnames = {0}; + cmap_id_emplace(&idnames, 100, "Hello"); + cmap_id_insert(&idnames, 110, cstr_lit("World")); + cmap_id_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year)); + + c_foreach (i, cmap_id, idnames) + printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second)); + puts(""); + cmap_id_drop(&idnames); + + // CMAP CNT + + cmap_cnt countries = c_init(cmap_cnt, { + {"Norway", 100}, + {"Denmark", 50}, + {"Iceland", 10}, + {"Belgium", 10}, + {"Italy", 10}, + {"Germany", 10}, + {"Spain", 10}, + {"France", 10}, + }); + cmap_cnt_emplace(&countries, "Greenland", 0).ref->second += 20; + cmap_cnt_emplace(&countries, "Sweden", 0).ref->second += 20; + cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20; + cmap_cnt_emplace(&countries, "Finland", 0).ref->second += 20; + + c_forpair (country, health, cmap_cnt, countries) + printf("%s: %d\n", cstr_str(_.country), *_.health); + puts(""); + cmap_cnt_drop(&countries); + + // CVEC PAIR + + cvec_ip pairs1 = c_init(cvec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); + cvec_ip_sort(&pairs1); + + c_foreach (i, cvec_ip, pairs1) + printf("(%d %d) ", i.ref->x, i.ref->y); + puts(""); + cvec_ip_drop(&pairs1); + + // CLIST PAIR + + clist_ip pairs2 = c_init(clist_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); + clist_ip_sort(&pairs2); + + c_foreach (i, clist_ip, pairs2) + printf("(%d %d) ", i.ref->x, i.ref->y); + puts(""); + clist_ip_drop(&pairs2); +} diff --git a/misc/examples/mixed/read.c b/misc/examples/mixed/read.c new file mode 100644 index 00000000..de04fd31 --- /dev/null +++ b/misc/examples/mixed/read.c @@ -0,0 +1,27 @@ +#define i_implement +#include +#include +#define i_key_str +#include +#include + +cvec_str read_file(const char* name) +{ + cvec_str vec = {0}; + c_with (FILE* f = fopen(name, "r"), fclose(f)) + c_with (cstr line = {0}, cstr_drop(&line)) + while (cstr_getline(&line, f)) + cvec_str_push(&vec, cstr_clone(line)); + return vec; +} + +int main(void) +{ + int n = 0; + c_with (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec)) + c_foreach (i, cvec_str, vec) + printf("%5d: %s\n", ++n, cstr_str(i.ref)); + + if (errno) + printf("error: read_file(" __FILE__ "). errno: %d\n", errno); +} diff --git a/misc/examples/mmap.c b/misc/examples/mmap.c deleted file mode 100644 index 04a605a7..00000000 --- a/misc/examples/mmap.c +++ /dev/null @@ -1,65 +0,0 @@ -// This implements the multimap c++ example found at: -// https://en.cppreference.com/w/cpp/container/multimap/insert - -// Multimap entries -#define i_implement -#include -#define i_key_str -#include - -// Map of int => clist_str. -#define i_type Multimap -#define i_key int -#define i_valclass clist_str // set i_val = clist_str, bind clist_str_clone and clist_str_drop -#define i_cmp -c_default_cmp // like std::greater -#include - -void print(const char* lbl, const Multimap mmap) -{ - printf("%s ", lbl); - c_foreach (e, Multimap, mmap) { - c_foreach (s, clist_str, e.ref->second) - printf("{%d,%s} ", e.ref->first, cstr_str(s.ref)); - } - puts(""); -} - -void insert(Multimap* mmap, int key, const char* str) -{ - clist_str *list = &Multimap_insert(mmap, key, clist_str_init()).ref->second; - clist_str_emplace_back(list, str); -} - -int main(void) -{ - Multimap mmap = {0}; - - // list-initialize - typedef struct {int a; const char* b;} pair; - c_forlist (i, pair, {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}}) - insert(&mmap, i.ref->a, i.ref->b); - print("#1", mmap); - - // insert using value_type - insert(&mmap, 5, "pqr"); - print("#2", mmap); - - // insert using make_pair - insert(&mmap, 6, "uvw"); - print("#3", mmap); - - insert(&mmap, 7, "xyz"); - print("#4", mmap); - - // insert using initialization_list - c_forlist (i, pair, {{5, "one"}, {5, "two"}}) - insert(&mmap, i.ref->a, i.ref->b); - print("#5", mmap); - - // FOLLOWING NOT IN ORIGINAL EXAMPLE: - // erase all entries with key 5 - Multimap_erase(&mmap, 5); - print("+5", mmap); - - Multimap_drop(&mmap); -} diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c deleted file mode 100644 index 798a1126..00000000 --- a/misc/examples/multidim.c +++ /dev/null @@ -1,67 +0,0 @@ -// Example based on https://en.cppreference.com/w/cpp/container/mdspan -#define i_val int -#include -#include -#include - -using_cspan3(ispan, int); - -int main(void) -{ - cstack_int v = c_init(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}); - - // View data as contiguous memory representing 24 ints - ispan ms1 = cspan_from(&v); - - // View the same data as a 3D array 2 x 3 x 4 - ispan3 ms3 = cspan_md(v.data, 2, 3, 4); - - puts("ms3:"); - for (int i=0; i != ms3.shape[0]; i++) { - for (int j=0; j != ms3.shape[1]; j++) { - for (int k=0; k != ms3.shape[2]; k++) { - printf(" %2d", *cspan_at(&ms3, i, j, k)); - } - puts(""); - } - puts(""); - } - puts("ss3 = ms3[:, 1:3, 1:3]"); - ispan3 ss3 = ms3; - ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3}); - - for (int i=0; i != ss3.shape[0]; i++) { - for (int j=0; j != ss3.shape[1]; j++) { - for (int k=0; k != ss3.shape[2]; k++) { - printf(" %2d", *cspan_at(&ss3, i, j, k)); - } - puts(""); - } - puts(""); - } - - puts("Iterate ss3 flat:"); - c_foreach (i, ispan3, ss3) - printf(" %d", *i.ref); - puts(""); - - ispan2 ms2 = cspan_submd3(&ms3, 0); - - // write data using 2D view - for (int i=0; i != ms2.shape[0]; i++) - for (int j=0; j != ms2.shape[1]; j++) - *cspan_at(&ms2, i, j) = i*1000 + j; - - puts("\nview data as 1D view:"); - for (int i=0; i != cspan_size(&ms1); i++) - printf(" %d", *cspan_at(&ms1, i)); - puts(""); - - puts("iterate subspan ms3[1]:"); - ispan2 sub = cspan_submd3(&ms3, 1); - c_foreach (i, ispan2, sub) - printf(" %d", *i.ref); - puts(""); - - cstack_int_drop(&v); -} diff --git a/misc/examples/multimap.c b/misc/examples/multimap.c deleted file mode 100644 index 1068a5dc..00000000 --- a/misc/examples/multimap.c +++ /dev/null @@ -1,102 +0,0 @@ -#define i_implement -#include - -// Olympics multimap example - -struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = { - {2026, "Milan and Cortina d'Ampezzo", "Italy", "February 6-22"}, - {2022, "Beijing", "China", "February 4-20"}, - {2018, "PyeongChang", "South Korea", "February 9-25"}, - {2014, "Sochi", "Russia", "February 7-23"}, - {2010, "Vancouver", "Canada", "February 12-28"}, - {2006, "Torino", "Italy", "February 10-26"}, - {2002, "Salt Lake City", "United States", "February 8-24"}, - {1998, "Nagano", "Japan", "February 7-22"}, - {1994, "Lillehammer", "Norway", "February 12-27"}, - {1992, "Albertville", "France", "February 8-23"}, - {1988, "Calgary", "Canada", "February 13-28"}, - {1984, "Sarajevo", "Yugoslavia", "February 8-19"}, - {1980, "Lake Placid", "United States", "February 13-24"}, - {1976, "Innsbruck", "Austria", "February 4-15"}, - {1972, "Sapporo", "Japan", "February 3-13"}, - {1968, "Grenoble", "France", "February 6-18"}, - {1964, "Innsbruck", "Austria", "January 29-February 9"}, - {1960, "Squaw Valley", "United States", "February 18-28"}, - {1956, "Cortina d'Ampezzo", "Italy", "January 26 - February 5"}, - {1952, "Oslo", "Norway", "February 14 - 25"}, - {1948, "St. Moritz", "Switzerland", "January 30 - February 8"}, - {1944, "canceled", "canceled", "canceled"}, - {1940, "canceled", "canceled", "canceled"}, - {1936, "Garmisch-Partenkirchen", "Germany", "February 6 - 16"}, - {1932, "Lake Placid", "United States", "February 4 - 15"}, - {1928, "St. Moritz", "Switzerland", "February 11 - 19"}, - {1924, "Chamonix", "France", "January 25 - February 5"}, -}; - -typedef struct { int year; cstr city, date; } OlympicLoc; - -int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b); -OlympicLoc OlympicLoc_clone(OlympicLoc loc); -void OlympicLoc_drop(OlympicLoc* self); - -// Create a clist, can be sorted by year. -#define i_keyclass OlympicLoc // binds _cmp, _clone and _drop. -#define i_tag OL -#include - -// Create a csmap where key is country name -#define i_key_str // binds cstr_equ, cstr_hash, cstr_clone, ++ -#define i_valclass clist_OL // binds clist_OL_clone, clist_OL_drop -#define i_tag OL -#include - -int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b) { - return a->year - b->year; -} - -OlympicLoc OlympicLoc_clone(OlympicLoc loc) { - loc.city = cstr_clone(loc.city); - loc.date = cstr_clone(loc.date); - return loc; -} - -void OlympicLoc_drop(OlympicLoc* self) { - cstr_drop(&self->city); - cstr_drop(&self->date); -} - - -int main(void) -{ - // Define the multimap with destructor defered to when block is completed. - csmap_OL multimap = {0}; - const clist_OL empty = clist_OL_init(); - - for (size_t i = 0; i < c_arraylen(ol_data); ++i) - { - struct OlympicsData* d = &ol_data[i]; - OlympicLoc loc = {.year = d->year, - .city = cstr_from(d->city), - .date = cstr_from(d->date)}; - // Insert an empty list for each new country, and append the entry to the list. - // If country already exist in map, its list is returned from the insert function. - clist_OL* list = &csmap_OL_emplace(&multimap, d->country, empty).ref->second; - clist_OL_push_back(list, loc); - } - - // Sort locations by year for each country. - c_foreach (country, csmap_OL, multimap) - clist_OL_sort(&country.ref->second); - - // Print the multimap: - c_foreach (country, csmap_OL, multimap) - { - // Loop the locations for a country sorted by year - c_foreach (loc, clist_OL, country.ref->second) - printf("%s: %d, %s, %s\n", cstr_str(&country.ref->first), - loc.ref->year, - cstr_str(&loc.ref->city), - cstr_str(&loc.ref->date)); - } - csmap_OL_drop(&multimap); -} diff --git a/misc/examples/music_arc.c b/misc/examples/music_arc.c deleted file mode 100644 index 16111b0b..00000000 --- a/misc/examples/music_arc.c +++ /dev/null @@ -1,67 +0,0 @@ -// shared_ptr-examples.cpp -// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 -#define i_implement -#include - -typedef struct -{ - cstr artist; - cstr title; -} Song; - -int Song_cmp(const Song* x, const Song* y) - { return cstr_cmp(&x->title, &y->title); } - -Song Song_make(const char* artist, const char* title) - { return c_LITERAL(Song){cstr_from(artist), cstr_from(title)}; } - -void Song_drop(Song* s) { - printf("drop: %s\n", cstr_str(&s->title)); - c_drop(cstr, &s->artist, &s->title); -} - -// Define the shared pointer: -#define i_type SongArc -#define i_keyclass Song -#define i_no_hash // no hash fn for Song, fallback hash pointer to Song. -#include - -// ... and a vector of them -#define i_type SongVec -#define i_keyboxed SongArc // use i_keyboxed on carc / cbox (instead of i_key) -#include - -void example3(void) -{ - SongVec vec1 = c_init(SongVec, { - Song_make("Bob Dylan", "The Times They Are A Changing"), - Song_make("Aretha Franklin", "Bridge Over Troubled Water"), - Song_make("Thalia", "Entre El Mar y Una Estrella") - }); - - SongVec vec2 = {0}; - // Share all entries in vec with vec2, except Bob Dylan. - c_foreach (s, SongVec, vec1) - if (!cstr_equals(&s.ref->get->artist, "Bob Dylan")) - SongVec_push(&vec2, SongArc_clone(*s.ref)); - - // Add a few more to vec2. We can use emplace when creating new entries - // Emplace calls SongArc_from() on the argument to create the Arc: - SongVec_emplace(&vec2, Song_make("Michael Jackson", "Billie Jean")); - SongVec_emplace(&vec2, Song_make("Rihanna", "Stay")); - - // We now have two vectors with some shared, some unique entries. - c_forlist (i, SongVec, {vec1, vec2}) { - puts("VEC:"); - c_foreach (s, SongVec, *i.ref) - printf(" %s - %s, REFS: %ld\n", cstr_str(&s.ref->get->artist), - cstr_str(&s.ref->get->title), - *s.ref->use_count); - } - c_drop(SongVec, &vec1, &vec2); -} - -int main(void) -{ - example3(); -} diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c deleted file mode 100644 index 2112bf1f..00000000 --- a/misc/examples/new_list.c +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include - -forward_clist(clist_i32, int); -forward_clist(clist_pnt, struct Point); - -typedef struct { - clist_i32 intlist; - clist_pnt pntlist; -} MyStruct; - -#define i_key int -#define i_tag i32 -#define i_is_forward -#include - -typedef struct Point { int x, y; } Point; -int point_cmp(const Point* a, const Point* b) { - int c = a->x - b->x; - return c ? c : a->y - b->y; -} - -#define i_key Point -#define i_cmp point_cmp -#define i_is_forward -#define i_tag pnt -#include - -#define i_key float -#define i_cmp_native // use < and == operators for comparison -#include - -void MyStruct_drop(MyStruct* s); -#define i_type MyList -#define i_key MyStruct -#define i_keydrop MyStruct_drop // define drop function -#define i_no_clone // must explicitely exclude or define cloning support because of drop. -#include - -void MyStruct_drop(MyStruct* s) { - clist_i32_drop(&s->intlist); - clist_pnt_drop(&s->pntlist); -} - - -int main(void) -{ - MyStruct my = {0}; - clist_i32_push_back(&my.intlist, 123); - clist_pnt_push_back(&my.pntlist, c_LITERAL(Point){123, 456}); - MyStruct_drop(&my); - - clist_pnt plist = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); - clist_pnt_sort(&plist); - - c_foreach (i, clist_pnt, plist) - printf(" (%d %d)", i.ref->x, i.ref->y); - puts(""); - clist_pnt_drop(&plist); - - - clist_float flist = c_init(clist_float, {123.3f, 321.2f, -32.2f, 78.2f}); - clist_float_sort(&flist); - - c_foreach (i, clist_float, flist) - printf(" %g", (double)*i.ref); - - puts(""); - clist_float_drop(&flist); -} diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c deleted file mode 100644 index de990040..00000000 --- a/misc/examples/new_map.c +++ /dev/null @@ -1,75 +0,0 @@ -#define i_implement -#include -#include - -forward_cmap(cmap_pnt, struct Point, int); - -typedef struct MyStruct { - cmap_pnt pntmap; - cstr name; -} MyStruct; - -// int => int map -#define i_key int -#define i_val int -#include - -// Point => int map -typedef struct Point { int x, y; } Point; - -int point_cmp(const Point* a, const Point* b) { - int c = a->x - b->x; - return c ? c : a->y - b->y; -} - -// Point => int map -#define i_key Point -#define i_val int -#define i_cmp point_cmp -#define i_hash c_default_hash -#define i_is_forward -#define i_tag pnt -#include - -// cstr => cstr map -#define i_key_str -#define i_val_str -#include - -// string set -#define i_key_str -#include - - -int main(void) -{ - cmap_pnt pmap = c_init(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}}); - - c_foreach (i, cmap_pnt, pmap) - printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second); - puts(""); - - cmap_str smap = c_init(cmap_str, { - {"Hello, friend", "long time no see"}, - {"So long", "see you around"}, - }); - - cset_str sset = c_init(cset_str, { - "Hello, friend", - "Nice to see you again", - "So long", - }); - - cmap_int map = {0}; - cmap_int_insert(&map, 123, 321); - cmap_int_insert(&map, 456, 654); - cmap_int_insert(&map, 789, 987); - - c_foreach (i, cset_str, sset) - printf(" %s\n", cstr_str(i.ref)); - - cmap_int_drop(&map); - cset_str_drop(&sset); - cmap_str_drop(&smap); - cmap_pnt_drop(&pmap); -} diff --git a/misc/examples/new_pque.c b/misc/examples/new_pque.c deleted file mode 100644 index 16823bb6..00000000 --- a/misc/examples/new_pque.c +++ /dev/null @@ -1,22 +0,0 @@ -#include - -typedef struct Point { int x, y; } Point; - -#define i_type PointQ -#define i_key Point -#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) -#include - - -int main(void) -{ - PointQ pque = c_init(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}}); - // print - for (; !PointQ_empty(&pque); PointQ_pop(&pque)) - { - const Point *v = PointQ_top(&pque); - printf(" (%d,%d)", v->x, v->y); - } - puts(""); - PointQ_drop(&pque); -} diff --git a/misc/examples/new_queue.c b/misc/examples/new_queue.c deleted file mode 100644 index f3592df6..00000000 --- a/misc/examples/new_queue.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include -#include - -forward_cqueue(cqueue_pnt, struct Point); - -typedef struct Point { int x, y; } Point; -int point_cmp(const Point* a, const Point* b) { - int c = c_default_cmp(&a->x, &b->x); - return c ? c : c_default_cmp(&a->y, &b->y); -} -#define i_key Point -#define i_cmp point_cmp -#define i_is_forward -#define i_tag pnt -#include - -#define i_type IQ -#define i_key int -#include - -int main(void) { - int n = 50000000; - crand_t rng = crand_init((uint64_t)time(NULL)); - crand_unif_t dist = crand_unif_init(0, n); - - IQ Q = {0}; - - // Push 50'000'000 random numbers onto the queue. - c_forrange (n) - IQ_push(&Q, (int)crand_unif(&rng, &dist)); - - // Push or pop on the queue 50 million times - printf("befor: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q)); - - c_forrange (n) { - int r = (int)crand_unif(&rng, &dist); - if (r & 3) - IQ_push(&Q, r); - else - IQ_pop(&Q); - } - - printf("after: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q)); - IQ_drop(&Q); -} diff --git a/misc/examples/new_smap.c b/misc/examples/new_smap.c deleted file mode 100644 index ee946c9a..00000000 --- a/misc/examples/new_smap.c +++ /dev/null @@ -1,67 +0,0 @@ -#define i_implement -#include -#include - -forward_csmap(PMap, struct Point, int); - -// Use forward declared PMap in struct -typedef struct { - PMap pntmap; - cstr name; -} MyStruct; - -// Point => int map -typedef struct Point { int x, y; } Point; -int point_cmp(const Point* a, const Point* b) { - int c = a->x - b->x; - return c ? c : a->y - b->y; -} - -#define i_type PMap -#define i_key Point -#define i_val int -#define i_cmp point_cmp -#define i_is_forward -#include - -// cstr => cstr map -#define i_type SMap -#define i_key_str -#define i_val_str -#include - -// cstr set -#define i_type SSet -#define i_key_str -#include - - -int main(void) -{ - PMap pmap = c_init(PMap, { - {{42, 14}, 1}, - {{32, 94}, 2}, - {{62, 81}, 3}, - }); - SMap smap = c_init(SMap, { - {"Hello, friend", "this is the mapped value"}, - {"The brown fox", "jumped"}, - {"This is the time", "for all good things"}, - }); - SSet sset = {0}; - - c_forpair (p, i, PMap, pmap) - printf(" (%d,%d: %d)", _.p->x, _.p->y, *_.i); - puts(""); - - c_forpair (i, j, SMap, smap) - printf(" (%s: %s)\n", cstr_str(_.i), cstr_str(_.j)); - - SSet_emplace(&sset, "Hello, friend"); - SSet_emplace(&sset, "Goodbye, foe"); - printf("Found? %s\n", SSet_contains(&sset, "Hello, friend") ? "true" : "false"); - - PMap_drop(&pmap); - SMap_drop(&smap); - SSet_drop(&sset); -} diff --git a/misc/examples/new_sptr.c b/misc/examples/new_sptr.c deleted file mode 100644 index 3c6fa16c..00000000 --- a/misc/examples/new_sptr.c +++ /dev/null @@ -1,75 +0,0 @@ -#define i_implement -#include - -typedef struct { cstr name, last; } Person; -Person Person_make(const char* name, const char* last); -Person Person_clone(Person p); -void Person_drop(Person* p); -int Person_cmp(const Person* a, const Person* b); -uint64_t Person_hash(const Person* p); - -#define i_type PersonArc -#define i_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined. -#include - -#define i_type IPtr -#define i_key int -#define i_keydrop(x) printf("drop: %d\n", *x) -#define i_cmp_native -#include - -#define i_type IPStack -#define i_keyboxed IPtr -#include - -#define i_type PASet -#define i_keyboxed PersonArc -#include - - -Person Person_make(const char* name, const char* last) { - Person p = {.name = cstr_from(name), .last = cstr_from(last)}; - return p; -} - -int Person_cmp(const Person* a, const Person* b) { - return cstr_cmp(&a->name, &b->name); -} - -uint64_t Person_hash(const Person* p) { - return cstr_hash(&p->name); -} - -Person Person_clone(Person p) { - p.name = cstr_clone(p.name), p.last = cstr_clone(p.last); - return p; -} - -void Person_drop(Person* p) { - printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); - c_drop(cstr, &p->name, &p->last); -} - - -int main(void) { - puts("Ex1"); - PersonArc p = PersonArc_from(Person_make("John", "Smiths")); - PersonArc q = PersonArc_clone(p); // share - PersonArc r = PersonArc_clone(p); - PersonArc s = PersonArc_from(Person_clone(*p.get)); // deep copy - printf("%s %s: refs %ld\n", cstr_str(&p.get->name), cstr_str(&p.get->last), *p.use_count); - c_drop(PersonArc, &p, &q, &r, &s); - - puts("Ex2"); - IPStack vec = {0}; - IPStack_push(&vec, IPtr_from(10)); - IPStack_push(&vec, IPtr_from(20)); - IPStack_emplace(&vec, 30); // same as IPStack_push(&vec, IPtr_from(30)); - IPStack_push(&vec, IPtr_clone(*IPStack_back(&vec))); - IPStack_push(&vec, IPtr_clone(*IPStack_front(&vec))); - - c_foreach (i, IPStack, vec) - printf(" (%d: refs %ld)", *i.ref->get, *i.ref->use_count); - puts(""); - IPStack_drop(&vec); -} diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c deleted file mode 100644 index 88efd55a..00000000 --- a/misc/examples/new_vec.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include - -forward_cvec(cvec_i32, int); -forward_cvec(cvec_pnt, struct Point); - -typedef struct MyStruct { - cvec_i32 intvec; - cvec_pnt pntvec; -} MyStruct; - -#define i_key int -#define i_tag i32 -#define i_is_forward -#include - -typedef struct Point { int x, y; } Point; - -#define i_key Point -#define i_tag pnt -#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) -#define i_eq(a, b) a->x == b->x && a->y == b->y -#define i_is_forward -#include - -int main(void) -{ - MyStruct my = {0}; - - cvec_pnt_push(&my.pntvec, c_LITERAL(Point){42, 14}); - cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 94}); - cvec_pnt_push(&my.pntvec, c_LITERAL(Point){62, 81}); - cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 91}); - - cvec_pnt_sort(&my.pntvec); - - c_foreach (i, cvec_pnt, my.pntvec) - printf(" (%d %d)", i.ref->x, i.ref->y); - puts(""); - - cvec_i32_drop(&my.intvec); - cvec_pnt_drop(&my.pntvec); -} diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c deleted file mode 100644 index 38c883a7..00000000 --- a/misc/examples/person_arc.c +++ /dev/null @@ -1,77 +0,0 @@ -/* cbox: heap allocated boxed type */ -#define i_implement -#include - -typedef struct { cstr name, last; } Person; - -Person Person_make(const char* name, const char* last) { - Person p = {.name = cstr_from(name), .last = cstr_from(last)}; - return p; -} - -int Person_cmp(const Person* a, const Person* b) { - int c = cstr_cmp(&a->name, &b->name); - return c ? c : cstr_cmp(&a->last, &b->last); -} - -uint64_t Person_hash(const Person* a) { - return cstr_hash(&a->name) ^ cstr_hash(&a->last); -} - -Person Person_clone(Person p) { - p.name = cstr_clone(p.name); - p.last = cstr_clone(p.last); - return p; -} - -void Person_drop(Person* p) { - printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); - c_drop(cstr, &p->name, &p->last); -} - -#define i_type PSPtr -#define i_keyclass Person // ensure Person_drop -#define i_cmp Person_cmp // specify object cmp, instead of ptr cmp for arc. -#include - -#define i_type Persons -#define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop... -#include - - -int main(void) -{ - PSPtr p = PSPtr_from(Person_make("Laura", "Palmer")); - PSPtr q = PSPtr_from(Person_clone(*p.get)); // deep copy - Persons vec = {0}; - - c_defer( - PSPtr_drop(&p), - PSPtr_drop(&q), - Persons_drop(&vec) - ){ - cstr_assign(&q.get->name, "Leland"); - - printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); - printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); - - // Use Persons_emplace to implicitly call PSPtr_make on the argument. - // No need to do: Persons_push(&vec, PSPtr_make(Person_make("Audrey", "Home"))); - Persons_emplace(&vec, Person_make("Audrey", "Home")); - Persons_emplace(&vec, Person_make("Dale", "Cooper")); - - // Clone/share p and q to the vector - c_forlist (i, PSPtr, {p, q}) - Persons_push(&vec, PSPtr_clone(*i.ref)); - - c_foreach (i, Persons, vec) - printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); - puts(""); - - // Look-up Audrey! - Person a = Person_make("Audrey", "Home"); - const PSPtr *v = Persons_get(&vec, a); - if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); - Person_drop(&a); - } -} diff --git a/misc/examples/phonebook.c b/misc/examples/phonebook.c deleted file mode 100644 index faf7566e..00000000 --- a/misc/examples/phonebook.c +++ /dev/null @@ -1,72 +0,0 @@ -// The MIT License (MIT) -// Copyright (c) 2018 Maksim Andrianov -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -// Program to emulates the phone book. -#define i_implement -#include - -#define i_key_str -#define i_val_str -#include - -#define i_key_str -#include - -void print_phone_book(cmap_str phone_book) -{ - c_foreach (i, cmap_str, phone_book) - printf("%s\t- %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); -} - -int main(int argc, char **argv) -{ - cmap_str phone_book = c_init(cmap_str, { - {"Lilia Friedman", "(892) 670-4739"}, - {"Tariq Beltran", "(489) 600-7575"}, - {"Laiba Juarez", "(303) 885-5692"}, - {"Elliott Mooney", "(945) 616-4482"}, - }); - - printf("Phone book:\n"); - print_phone_book(phone_book); - - cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1880"); - cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1990"); - - printf("\nPhone book after adding Zak Byers:\n"); - print_phone_book(phone_book); - - if (cmap_str_contains(&phone_book, "Tariq Beltran")) - printf("\nTariq Beltran is in phone book\n"); - - cmap_str_erase(&phone_book, "Tariq Beltran"); - cmap_str_erase(&phone_book, "Elliott Mooney"); - - printf("\nPhone book after erasing Tariq and Elliott:\n"); - print_phone_book(phone_book); - - cmap_str_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188"); - - printf("\nPhone book after update phone of Zak Byers:\n"); - print_phone_book(phone_book); - - cmap_str_drop(&phone_book); -} diff --git a/misc/examples/prime.c b/misc/examples/prime.c deleted file mode 100644 index cb3b095a..00000000 --- a/misc/examples/prime.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include -#include -#include - - -cbits sieveOfEratosthenes(int64_t n) -{ - cbits bits = cbits_with_size(n/2 + 1, true); - int64_t q = (int64_t)sqrt((double) n) + 1; - for (int64_t i = 3; i < q; i += 2) { - int64_t j = i; - for (; j < n; j += 2) { - if (cbits_test(&bits, j>>1)) { - i = j; - break; - } - } - for (int64_t j = i*i; j < n; j += i*2) - cbits_reset(&bits, j>>1); - } - return bits; -} - -int main(void) -{ - int n = 1000000000; - printf("Computing prime numbers up to %d\n", n); - - clock_t t = clock(); - cbits primes = sieveOfEratosthenes(n + 1); - int np = (int)cbits_count(&primes); - t = clock() - t; - - puts("Show all the primes in the range [2, 1000):"); - printf("2"); - c_forrange (i, 3, 1000, 2) - if (cbits_test(&primes, i>>1)) printf(" %lld", i); - puts("\n"); - - puts("Show the last 50 primes using a temporary crange generator:"); - crange range = crange_make(n - 1, 0, -2); - - c_forfilter (i, crange, range, - cbits_test(&primes, *i.ref/2) && - c_flt_take(i, 50) - ){ - printf("%lld ", *i.ref); - if (c_flt_getcount(i) % 10 == 0) puts(""); - } - printf("Number of primes: %d, time: %.2f\n\n", np, (double)t/CLOCKS_PER_SEC); - - cbits_drop(&primes); -} diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c deleted file mode 100644 index cd3c5f4f..00000000 --- a/misc/examples/printspan.c +++ /dev/null @@ -1,52 +0,0 @@ -// printspan.c - -#include -#define i_implement -#include -#define i_key int -#include -#define i_key int -#include -#define i_key_str -#include - -#include -using_cspan(intspan, int, 1); - -void printMe(intspan container) { - printf("%d:", (int)cspan_size(&container)); - c_foreach (e, intspan, container) - printf(" %d", *e.ref); - puts(""); -} - -int main(void) -{ - intspan sp1 = cspan_init(intspan, {1, 2}); - printMe( sp1 ); - - printMe( c_init(intspan, {1, 2, 3}) ); - - int arr[] = {1, 2, 3, 4, 5, 6}; - intspan sp2 = cspan_from_array(arr); - printMe( c_LITERAL(intspan)cspan_subspan(&sp2, 1, 4) ); - - cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5}); - printMe( c_LITERAL(intspan)cspan_from(&vec) ); - - printMe( sp2 ); - - cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7}); - printMe( c_LITERAL(intspan)cspan_from(&stk) ); - - csset_str set = c_init(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); - printf("%d:", (int)csset_str_size(&set)); - c_foreach (e, csset_str, set) - printf(" %s", cstr_str(e.ref)); - puts(""); - - // cleanup - cvec_int_drop(&vec); - cstack_int_drop(&stk); - csset_str_drop(&set); -} diff --git a/misc/examples/priority.c b/misc/examples/priority.c deleted file mode 100644 index bf2e188a..00000000 --- a/misc/examples/priority.c +++ /dev/null @@ -1,37 +0,0 @@ - -#include -#include -#include - -#define i_key int64_t -#define i_cmp -c_default_cmp // min-heap (increasing values) -#define i_tag i -#include - -int main(void) { - intptr_t N = 10000000; - crand_t rng = crand_init((uint64_t)time(NULL)); - crand_unif_t dist = crand_unif_init(0, N * 10); - - cpque_i heap = {0}; - - // Push ten million random numbers to priority queue - printf("Push %" c_ZI " numbers\n", N); - c_forrange (N) - cpque_i_push(&heap, crand_unif(&rng, &dist)); - - // push some negative numbers too. - c_forlist (i, int, {-231, -32, -873, -4, -343}) - cpque_i_push(&heap, *i.ref); - - c_forrange (N) - cpque_i_push(&heap, crand_unif(&rng, &dist)); - - puts("Extract the hundred smallest."); - c_forrange (100) { - printf("%" PRId64 " ", *cpque_i_top(&heap)); - cpque_i_pop(&heap); - } - - cpque_i_drop(&heap); -} diff --git a/misc/examples/priorityqueues/functor.c b/misc/examples/priorityqueues/functor.c new file mode 100644 index 00000000..e3bde1dd --- /dev/null +++ b/misc/examples/priorityqueues/functor.c @@ -0,0 +1,57 @@ +// Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue +// Example of per-instance less-function on a single priority queue type +// + +#include + +#define i_type IPQue +#define i_base cpque +#define i_key int +#define i_extend bool(*less)(const int*, const int*); +#define i_less(x, y) c_extend()->less(x, y) +// Note: i_less: c_extend() accessible for cpque types +// i_cmp: c_extend() accessible for csmap and csset types +// i_hash/i_eq: c_extend() accessible for cmap and cset types +#include + +void print_queue(const char* name, IPQue_ext q) { + // NB: make a clone because there is no way to traverse + // priority queue's content without erasing the queue. + IPQue_ext copy = {q.less, IPQue_clone(q.get)}; + + for (printf("%s: \t", name); !IPQue_empty(©.get); IPQue_pop(©.get)) + printf("%d ", *IPQue_top(©.get)); + puts(""); + + IPQue_drop(©.get); +} + +static bool int_less(const int* x, const int* y) { return *x < *y; } +static bool int_greater(const int* x, const int* y) { return *x > *y; } +static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); } + +int main(void) +{ + const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_arraylen(data); + printf("data: \t"); + c_forrange (i, n) printf("%d ", data[i]); + puts(""); + + + // Max priority queue + IPQue_ext q1 = {.less=int_less}; + IPQue_put_n(&q1.get, data, n); + print_queue("q1", q1); + + // Min priority queue + IPQue_ext minq1 = {.less=int_greater}; + IPQue_put_n(&minq1.get, data, n); + print_queue("minq1", minq1); + + // Using lambda to compare elements. + IPQue_ext q5 = {.less=int_lambda}; + IPQue_put_n(&q5.get, data, n); + print_queue("q5", q5); + + c_drop(IPQue, &q1.get, &minq1.get, &q5.get); +} diff --git a/misc/examples/priorityqueues/new_pque.c b/misc/examples/priorityqueues/new_pque.c new file mode 100644 index 00000000..16823bb6 --- /dev/null +++ b/misc/examples/priorityqueues/new_pque.c @@ -0,0 +1,22 @@ +#include + +typedef struct Point { int x, y; } Point; + +#define i_type PointQ +#define i_key Point +#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) +#include + + +int main(void) +{ + PointQ pque = c_init(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}}); + // print + for (; !PointQ_empty(&pque); PointQ_pop(&pque)) + { + const Point *v = PointQ_top(&pque); + printf(" (%d,%d)", v->x, v->y); + } + puts(""); + PointQ_drop(&pque); +} diff --git a/misc/examples/priorityqueues/priority.c b/misc/examples/priorityqueues/priority.c new file mode 100644 index 00000000..bf2e188a --- /dev/null +++ b/misc/examples/priorityqueues/priority.c @@ -0,0 +1,37 @@ + +#include +#include +#include + +#define i_key int64_t +#define i_cmp -c_default_cmp // min-heap (increasing values) +#define i_tag i +#include + +int main(void) { + intptr_t N = 10000000; + crand_t rng = crand_init((uint64_t)time(NULL)); + crand_unif_t dist = crand_unif_init(0, N * 10); + + cpque_i heap = {0}; + + // Push ten million random numbers to priority queue + printf("Push %" c_ZI " numbers\n", N); + c_forrange (N) + cpque_i_push(&heap, crand_unif(&rng, &dist)); + + // push some negative numbers too. + c_forlist (i, int, {-231, -32, -873, -4, -343}) + cpque_i_push(&heap, *i.ref); + + c_forrange (N) + cpque_i_push(&heap, crand_unif(&rng, &dist)); + + puts("Extract the hundred smallest."); + c_forrange (100) { + printf("%" PRId64 " ", *cpque_i_top(&heap)); + cpque_i_pop(&heap); + } + + cpque_i_drop(&heap); +} diff --git a/misc/examples/queue.c b/misc/examples/queue.c deleted file mode 100644 index 56b5beb9..00000000 --- a/misc/examples/queue.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -#define i_key int -#define i_tag i -#include - -int main(void) { - int n = 100000000; - crand_unif_t dist; - crand_t rng = crand_init(1234); - dist = crand_unif_init(0, n); - - cqueue_i queue = {0}; - - // Push ten million random numbers onto the queue. - c_forrange (n) - cqueue_i_push(&queue, (int)crand_unif(&rng, &dist)); - - // Push or pop on the queue ten million times - printf("%d\n", n); - c_forrange (n) { // forrange uses initial n only. - int r = (int)crand_unif(&rng, &dist); - if (r & 1) - ++n, cqueue_i_push(&queue, r); - else - --n, cqueue_i_pop(&queue); - } - printf("%d, %" c_ZI "\n", n, cqueue_i_size(&queue)); - - cqueue_i_drop(&queue); -} diff --git a/misc/examples/queues/new_queue.c b/misc/examples/queues/new_queue.c new file mode 100644 index 00000000..f3592df6 --- /dev/null +++ b/misc/examples/queues/new_queue.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +forward_cqueue(cqueue_pnt, struct Point); + +typedef struct Point { int x, y; } Point; +int point_cmp(const Point* a, const Point* b) { + int c = c_default_cmp(&a->x, &b->x); + return c ? c : c_default_cmp(&a->y, &b->y); +} +#define i_key Point +#define i_cmp point_cmp +#define i_is_forward +#define i_tag pnt +#include + +#define i_type IQ +#define i_key int +#include + +int main(void) { + int n = 50000000; + crand_t rng = crand_init((uint64_t)time(NULL)); + crand_unif_t dist = crand_unif_init(0, n); + + IQ Q = {0}; + + // Push 50'000'000 random numbers onto the queue. + c_forrange (n) + IQ_push(&Q, (int)crand_unif(&rng, &dist)); + + // Push or pop on the queue 50 million times + printf("befor: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q)); + + c_forrange (n) { + int r = (int)crand_unif(&rng, &dist); + if (r & 3) + IQ_push(&Q, r); + else + IQ_pop(&Q); + } + + printf("after: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q)); + IQ_drop(&Q); +} diff --git a/misc/examples/queues/queue.c b/misc/examples/queues/queue.c new file mode 100644 index 00000000..56b5beb9 --- /dev/null +++ b/misc/examples/queues/queue.c @@ -0,0 +1,32 @@ +#include +#include + +#define i_key int +#define i_tag i +#include + +int main(void) { + int n = 100000000; + crand_unif_t dist; + crand_t rng = crand_init(1234); + dist = crand_unif_init(0, n); + + cqueue_i queue = {0}; + + // Push ten million random numbers onto the queue. + c_forrange (n) + cqueue_i_push(&queue, (int)crand_unif(&rng, &dist)); + + // Push or pop on the queue ten million times + printf("%d\n", n); + c_forrange (n) { // forrange uses initial n only. + int r = (int)crand_unif(&rng, &dist); + if (r & 1) + ++n, cqueue_i_push(&queue, r); + else + --n, cqueue_i_pop(&queue); + } + printf("%d, %" c_ZI "\n", n, cqueue_i_size(&queue)); + + cqueue_i_drop(&queue); +} diff --git a/misc/examples/random.c b/misc/examples/random.c deleted file mode 100644 index b7c0f277..00000000 --- a/misc/examples/random.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include - -int main(void) -{ - const int N = 1000000000; - const uint64_t seed = (uint64_t)time(NULL), range = 1000000; - crand_t rng = crand_init(seed); - - int64_t sum; - clock_t diff, before; - - printf("Compare speed of full and unbiased ranged random numbers...\n"); - sum = 0; - before = clock(); - c_forrange (N) { - sum += (uint32_t)crand_u64(&rng); - } - diff = clock() - before; - printf("full range\t\t: %f secs, %d, avg: %f\n", - (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); - - crand_unif_t dist1 = crand_unif_init(0, range); - rng = crand_init(seed); - sum = 0; - before = clock(); - c_forrange (N) { - sum += crand_unif(&rng, &dist1); // unbiased - } - diff = clock() - before; - printf("unbiased 0-%" PRIu64 "\t: %f secs, %d, avg: %f\n", - range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); - - sum = 0; - rng = crand_init(seed); - before = clock(); - c_forrange (N) { - sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased - } - diff = clock() - before; - printf("biased 0-%" PRIu64 " \t: %f secs, %d, avg: %f\n", - range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); - -} diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c deleted file mode 100644 index 694ce12e..00000000 --- a/misc/examples/rawptr_elements.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#define i_implement -#include - -// Create cmap of cstr => long* -#define i_type SIPtrMap -#define i_key_str -#define i_val long* -#define i_valraw long -#define i_valfrom(raw) c_new(long, raw) -#define i_valto(x) **x -#define i_valclone(x) c_new(long, *x) -#define i_valdrop(x) c_free(*x) -#include - -// Alternatively, using cbox: -#define i_type IBox -#define i_key long -#include // unique_ptr alike. - -// cmap of cstr => IBox -#define i_type SIBoxMap -#define i_key_str -#define i_valboxed IBox // i_valboxed: use properties from IBox automatically -#include - -int main(void) -{ - // These have the same behaviour, except IBox has a get member: - SIPtrMap map1 = {0}; - SIBoxMap map2 = {0}; - - printf("\nMap cstr => long*:\n"); - SIPtrMap_insert(&map1, cstr_from("Test1"), c_new(long, 1)); - SIPtrMap_insert(&map1, cstr_from("Test2"), c_new(long, 2)); - - // Emplace implicitly creates cstr from const char* and an owned long* from long! - SIPtrMap_emplace(&map1, "Test3", 3); - SIPtrMap_emplace(&map1, "Test4", 4); - - c_forpair (name, number, SIPtrMap, map1) - printf("%s: %ld\n", cstr_str(_.name), **_.number); - - puts("\nMap cstr => IBox:"); - SIBoxMap_insert(&map2, cstr_from("Test1"), IBox_make(1)); - SIBoxMap_insert(&map2, cstr_from("Test2"), IBox_make(2)); - - // Emplace implicitly creates cstr from const char* and IBox from long! - SIBoxMap_emplace(&map2, "Test3", 3); - SIBoxMap_emplace(&map2, "Test4", 4); - - c_forpair (name, number, SIBoxMap, map2) - printf("%s: %ld\n", cstr_str(_.name), *_.number->get); - puts(""); - - SIPtrMap_drop(&map1); - SIBoxMap_drop(&map2); -} diff --git a/misc/examples/read.c b/misc/examples/read.c deleted file mode 100644 index b12f7409..00000000 --- a/misc/examples/read.c +++ /dev/null @@ -1,27 +0,0 @@ -#define i_implement -#include -#include -#define i_key_str -#include -#include - -cvec_str read_file(const char* name) -{ - cvec_str vec = cvec_str_init(); - c_with (FILE* f = fopen(name, "r"), fclose(f)) - c_with (cstr line = cstr_null, cstr_drop(&line)) - while (cstr_getline(&line, f)) - cvec_str_push(&vec, cstr_clone(line)); - return vec; -} - -int main(void) -{ - int n = 0; - c_with (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec)) - c_foreach (i, cvec_str, vec) - printf("%5d: %s\n", ++n, cstr_str(i.ref)); - - if (errno) - printf("error: read_file(" __FILE__ "). errno: %d\n", errno); -} diff --git a/misc/examples/regex1.c b/misc/examples/regex1.c deleted file mode 100644 index d8032358..00000000 --- a/misc/examples/regex1.c +++ /dev/null @@ -1,32 +0,0 @@ -#define i_import -#include - -int main(int argc, char* argv[]) -{ - if (argc <= 1) { - printf("Usage: regex1 -i\n"); - return 0; - } - cstr input = {0}; - cregex float_expr = {0}; - - int res = cregex_compile(&float_expr, "^[+-]?[0-9]+((\\.[0-9]*)?|\\.[0-9]+)$"); - // Until "q" is given, ask for another number - if (res > 0) while (true) - { - printf("Enter a double precision number (q for quit): "); - cstr_getline(&input, stdin); - - // Exit when the user inputs q - if (cstr_equals(&input, "q")) - break; - - if (cregex_is_match(&float_expr, cstr_str(&input))) - printf("Input is a float\n"); - else - printf("Invalid input : Not a float\n"); - } - - cstr_drop(&input); - cregex_drop(&float_expr); -} diff --git a/misc/examples/regex2.c b/misc/examples/regex2.c deleted file mode 100644 index a798b1a1..00000000 --- a/misc/examples/regex2.c +++ /dev/null @@ -1,34 +0,0 @@ -#define i_import -#include - -int main(void) -{ - struct { const char *pattern, *input; } s[] = { - {"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])", - "date: 2024-02-29 leapyear day, christmas eve is on 2022-12-24." - }, - {"(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?", - "https://en.cppreference.com/w/cpp/regex/regex_search" - }, - {"!((abc|123)+)!", "!123abcabc!"}, - {"(\\p{Alpha}+ )+(\\p{Nd}+)", "Großpackung süßigkeiten 199"}, - {"\\p{Han}+", "This is Han: 王明:那是杂志吗?"}, - }; - - cregex re = {0}; - c_forrange (i, c_arraylen(s)) - { - int res = cregex_compile(&re, s[i].pattern); - if (res < 0) { - printf("error in regex pattern: %d\n", res); - continue; - } - printf("\ninput: %s\n", s[i].input); - - c_formatch (j, &re, s[i].input) { - c_forrange (k, cregex_captures(&re) + 1) - printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); - } - } - cregex_drop(&re); -} diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c deleted file mode 100644 index 11426d2d..00000000 --- a/misc/examples/regex_match.c +++ /dev/null @@ -1,37 +0,0 @@ -#define i_import -#include -#define i_implement -#include - -#define i_key float -#include - -int main(void) -{ - // Lets find the first sequence of digits in a string - const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour." - " Around 365.25 days a year, and 52 weeks in a year." - " Boltzmann const: 1.38064852E-23, is very small." - " Bohrradius is 5.29177210903e-11, and Avogadros number is 6.02214076e23."; - cregex re = {0}; - cstack_float vec = {0}; - - const char* pattern = "[+-]?([0-9]*\\.)?\\d+([Ee][+-]?\\d+)?"; - int res = cregex_compile(&re, pattern); - printf("%d: %s\n", res, pattern); - - // extract and convert all numbers in str to floats - c_formatch (i, &re, str) - cstack_float_push(&vec, (float)atof(i.match[0].str)); - - c_foreach (i, cstack_float, vec) - printf(" %g\n", (double)*i.ref); - - // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); - printf("\n%s\n", cstr_str(&nums)); - - cstr_drop(&nums); - cregex_drop(&re); - cstack_float_drop(&vec); -} diff --git a/misc/examples/regex_replace.c b/misc/examples/regex_replace.c deleted file mode 100644 index f1ea2711..00000000 --- a/misc/examples/regex_replace.c +++ /dev/null @@ -1,57 +0,0 @@ -#define i_import -#include -#include - -bool add_10_years(int i, csview match, cstr* out) { - if (i == 1) { // group 1 matches year - int year; - sscanf(match.str, "%4d", &year); // scan 4 chars only - cstr_printf(out, "%04d", year + 10); - return true; - } - return false; -} - -int main(void) -{ - const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b"; - const char* input = "start date: 2015-12-31, end date: 2022-02-28"; - cstr str = {0}; - cregex re = {0}; - - c_defer( - cregex_drop(&re), - cstr_drop(&str) - ){ - printf("INPUT: %s\n", input); - - /* replace with a fixed string, extended all-in-one call: */ - cstr_take(&str, cregex_replace_pattern(pattern, input, "YYYY-MM-DD")); - printf("fixed: %s\n", cstr_str(&str)); - - /* US date format, and add 10 years to dates: */ - cstr_take(&str, cregex_replace_pattern(pattern, input, "$1/$3/$2", 0, add_10_years, CREG_DEFAULT)); - printf("us+10: %s\n", cstr_str(&str)); - - /* Wrap first date inside []: */ - cstr_take(&str, cregex_replace_pattern(pattern, input, "[$0]")); - printf("brack: %s\n", cstr_str(&str)); - - /* Shows how to compile RE separately */ - re = cregex_from(pattern); - if (cregex_captures(&re) == 0) - continue; /* break c_defer */ - - /* European date format. */ - cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); - printf("euros: %s\n", cstr_str(&str)); - - /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); - printf("strip: %s\n", cstr_str(&str)); - - /* Wrap all words in ${} */ - cstr_take(&str, cregex_replace_pattern("[a-z]+", "52 apples and 31 mangoes", "$${$0}")); - printf("curly: %s\n", cstr_str(&str)); - } -} diff --git a/misc/examples/regularexpressions/regex1.c b/misc/examples/regularexpressions/regex1.c new file mode 100644 index 00000000..d8032358 --- /dev/null +++ b/misc/examples/regularexpressions/regex1.c @@ -0,0 +1,32 @@ +#define i_import +#include + +int main(int argc, char* argv[]) +{ + if (argc <= 1) { + printf("Usage: regex1 -i\n"); + return 0; + } + cstr input = {0}; + cregex float_expr = {0}; + + int res = cregex_compile(&float_expr, "^[+-]?[0-9]+((\\.[0-9]*)?|\\.[0-9]+)$"); + // Until "q" is given, ask for another number + if (res > 0) while (true) + { + printf("Enter a double precision number (q for quit): "); + cstr_getline(&input, stdin); + + // Exit when the user inputs q + if (cstr_equals(&input, "q")) + break; + + if (cregex_is_match(&float_expr, cstr_str(&input))) + printf("Input is a float\n"); + else + printf("Invalid input : Not a float\n"); + } + + cstr_drop(&input); + cregex_drop(&float_expr); +} diff --git a/misc/examples/regularexpressions/regex2.c b/misc/examples/regularexpressions/regex2.c new file mode 100644 index 00000000..a798b1a1 --- /dev/null +++ b/misc/examples/regularexpressions/regex2.c @@ -0,0 +1,34 @@ +#define i_import +#include + +int main(void) +{ + struct { const char *pattern, *input; } s[] = { + {"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])", + "date: 2024-02-29 leapyear day, christmas eve is on 2022-12-24." + }, + {"(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?", + "https://en.cppreference.com/w/cpp/regex/regex_search" + }, + {"!((abc|123)+)!", "!123abcabc!"}, + {"(\\p{Alpha}+ )+(\\p{Nd}+)", "Großpackung süßigkeiten 199"}, + {"\\p{Han}+", "This is Han: 王明:那是杂志吗?"}, + }; + + cregex re = {0}; + c_forrange (i, c_arraylen(s)) + { + int res = cregex_compile(&re, s[i].pattern); + if (res < 0) { + printf("error in regex pattern: %d\n", res); + continue; + } + printf("\ninput: %s\n", s[i].input); + + c_formatch (j, &re, s[i].input) { + c_forrange (k, cregex_captures(&re) + 1) + printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); + } + } + cregex_drop(&re); +} diff --git a/misc/examples/regularexpressions/regex_match.c b/misc/examples/regularexpressions/regex_match.c new file mode 100644 index 00000000..11426d2d --- /dev/null +++ b/misc/examples/regularexpressions/regex_match.c @@ -0,0 +1,37 @@ +#define i_import +#include +#define i_implement +#include + +#define i_key float +#include + +int main(void) +{ + // Lets find the first sequence of digits in a string + const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour." + " Around 365.25 days a year, and 52 weeks in a year." + " Boltzmann const: 1.38064852E-23, is very small." + " Bohrradius is 5.29177210903e-11, and Avogadros number is 6.02214076e23."; + cregex re = {0}; + cstack_float vec = {0}; + + const char* pattern = "[+-]?([0-9]*\\.)?\\d+([Ee][+-]?\\d+)?"; + int res = cregex_compile(&re, pattern); + printf("%d: %s\n", res, pattern); + + // extract and convert all numbers in str to floats + c_formatch (i, &re, str) + cstack_float_push(&vec, (float)atof(i.match[0].str)); + + c_foreach (i, cstack_float, vec) + printf(" %g\n", (double)*i.ref); + + // extracts the numbers only to a comma separated string. + cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); + printf("\n%s\n", cstr_str(&nums)); + + cstr_drop(&nums); + cregex_drop(&re); + cstack_float_drop(&vec); +} diff --git a/misc/examples/regularexpressions/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c new file mode 100644 index 00000000..f1ea2711 --- /dev/null +++ b/misc/examples/regularexpressions/regex_replace.c @@ -0,0 +1,57 @@ +#define i_import +#include +#include + +bool add_10_years(int i, csview match, cstr* out) { + if (i == 1) { // group 1 matches year + int year; + sscanf(match.str, "%4d", &year); // scan 4 chars only + cstr_printf(out, "%04d", year + 10); + return true; + } + return false; +} + +int main(void) +{ + const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b"; + const char* input = "start date: 2015-12-31, end date: 2022-02-28"; + cstr str = {0}; + cregex re = {0}; + + c_defer( + cregex_drop(&re), + cstr_drop(&str) + ){ + printf("INPUT: %s\n", input); + + /* replace with a fixed string, extended all-in-one call: */ + cstr_take(&str, cregex_replace_pattern(pattern, input, "YYYY-MM-DD")); + printf("fixed: %s\n", cstr_str(&str)); + + /* US date format, and add 10 years to dates: */ + cstr_take(&str, cregex_replace_pattern(pattern, input, "$1/$3/$2", 0, add_10_years, CREG_DEFAULT)); + printf("us+10: %s\n", cstr_str(&str)); + + /* Wrap first date inside []: */ + cstr_take(&str, cregex_replace_pattern(pattern, input, "[$0]")); + printf("brack: %s\n", cstr_str(&str)); + + /* Shows how to compile RE separately */ + re = cregex_from(pattern); + if (cregex_captures(&re) == 0) + continue; /* break c_defer */ + + /* European date format. */ + cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); + printf("euros: %s\n", cstr_str(&str)); + + /* Strip out everything but the matches */ + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + printf("strip: %s\n", cstr_str(&str)); + + /* Wrap all words in ${} */ + cstr_take(&str, cregex_replace_pattern("[a-z]+", "52 apples and 31 mangoes", "$${$0}")); + printf("curly: %s\n", cstr_str(&str)); + } +} diff --git a/misc/examples/replace.c b/misc/examples/replace.c deleted file mode 100644 index 59a56bf7..00000000 --- a/misc/examples/replace.c +++ /dev/null @@ -1,36 +0,0 @@ -#define i_implement -#include - -int main(void) -{ - const char *base = "this is a test string."; - const char *s2 = "n example"; - const char *s3 = "sample phrase"; - - // replace signatures used in the same order as described above: - - // Ustring positions: 0123456789*123456789*12345 - cstr s = cstr_from(base); // "this is a test string." - cstr m = cstr_clone(s); - - cstr_append(&m, cstr_str(&m)); - cstr_append(&m, cstr_str(&m)); - printf("%s\n", cstr_str(&m)); - - cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) - printf("(1) %s\n", cstr_str(&s)); - - cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) - printf("(2) %s\n", cstr_str(&s)); - - cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) - printf("(3) %s\n", cstr_str(&s)); - - cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) - printf("(4) %s\n", cstr_str(&s)); - - cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) - printf("(5) %s\n", cstr_str(&s)); - - c_drop(cstr, &s, &m); -} diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c deleted file mode 100644 index 38defd0f..00000000 --- a/misc/examples/scheduler.c +++ /dev/null @@ -1,74 +0,0 @@ -// https://www.youtube.com/watch?v=8sEe-4tig_A -#include -#include - -struct Task { - int (*fn)(struct Task*); - int cco_state; - struct Scheduler* sched; -}; - -#define i_type Scheduler -#define i_key struct Task -#include - -static bool schedule(Scheduler* sched) -{ - struct Task task = *Scheduler_front(sched); - Scheduler_pop(sched); - - if (!cco_done(&task)) - task.fn(&task); - - return !Scheduler_empty(sched); -} - -static int push_task(const struct Task* task) -{ - Scheduler_push(task->sched, *task); - return CCO_YIELD; -} - - -static int taskA(struct Task* task) -{ - cco_routine(task) { - puts("Hello, from task A"); - cco_yield_v(push_task(task)); - puts("A is back doing work"); - cco_yield_v(push_task(task)); - puts("A is back doing more work"); - cco_yield_v(push_task(task)); - puts("A is back doing even more work"); - } - return 0; -} - -static int taskB(struct Task* task) -{ - cco_routine(task) { - puts("Hello, from task B"); - cco_yield_v(push_task(task)); - puts("B is back doing work"); - cco_yield_v(push_task(task)); - puts("B is back doing more work"); - } - return 0; -} - -void Use(void) -{ - Scheduler scheduler = c_init(Scheduler, { - {.fn=taskA, .sched=&scheduler}, - {.fn=taskB, .sched=&scheduler}, - }); - - while (schedule(&scheduler)) {} - - Scheduler_drop(&scheduler); -} - -int main(void) -{ - Use(); -} diff --git a/misc/examples/shape.c b/misc/examples/shape.c deleted file mode 100644 index bd4bdd5a..00000000 --- a/misc/examples/shape.c +++ /dev/null @@ -1,158 +0,0 @@ -// Demo of typesafe polymorphism in C99, using STC. - -#include -#include -#include - -#define DYN_CAST(T, s) \ - (&T##_api == (s)->api ? (T*)(s) : (T*)0) - -// Shape definition -// ============================================================ - -typedef struct { - float x, y; -} Point; - -typedef struct Shape Shape; - -struct ShapeAPI { - void (*drop)(Shape*); - void (*draw)(const Shape*); -}; - -struct Shape { - struct ShapeAPI* api; - uint32_t color; - uint16_t style; - uint8_t thickness; - uint8_t hardness; -}; - -void Shape_drop(Shape* shape) -{ - printf("shape destructed\n"); -} - -void Shape_delete(Shape* shape) -{ - if (shape) { - shape->api->drop(shape); - c_free(shape); - } -} - -// Triangle implementation -// ============================================================ - -typedef struct { - Shape shape; - Point p[3]; -} Triangle; - -extern struct ShapeAPI Triangle_api; - - -Triangle Triangle_from(Point a, Point b, Point c) { - Triangle t = {{&Triangle_api}, {a, b, c}}; - return t; -} - -static void Triangle_draw(const Shape* shape) -{ - const Triangle* self = DYN_CAST(Triangle, shape); - printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n", - (double)self->p[0].x, (double)self->p[0].y, - (double)self->p[1].x, (double)self->p[1].y, - (double)self->p[2].x, (double)self->p[2].y); -} - -struct ShapeAPI Triangle_api = { - .drop = Shape_drop, - .draw = Triangle_draw, -}; - -// Polygon implementation -// ============================================================ - -#define i_type PointVec -#define i_key Point -#include - -typedef struct { - Shape shape; - PointVec points; -} Polygon; - -extern struct ShapeAPI Polygon_api; - - -Polygon Polygon_init(void) { - Polygon p = {{&Polygon_api}, {0}}; - return p; -} - -void Polygon_addPoint(Polygon* self, Point p) -{ - PointVec_push(&self->points, p); -} - -static void Polygon_drop(Shape* shape) -{ - Polygon* self = DYN_CAST(Polygon, shape); - printf("poly destructed\n"); - PointVec_drop(&self->points); -} - -static void Polygon_draw(const Shape* shape) -{ - const Polygon* self = DYN_CAST(Polygon, shape); - printf("Polygon :"); - c_foreach (i, PointVec, self->points) - printf(" (%g,%g)", (double)i.ref->x, (double)i.ref->y); - puts(""); -} - -struct ShapeAPI Polygon_api = { - .drop = Polygon_drop, - .draw = Polygon_draw, -}; - -// Test -// ============================================================ - -#define i_type Shapes -#define i_key Shape* -#define i_keydrop(x) Shape_delete(*x) -#define i_no_clone -#include - -void testShape(const Shape* shape) -{ - shape->api->draw(shape); -} - - -int main(void) -{ - Shapes shapes = {0}; - - Triangle* tri1 = c_new(Triangle, Triangle_from(c_LITERAL(Point){5, 7}, c_LITERAL(Point){12, 7}, c_LITERAL(Point){12, 20})); - Polygon* pol1 = c_new(Polygon, Polygon_init()); - Polygon* pol2 = c_new(Polygon, Polygon_init()); - - c_forlist (i, Point, {{50, 72}, {123, 73}, {127, 201}, {828, 333}}) - Polygon_addPoint(pol1, *i.ref); - - c_forlist (i, Point, {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}) - Polygon_addPoint(pol2, *i.ref); - - Shapes_push(&shapes, &tri1->shape); - Shapes_push(&shapes, &pol1->shape); - Shapes_push(&shapes, &pol2->shape); - - c_foreach (i, Shapes, shapes) - testShape(*i.ref); - - Shapes_drop(&shapes); -} diff --git a/misc/examples/shape.cpp b/misc/examples/shape.cpp deleted file mode 100644 index ea1f53d2..00000000 --- a/misc/examples/shape.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// Demo of polymorphism in C++ - -#include -#include -#include - -// Shape definition -// ============================================================ - -struct Point { - float x, y; -}; - -std::ostream& operator<<(std::ostream& os, const Point& p) { - os << " (" << p.x << "," << p.y << ")"; - return os; -} - -struct Shape { - virtual ~Shape(); - virtual void draw() const = 0; - - uint32_t color; - uint16_t style; - uint8_t thickness; - uint8_t hardness; -}; - -Shape::~Shape() -{ - std::cout << "base destructed" << std::endl; -} - -// Triangle implementation -// ============================================================ - -struct Triangle : public Shape -{ - Triangle(Point a, Point b, Point c); - void draw() const override; - - private: Point p[3]; -}; - - -Triangle::Triangle(Point a, Point b, Point c) - : p{a, b, c} {} - -void Triangle::draw() const -{ - std::cout << "Triangle :" - << p[0] << p[1] << p[2] - << std::endl; -} - - -// Polygon implementation -// ============================================================ - - -struct Polygon : public Shape -{ - ~Polygon(); - void draw() const override; - void addPoint(const Point& p); - - private: std::vector points; -}; - - -void Polygon::addPoint(const Point& p) -{ - points.push_back(p); -} - -Polygon::~Polygon() -{ - std::cout << "poly destructed" << std::endl; -} - -void Polygon::draw() const -{ - std::cout << "Polygon :"; - for (auto& p : points) - std::cout << p ; - std::cout << std::endl; -} - - -// Test -// ============================================================ - -void testShape(const Shape* shape) -{ - shape->draw(); -} - -#include - -int main(void) -{ - std::vector> shapes; - - auto tri1 = std::make_unique(Point{5, 7}, Point{12, 7}, Point{12, 20}); - auto pol1 = std::make_unique(); - auto pol2 = std::make_unique(); - - for (auto& p: std::array - {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}}) - pol1->addPoint(p); - - for (auto& p: std::array - {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}}) - pol2->addPoint(p); - - shapes.push_back(std::move(tri1)); - shapes.push_back(std::move(pol1)); - shapes.push_back(std::move(pol2)); - - for (auto& shape: shapes) - testShape(shape.get()); -} diff --git a/misc/examples/sidebyside.cpp b/misc/examples/sidebyside.cpp deleted file mode 100644 index 9414b691..00000000 --- a/misc/examples/sidebyside.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include -#include - -#define i_type IIMap -#define i_key int -#define i_val int -#include - -#define i_type SIMap -#define i_key_str -#define i_val int -#include - -int main(void) { - { - std::map hist; - hist.emplace(12, 100).first->second += 1; - hist.emplace(13, 100).first->second += 1; - hist.emplace(12, 100).first->second += 1; - - for (auto i: hist) - std::cout << i.first << ", " << i.second << std::endl; - std::cout << std::endl; - } - { - IIMap hist = {0}; - IIMap_insert(&hist, 12, 100).ref->second += 1; - IIMap_insert(&hist, 13, 100).ref->second += 1; - IIMap_insert(&hist, 12, 100).ref->second += 1; - - c_foreach (i, IIMap, hist) - printf("%d, %d\n", i.ref->first, i.ref->second); - puts(""); - IIMap_drop(&hist); - } - // =================================================== - { - std::map food = - {{"burger", 5}, {"pizza", 12}, {"steak", 15}}; - - for (auto i: food) - std::cout << i.first << ", " << i.second << std::endl; - std::cout << std::endl; - } - { - SIMap food = {0}; - c_forlist (i, SIMap_raw, {{"burger", 5}, {"pizza", 12}, {"steak", 15}}) - SIMap_emplace(&food, i.ref->first, i.ref->second); - - c_foreach (i, SIMap, food) - printf("%s, %d\n", cstr_str(&i.ref->first), i.ref->second); - puts(""); - SIMap_drop(&food); - } -} diff --git a/misc/examples/smartpointers/arc_containers.c b/misc/examples/smartpointers/arc_containers.c new file mode 100644 index 00000000..2fb04c56 --- /dev/null +++ b/misc/examples/smartpointers/arc_containers.c @@ -0,0 +1,81 @@ +// Create a stack and a list of shared pointers to maps, +// and demonstrate sharing and cloning of maps. +#define i_implement +#include +#include +#define i_type Map +#define i_key_str // strings +#define i_val int +#define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p)) +#include + +#define i_type Arc // (atomic) ref. counted type +#define i_key Map +#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) +// no need for atomic ref. count in single thread: +#define i_opt c_no_atomic +#include + +#define i_type Stack +#define i_keyboxed Arc // define i_keyboxed for carc/cbox value (not i_key) +#include + +#define i_type List +#define i_keyboxed Arc // as above +#include + +int main(void) +{ + Stack stack = {0}; + List list = {0}; + c_defer( + Stack_drop(&stack), + List_drop(&list) + ){ + // POPULATE stack with shared pointers to Maps: + Map *map; + map = Stack_push(&stack, Arc_from(Map_init()))->get; + Map_emplace(map, "Joey", 1990); + Map_emplace(map, "Mary", 1995); + Map_emplace(map, "Joanna", 1992); + + map = Stack_push(&stack, Arc_from(Map_init()))->get; + Map_emplace(map, "Rosanna", 2001); + Map_emplace(map, "Brad", 1999); + Map_emplace(map, "Jack", 1980); + + // POPULATE list: + map = List_push_back(&list, Arc_from(Map_init()))->get; + Map_emplace(map, "Steve", 1979); + Map_emplace(map, "Rick", 1974); + Map_emplace(map, "Tracy", 2003); + + // Share two Maps from the stack with the list using emplace (clone the carc): + List_push_back(&list, Arc_clone(stack.data[0])); + List_push_back(&list, Arc_clone(stack.data[1])); + + // Clone (deep copy) a Map from the stack to the list + // List will contain two shared and two unshared maps. + map = List_push_back(&list, Arc_from(Map_clone(*stack.data[1].get)))->get; + + // Add one more element to the cloned map: + Map_emplace_or_assign(map, "CLONED", 2021); + + // Add one more element to the shared map: + Map_emplace_or_assign(stack.data[1].get, "SHARED", 2021); + + puts("STACKS"); + c_foreach (i, Stack, stack) { + c_forpair (name, year, Map, *i.ref->get) + printf(" %s:%d", cstr_str(_.name), *_.year); + puts(""); + } + + puts("LIST"); + c_foreach (i, List, list) { + c_forpair (name, year, Map, *i.ref->get) + printf(" %s:%d", cstr_str(_.name), *_.year); + puts(""); + } + } +} diff --git a/misc/examples/smartpointers/arc_demo.c b/misc/examples/smartpointers/arc_demo.c new file mode 100644 index 00000000..929a48a1 --- /dev/null +++ b/misc/examples/smartpointers/arc_demo.c @@ -0,0 +1,62 @@ +#include +#include + +void int_drop(int* x) { + printf("drop: %d\n", *x); +} + +// carc implements its own clone method using reference counting, +// so 'i_keyclone' is not required to be defined (ignored). + +#define i_type Arc // set type name to be defined (instead of 'carc_int') +#define i_key int +#define i_keydrop int_drop // optional, just to display the elements destroyed +#define i_cmp_native // use int comparison (x < y, x == y). +#include // Arc + +#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements +#include // csset_Arc (like: std::set>) + +#define i_keyboxed Arc // note: as above. +#include // cvec_Arc (like: std::vector>) + +int main(void) +{ + const int years[] = {2021, 2012, 2022, 2015}; + + cvec_Arc vec = {0}; + c_forrange (i, c_arraylen(years)) { + cvec_Arc_emplace(&vec, years[i]); + // cvec_Arc_push(&vec, Arc_from(years[i])); // alt. + } + + cvec_Arc_sort(&vec); + + printf("vec:"); + c_foreach (i, cvec_Arc, vec) + printf(" %d", *i.ref->get); + puts(""); + + // add odd numbers from vec to set + csset_Arc set = {0}; + c_foreach (i, cvec_Arc, vec) + if (*i.ref->get & 1) + csset_Arc_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter. + + // erase the two last elements in vec + cvec_Arc_pop_back(&vec); + cvec_Arc_pop_back(&vec); + + printf("vec:"); + c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get); + + printf("\nset:"); + c_foreach (i, csset_Arc, set) printf(" %d", *i.ref->get); + + Arc p = Arc_clone(vec.data[0]); + printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count); + + Arc_drop(&p); + cvec_Arc_drop(&vec); + csset_Arc_drop(&set); +} diff --git a/misc/examples/smartpointers/arcvec_erase.c b/misc/examples/smartpointers/arcvec_erase.c new file mode 100644 index 00000000..ba54c1c7 --- /dev/null +++ b/misc/examples/smartpointers/arcvec_erase.c @@ -0,0 +1,50 @@ +#include + +void show_drop(int* x) { printf("drop: %d\n", *x); } + +#define i_type Arc +#define i_key int +#define i_keydrop show_drop +#define i_cmp_native // enable sort/search for int type +#include // Shared pointer to int + +#define i_type Vec +#define i_keyboxed Arc +#include // Vec: cvec + + +int main(void) +{ + Vec vec = c_init(Vec, {2012, 1990, 2012, 2019, 2015}); + + // clone the second 2012 and push it back. + // note: cloning make sure that vec.data[2] has ref count 2. + Vec_push(&vec, Arc_clone(vec.data[2])); + + printf("vec before erase :"); + c_foreach (i, Vec, vec) + printf(" %d", *i.ref->get); + + printf("\nerase vec.data[2]; or first matching value depending on compare.\n"); + Vec_iter it; + it = Vec_find(&vec, *vec.data[2].get); + if (it.ref) + Vec_erase_at(&vec, it); + + int year = 2015; + it = Vec_find(&vec, year); // Ok as tmp only. + if (it.ref) + Vec_erase_at(&vec, it); + + printf("vec after erase :"); + c_foreach (i, Vec, vec) + printf(" %d", *i.ref->get); + + Vec_sort(&vec); + printf("\nvec after sort :"); + c_foreach (i, Vec, vec) + printf(" %d", *i.ref->get); + + puts("\nDone"); + Vec_drop(&vec); +} diff --git a/misc/examples/smartpointers/box.c b/misc/examples/smartpointers/box.c new file mode 100644 index 00000000..94d126c0 --- /dev/null +++ b/misc/examples/smartpointers/box.c @@ -0,0 +1,69 @@ +/* cbox: heap allocated boxed type */ +#define i_implement +#include + +typedef struct { cstr name, last; } Person; + +Person Person_make(const char* name, const char* last) { + return c_LITERAL(Person){.name = cstr_from(name), .last = cstr_from(last)}; +} + +uint64_t Person_hash(const Person* a) { + return cstr_hash(&a->name) ^ cstr_hash(&a->last); +} + +int Person_cmp(const Person* a, const Person* b) { + int c = cstr_cmp(&a->name, &b->name); + return c ? c : cstr_cmp(&a->last, &b->last); +} + +Person Person_clone(Person p) { + p.name = cstr_clone(p.name); + p.last = cstr_clone(p.last); + return p; +} + +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); + c_drop(cstr, &p->name, &p->last); +} + +#define i_type PBox +#define i_keyclass Person // "class" binds _cmp, _clone, _drop functions. +#include + +#define i_type Persons +#define i_keyboxed PBox // "arcbox" informs that PBox is a smart pointer. +#include + +int main(void) +{ + Persons vec = {0}; + PBox p = PBox_from(Person_make("Laura", "Palmer")); + PBox q = PBox_clone(p); + cstr_assign(&q.get->name, "Leland"); + + printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); + printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); + + Persons_emplace(&vec, Person_make("Dale", "Cooper")); + Persons_emplace(&vec, Person_make("Audrey", "Home")); + + // NB! Clone/share p and q in the Persons container. + Persons_push(&vec, PBox_clone(p)); + Persons_push(&vec, PBox_clone(q)); + + c_foreach (i, Persons, vec) + printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); + puts(""); + + // Look-up Audrey! Create a temporary Person for lookup. + Person a = Person_make("Audrey", "Home"); + const PBox *v = Persons_get(&vec, a); // lookup + if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); + + Person_drop(&a); + PBox_drop(&p); + PBox_drop(&q); + Persons_drop(&vec); +} diff --git a/misc/examples/smartpointers/box2.c b/misc/examples/smartpointers/box2.c new file mode 100644 index 00000000..eaab1c47 --- /dev/null +++ b/misc/examples/smartpointers/box2.c @@ -0,0 +1,82 @@ +// example: https://doc.rust-lang.org/rust-by-example/std/box.html +#include + +typedef struct { + double x; + double y; +} Point; + +// A Rectangle can be specified by where its top left and bottom right +// corners are in space +typedef struct { + Point top_left; + Point bottom_right; +} Rectangle; + +#define i_key Point +#include // cbox_Point + +#define i_key Rectangle +#include // cbox_Rectangle + +// Box in box: +#define i_type BoxBoxPoint +#define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc! +#define i_no_cmp +#include // BoxBoxPoint + +Point origin(void) { + return c_LITERAL(Point){ .x=1.0, .y=2.0 }; +} + +cbox_Point boxed_origin(void) { + // Allocate this point on the heap, and return a pointer to it + return cbox_Point_make(c_LITERAL(Point){ .x=1.0, .y=2.0 }); +} + + +int main(void) { + // Stack allocated variables + Point point = origin(); + Rectangle rectangle = { + .top_left = origin(), + .bottom_right = { .x=3.0, .y=-4.0 } + }; + + // Heap allocated rectangle + cbox_Rectangle boxed_rectangle = cbox_Rectangle_make(c_LITERAL(Rectangle){ + .top_left = origin(), + .bottom_right = { .x=3.0, .y=-4.0 } + }); + // The output of functions can be boxed + cbox_Point boxed_point = cbox_Point_make(origin()); + + // Can use from(raw) and toraw instead: + BoxBoxPoint box_in_a_box = BoxBoxPoint_from(origin()); + + c_defer( + BoxBoxPoint_drop(&box_in_a_box), + cbox_Point_drop(&boxed_point), + cbox_Rectangle_drop(&boxed_rectangle) + ){ + printf("box_in_a_box: x = %g\n", BoxBoxPoint_toraw(&box_in_a_box).x); + + printf("Point occupies %d bytes on the stack\n", + (int)sizeof(point)); + printf("Rectangle occupies %d bytes on the stack\n", + (int)sizeof(rectangle)); + + // box size == pointer size + printf("Boxed point occupies %d bytes on the stack\n", + (int)sizeof(boxed_point)); + printf("Boxed rectangle occupies %d bytes on the stack\n", + (int)sizeof(boxed_rectangle)); + printf("Boxed box occupies %d bytes on the stack\n", + (int)sizeof(box_in_a_box)); + + // Copy the data contained in `boxed_point` into `unboxed_point` + Point unboxed_point = *boxed_point.get; + printf("Unboxed point occupies %d bytes on the stack\n", + (int)sizeof(unboxed_point)); + } +} diff --git a/misc/examples/smartpointers/music_arc.c b/misc/examples/smartpointers/music_arc.c new file mode 100644 index 00000000..16111b0b --- /dev/null +++ b/misc/examples/smartpointers/music_arc.c @@ -0,0 +1,67 @@ +// shared_ptr-examples.cpp +// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 +#define i_implement +#include + +typedef struct +{ + cstr artist; + cstr title; +} Song; + +int Song_cmp(const Song* x, const Song* y) + { return cstr_cmp(&x->title, &y->title); } + +Song Song_make(const char* artist, const char* title) + { return c_LITERAL(Song){cstr_from(artist), cstr_from(title)}; } + +void Song_drop(Song* s) { + printf("drop: %s\n", cstr_str(&s->title)); + c_drop(cstr, &s->artist, &s->title); +} + +// Define the shared pointer: +#define i_type SongArc +#define i_keyclass Song +#define i_no_hash // no hash fn for Song, fallback hash pointer to Song. +#include + +// ... and a vector of them +#define i_type SongVec +#define i_keyboxed SongArc // use i_keyboxed on carc / cbox (instead of i_key) +#include + +void example3(void) +{ + SongVec vec1 = c_init(SongVec, { + Song_make("Bob Dylan", "The Times They Are A Changing"), + Song_make("Aretha Franklin", "Bridge Over Troubled Water"), + Song_make("Thalia", "Entre El Mar y Una Estrella") + }); + + SongVec vec2 = {0}; + // Share all entries in vec with vec2, except Bob Dylan. + c_foreach (s, SongVec, vec1) + if (!cstr_equals(&s.ref->get->artist, "Bob Dylan")) + SongVec_push(&vec2, SongArc_clone(*s.ref)); + + // Add a few more to vec2. We can use emplace when creating new entries + // Emplace calls SongArc_from() on the argument to create the Arc: + SongVec_emplace(&vec2, Song_make("Michael Jackson", "Billie Jean")); + SongVec_emplace(&vec2, Song_make("Rihanna", "Stay")); + + // We now have two vectors with some shared, some unique entries. + c_forlist (i, SongVec, {vec1, vec2}) { + puts("VEC:"); + c_foreach (s, SongVec, *i.ref) + printf(" %s - %s, REFS: %ld\n", cstr_str(&s.ref->get->artist), + cstr_str(&s.ref->get->title), + *s.ref->use_count); + } + c_drop(SongVec, &vec1, &vec2); +} + +int main(void) +{ + example3(); +} diff --git a/misc/examples/smartpointers/new_sptr.c b/misc/examples/smartpointers/new_sptr.c new file mode 100644 index 00000000..3c6fa16c --- /dev/null +++ b/misc/examples/smartpointers/new_sptr.c @@ -0,0 +1,75 @@ +#define i_implement +#include + +typedef struct { cstr name, last; } Person; +Person Person_make(const char* name, const char* last); +Person Person_clone(Person p); +void Person_drop(Person* p); +int Person_cmp(const Person* a, const Person* b); +uint64_t Person_hash(const Person* p); + +#define i_type PersonArc +#define i_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined. +#include + +#define i_type IPtr +#define i_key int +#define i_keydrop(x) printf("drop: %d\n", *x) +#define i_cmp_native +#include + +#define i_type IPStack +#define i_keyboxed IPtr +#include + +#define i_type PASet +#define i_keyboxed PersonArc +#include + + +Person Person_make(const char* name, const char* last) { + Person p = {.name = cstr_from(name), .last = cstr_from(last)}; + return p; +} + +int Person_cmp(const Person* a, const Person* b) { + return cstr_cmp(&a->name, &b->name); +} + +uint64_t Person_hash(const Person* p) { + return cstr_hash(&p->name); +} + +Person Person_clone(Person p) { + p.name = cstr_clone(p.name), p.last = cstr_clone(p.last); + return p; +} + +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); + c_drop(cstr, &p->name, &p->last); +} + + +int main(void) { + puts("Ex1"); + PersonArc p = PersonArc_from(Person_make("John", "Smiths")); + PersonArc q = PersonArc_clone(p); // share + PersonArc r = PersonArc_clone(p); + PersonArc s = PersonArc_from(Person_clone(*p.get)); // deep copy + printf("%s %s: refs %ld\n", cstr_str(&p.get->name), cstr_str(&p.get->last), *p.use_count); + c_drop(PersonArc, &p, &q, &r, &s); + + puts("Ex2"); + IPStack vec = {0}; + IPStack_push(&vec, IPtr_from(10)); + IPStack_push(&vec, IPtr_from(20)); + IPStack_emplace(&vec, 30); // same as IPStack_push(&vec, IPtr_from(30)); + IPStack_push(&vec, IPtr_clone(*IPStack_back(&vec))); + IPStack_push(&vec, IPtr_clone(*IPStack_front(&vec))); + + c_foreach (i, IPStack, vec) + printf(" (%d: refs %ld)", *i.ref->get, *i.ref->use_count); + puts(""); + IPStack_drop(&vec); +} diff --git a/misc/examples/smartpointers/person_arc.c b/misc/examples/smartpointers/person_arc.c new file mode 100644 index 00000000..38c883a7 --- /dev/null +++ b/misc/examples/smartpointers/person_arc.c @@ -0,0 +1,77 @@ +/* cbox: heap allocated boxed type */ +#define i_implement +#include + +typedef struct { cstr name, last; } Person; + +Person Person_make(const char* name, const char* last) { + Person p = {.name = cstr_from(name), .last = cstr_from(last)}; + return p; +} + +int Person_cmp(const Person* a, const Person* b) { + int c = cstr_cmp(&a->name, &b->name); + return c ? c : cstr_cmp(&a->last, &b->last); +} + +uint64_t Person_hash(const Person* a) { + return cstr_hash(&a->name) ^ cstr_hash(&a->last); +} + +Person Person_clone(Person p) { + p.name = cstr_clone(p.name); + p.last = cstr_clone(p.last); + return p; +} + +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); + c_drop(cstr, &p->name, &p->last); +} + +#define i_type PSPtr +#define i_keyclass Person // ensure Person_drop +#define i_cmp Person_cmp // specify object cmp, instead of ptr cmp for arc. +#include + +#define i_type Persons +#define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop... +#include + + +int main(void) +{ + PSPtr p = PSPtr_from(Person_make("Laura", "Palmer")); + PSPtr q = PSPtr_from(Person_clone(*p.get)); // deep copy + Persons vec = {0}; + + c_defer( + PSPtr_drop(&p), + PSPtr_drop(&q), + Persons_drop(&vec) + ){ + cstr_assign(&q.get->name, "Leland"); + + printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); + printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); + + // Use Persons_emplace to implicitly call PSPtr_make on the argument. + // No need to do: Persons_push(&vec, PSPtr_make(Person_make("Audrey", "Home"))); + Persons_emplace(&vec, Person_make("Audrey", "Home")); + Persons_emplace(&vec, Person_make("Dale", "Cooper")); + + // Clone/share p and q to the vector + c_forlist (i, PSPtr, {p, q}) + Persons_push(&vec, PSPtr_clone(*i.ref)); + + c_foreach (i, Persons, vec) + printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); + puts(""); + + // Look-up Audrey! + Person a = Person_make("Audrey", "Home"); + const PSPtr *v = Persons_get(&vec, a); + if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); + Person_drop(&a); + } +} diff --git a/misc/examples/smartpointers/rawptr_elements.c b/misc/examples/smartpointers/rawptr_elements.c new file mode 100644 index 00000000..694ce12e --- /dev/null +++ b/misc/examples/smartpointers/rawptr_elements.c @@ -0,0 +1,59 @@ +#include +#include +#define i_implement +#include + +// Create cmap of cstr => long* +#define i_type SIPtrMap +#define i_key_str +#define i_val long* +#define i_valraw long +#define i_valfrom(raw) c_new(long, raw) +#define i_valto(x) **x +#define i_valclone(x) c_new(long, *x) +#define i_valdrop(x) c_free(*x) +#include + +// Alternatively, using cbox: +#define i_type IBox +#define i_key long +#include // unique_ptr alike. + +// cmap of cstr => IBox +#define i_type SIBoxMap +#define i_key_str +#define i_valboxed IBox // i_valboxed: use properties from IBox automatically +#include + +int main(void) +{ + // These have the same behaviour, except IBox has a get member: + SIPtrMap map1 = {0}; + SIBoxMap map2 = {0}; + + printf("\nMap cstr => long*:\n"); + SIPtrMap_insert(&map1, cstr_from("Test1"), c_new(long, 1)); + SIPtrMap_insert(&map1, cstr_from("Test2"), c_new(long, 2)); + + // Emplace implicitly creates cstr from const char* and an owned long* from long! + SIPtrMap_emplace(&map1, "Test3", 3); + SIPtrMap_emplace(&map1, "Test4", 4); + + c_forpair (name, number, SIPtrMap, map1) + printf("%s: %ld\n", cstr_str(_.name), **_.number); + + puts("\nMap cstr => IBox:"); + SIBoxMap_insert(&map2, cstr_from("Test1"), IBox_make(1)); + SIBoxMap_insert(&map2, cstr_from("Test2"), IBox_make(2)); + + // Emplace implicitly creates cstr from const char* and IBox from long! + SIBoxMap_emplace(&map2, "Test3", 3); + SIBoxMap_emplace(&map2, "Test4", 4); + + c_forpair (name, number, SIBoxMap, map2) + printf("%s: %ld\n", cstr_str(_.name), *_.number->get); + puts(""); + + SIPtrMap_drop(&map1); + SIBoxMap_drop(&map2); +} diff --git a/misc/examples/sorted_map.c b/misc/examples/sorted_map.c deleted file mode 100644 index 89381554..00000000 --- a/misc/examples/sorted_map.c +++ /dev/null @@ -1,67 +0,0 @@ -// https://iq.opengenus.org/containers-cpp-stl/ - -#include -#define i_key int -#define i_val int -#include - -int main(void) -{ - - // empty map containers - csmap_int gquiz1 = {0}, gquiz2 = {0}; - c_defer( - csmap_int_drop(&gquiz1), - csmap_int_drop(&gquiz2) - ){ - // insert elements in random order - csmap_int_insert(&gquiz1, 2, 30); - csmap_int_insert(&gquiz1, 4, 20); - csmap_int_insert(&gquiz1, 7, 10); - csmap_int_insert(&gquiz1, 5, 50); - csmap_int_insert(&gquiz1, 3, 60); - csmap_int_insert(&gquiz1, 1, 40); - csmap_int_insert(&gquiz1, 6, 50); - - // printing map gquiz1 - printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n"); - c_foreach (itr, csmap_int, gquiz1) - printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); - printf("\n"); - - // assigning the elements from gquiz1 to gquiz2 - c_foreach (i, csmap_int, gquiz1) - csmap_int_insert(&gquiz2, i.ref->first, i.ref->second); - - // print all elements of the map gquiz2 - printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n"); - c_foreach (itr, csmap_int, gquiz2) - printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); - printf("\n"); - - // remove all elements up to element with key=3 in gquiz2 - printf("\ngquiz2 after removal of elements less than key=3 :\n"); - printf("\tKEY\tELEMENT\n"); - csmap_int_erase_range(&gquiz2, csmap_int_begin(&gquiz2), - csmap_int_find(&gquiz2, 3)); - c_foreach (itr, csmap_int, gquiz2) - printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); - printf("\n"); - - // remove all elements with key = 4 - int num = csmap_int_erase(&gquiz2, 4); - printf("\ngquiz2.erase(4) : %d removed\n", num); - printf("\tKEY\tELEMENT\n"); - c_foreach (itr, csmap_int, gquiz2) - printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); - printf("\n"); - - // lower bound and upper bound for map gquiz1 key = 5 - printf("gquiz1.lower_bound(5) : "); - printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5).ref->first); - printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5).ref->second); - printf("gquiz1.upper_bound(5) : "); - printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5+1).ref->first); - printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5+1).ref->second); - } -} diff --git a/misc/examples/sortedmaps/csmap_erase.c b/misc/examples/sortedmaps/csmap_erase.c new file mode 100644 index 00000000..8d4eeae3 --- /dev/null +++ b/misc/examples/sortedmaps/csmap_erase.c @@ -0,0 +1,82 @@ +// map_erase.c +// From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16 +#define i_implement +#include +#include + +#define i_key int +#define i_val_str +#define i_type mymap +#include + +void printmap(mymap m) +{ + c_foreach (elem, mymap, m) + printf(" [%d, %s]", elem.ref->first, cstr_str(&elem.ref->second)); + printf("\nsize() == %" c_ZI "\n\n", mymap_size(&m)); +} + +int main(void) +{ + mymap m1 = {0}; + + // Fill in some data to test with, one at a time + mymap_insert(&m1, 1, cstr_lit("A")); + mymap_insert(&m1, 2, cstr_lit("B")); + mymap_insert(&m1, 3, cstr_lit("C")); + mymap_insert(&m1, 4, cstr_lit("D")); + mymap_insert(&m1, 5, cstr_lit("E")); + + puts("Starting data of map m1 is:"); + printmap(m1); + // The 1st member function removes an element at a given position + mymap_erase_at(&m1, mymap_advance(mymap_begin(&m1), 1)); + puts("After the 2nd element is deleted, the map m1 is:"); + printmap(m1); + + // Fill in some data to test with + mymap m2 = c_init(mymap, { + {10, "Bob"}, + {11, "Rob"}, + {12, "Robert"}, + {13, "Bert"}, + {14, "Bobby"}, + }); + + puts("Starting data of map m2 is:"); + printmap(m2); + mymap_iter it1 = mymap_advance(mymap_begin(&m2), 1); + mymap_iter it2 = mymap_find(&m2, mymap_back(&m2)->first); + + puts("to remove:"); + c_foreach (i, mymap, it1, it2) + printf(" [%d, %s]", i.ref->first, cstr_str(&i.ref->second)); + puts(""); + // The 2nd member function removes elements + // in the range [First, Last) + mymap_erase_range(&m2, it1, it2); + puts("After the middle elements are deleted, the map m2 is:"); + printmap(m2); + + mymap m3 = {0}; + + // Fill in some data to test with, one at a time, using emplace + mymap_emplace(&m3, 1, "red"); + mymap_emplace(&m3, 2, "yellow"); + mymap_emplace(&m3, 3, "blue"); + mymap_emplace(&m3, 4, "green"); + mymap_emplace(&m3, 5, "orange"); + mymap_emplace(&m3, 6, "purple"); + mymap_emplace(&m3, 7, "pink"); + + puts("Starting data of map m3 is:"); + printmap(m3); + // The 3rd member function removes elements with a given Key + int count = mymap_erase(&m3, 2); + // The 3rd member function also returns the number of elements removed + printf("The number of elements removed from m3 is: %d\n", count); + puts("After the element with a key of 2 is deleted, the map m3 is:"); + printmap(m3); + + c_drop(mymap, &m1, &m2, &m3); +} diff --git a/misc/examples/sortedmaps/csmap_find.c b/misc/examples/sortedmaps/csmap_find.c new file mode 100644 index 00000000..c392338d --- /dev/null +++ b/misc/examples/sortedmaps/csmap_find.c @@ -0,0 +1,73 @@ +// This implements the c++ std::map::find example at: +// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17 +#define i_implement +#include + +#define i_key int +#define i_val_str +#define i_tag istr +#include + +#define i_key csmap_istr_raw +#define i_tag istr +#include + +void print_elem(csmap_istr_raw p) { + printf("(%d, %s) ", p.first, p.second); +} + +#define using_print_collection(CX) \ + void print_collection_##CX(const CX* t) { \ + printf("%" c_ZI " elements: ", CX##_size(t)); \ + \ + c_foreach (p, CX, *t) { \ + print_elem(CX##_value_toraw(p.ref)); \ + } \ + puts(""); \ + } + +using_print_collection(csmap_istr) +using_print_collection(cvec_istr) + +void findit(csmap_istr c, csmap_istr_key val) +{ + printf("Trying find() on value %d\n", val); + csmap_istr_iter result = csmap_istr_find(&c, val); // prefer contains() or get() + if (result.ref) { + printf("Element found: "); print_elem(csmap_istr_value_toraw(result.ref)); puts(""); + } else { + puts("Element not found."); + } +} + +int main(void) +{ + csmap_istr m1 = c_init(csmap_istr, {{40, "Zr"}, {45, "Rh"}}); + cvec_istr v = {0}; + + puts("The starting map m1 is (key, value):"); + print_collection_csmap_istr(&m1); + + typedef cvec_istr_value pair; + cvec_istr_push(&v, c_LITERAL(pair){43, "Tc"}); + cvec_istr_push(&v, c_LITERAL(pair){41, "Nb"}); + cvec_istr_push(&v, c_LITERAL(pair){46, "Pd"}); + cvec_istr_push(&v, c_LITERAL(pair){42, "Mo"}); + cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); + cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); // attempt a duplicate + + puts("Inserting the following vector data into m1:"); + print_collection_cvec_istr(&v); + + c_foreach (i, cvec_istr, cvec_istr_begin(&v), cvec_istr_end(&v)) + csmap_istr_emplace(&m1, i.ref->first, i.ref->second); + + puts("The modified map m1 is (key, value):"); + print_collection_csmap_istr(&m1); + puts(""); + findit(m1, 45); + findit(m1, 6); + + csmap_istr_drop(&m1); + cvec_istr_drop(&v); +} diff --git a/misc/examples/sortedmaps/csmap_insert.c b/misc/examples/sortedmaps/csmap_insert.c new file mode 100644 index 00000000..c9f02891 --- /dev/null +++ b/misc/examples/sortedmaps/csmap_insert.c @@ -0,0 +1,108 @@ +// This implements the std::map insert c++ example at: +// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19 +#define i_key int +#define i_val int +#define i_tag ii // Map of int => int +#include + +#define i_implement +#include +#define i_key int +#define i_val_str +#define i_tag istr // Map of int => cstr +#include + +#define i_key csmap_ii_raw +#define i_opt c_no_cmp +#define i_tag ii +#include + +void print_ii(csmap_ii map) { + c_foreach (e, csmap_ii, map) + printf("(%d, %d) ", e.ref->first, e.ref->second); + puts(""); +} + +void print_istr(csmap_istr map) { + c_foreach (e, csmap_istr, map) + printf("(%d, %s) ", e.ref->first, cstr_str(&e.ref->second)); + puts(""); +} + +int main(void) +{ + // insert single values + csmap_ii m1 = {0}; + csmap_ii_insert(&m1, 1, 10); + csmap_ii_push(&m1, c_LITERAL(csmap_ii_value){2, 20}); + + puts("The original key and mapped values of m1 are:"); + print_ii(m1); + + // intentionally attempt a duplicate, single element + csmap_ii_result ret = csmap_ii_insert(&m1, 1, 111); + if (!ret.inserted) { + csmap_ii_value pr = *ret.ref; + puts("Insert failed, element with key value 1 already exists."); + printf(" The existing element is (%d, %d)\n", pr.first, pr.second); + } + else { + puts("The modified key and mapped values of m1 are:"); + print_ii(m1); + } + puts(""); + + csmap_ii_insert(&m1, 3, 30); + puts("The modified key and mapped values of m1 are:"); + print_ii(m1); + puts(""); + + // The templatized version inserting a jumbled range + csmap_ii m2 = {0}; + cvec_ii v = {0}; + typedef cvec_ii_value ipair; + cvec_ii_push(&v, c_LITERAL(ipair){43, 294}); + cvec_ii_push(&v, c_LITERAL(ipair){41, 262}); + cvec_ii_push(&v, c_LITERAL(ipair){45, 330}); + cvec_ii_push(&v, c_LITERAL(ipair){42, 277}); + cvec_ii_push(&v, c_LITERAL(ipair){44, 311}); + + puts("Inserting the following vector data into m2:"); + c_foreach (e, cvec_ii, v) + printf("(%d, %d) ", e.ref->first, e.ref->second); + puts(""); + + c_foreach (e, cvec_ii, v) + csmap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second); + + puts("The modified key and mapped values of m2 are:"); + c_foreach (e, csmap_ii, m2) + printf("(%d, %d) ", e.ref->first, e.ref->second); + puts("\n"); + + // The templatized versions move-constructing elements + csmap_istr m3 = {0}; + csmap_istr_value ip1 = {475, cstr_lit("blue")}, ip2 = {510, cstr_lit("green")}; + + // single element + csmap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second)); + puts("After the first move insertion, m3 contains:"); + print_istr(m3); + + // single element + csmap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second)); + puts("After the second move insertion, m3 contains:"); + print_istr(m3); + puts(""); + + csmap_ii m4 = {0}; + // Insert the elements from an initializer_list + m4 = c_init(csmap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}}); + puts("After initializer_list insertion, m4 contains:"); + print_ii(m4); + puts(""); + + cvec_ii_drop(&v); + csmap_istr_drop(&m3); + c_drop(csmap_ii, &m1, &m2, &m4); +} diff --git a/misc/examples/sortedmaps/csset_erase.c b/misc/examples/sortedmaps/csset_erase.c new file mode 100644 index 00000000..9c7f5e1a --- /dev/null +++ b/misc/examples/sortedmaps/csset_erase.c @@ -0,0 +1,41 @@ +#include + +#define i_key int +#include + +int main(void) +{ + csset_int set = c_init(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50}); + + c_foreach (k, csset_int, set) + printf(" %d", *k.ref); + puts(""); + + int val = 64; + csset_int_iter it; + printf("Show values >= %d:\n", val); + it = csset_int_lower_bound(&set, val); + + c_foreach (k, csset_int, it, csset_int_end(&set)) + printf(" %d", *k.ref); + puts(""); + + printf("Erase values >= %d:\n", val); + while (it.ref) + it = csset_int_erase_at(&set, it); + + c_foreach (k, csset_int, set) + printf(" %d", *k.ref); + puts(""); + + val = 40; + printf("Erase values < %d:\n", val); + it = csset_int_lower_bound(&set, val); + csset_int_erase_range(&set, csset_int_begin(&set), it); + + c_foreach (k, csset_int, set) + printf(" %d", *k.ref); + puts(""); + + csset_int_drop(&set); +} diff --git a/misc/examples/sortedmaps/gauss2.c b/misc/examples/sortedmaps/gauss2.c new file mode 100644 index 00000000..1ab8ade5 --- /dev/null +++ b/misc/examples/sortedmaps/gauss2.c @@ -0,0 +1,45 @@ +#include +#include + +#define i_implement +#include +#include + +// Declare int -> int sorted map. +#define i_key int +#define i_val int +#include + +int main(void) +{ + enum {N = 5000000}; + uint64_t seed = (uint64_t)time(NULL); + crand_t rng = crand_init(seed); + const double Mean = round(crand_f64(&rng)*98.0 - 49.0), StdDev = crand_f64(&rng)*10.0 + 1.0, Scale = 74.0; + + printf("Demo of gaussian / normal distribution of %d random samples\n", N); + printf("Mean %f, StdDev %f\n", Mean, StdDev); + + // Setup random engine with normal distribution. + crand_norm_t dist = crand_norm_init(Mean, StdDev); + + // Create and init histogram map with defered destruct + csmap_int hist = {0}; + cstr bar = {0}; + + c_forrange (N) { + int index = (int)round(crand_norm(&rng, &dist)); + csmap_int_insert(&hist, index, 0).ref->second += 1; + } + + // Print the gaussian bar chart + c_forpair (index, count, csmap_int, hist) { + int n = (int)round((double)*_.count * StdDev * Scale * 2.5 / (double)N); + if (n > 0) { + cstr_resize(&bar, n, '*'); + printf("%4d %s\n", *_.index, cstr_str(&bar)); + } + } + cstr_drop(&bar); + csmap_int_drop(&hist); +} diff --git a/misc/examples/sortedmaps/listmap.c b/misc/examples/sortedmaps/listmap.c new file mode 100644 index 00000000..04a605a7 --- /dev/null +++ b/misc/examples/sortedmaps/listmap.c @@ -0,0 +1,65 @@ +// This implements the multimap c++ example found at: +// https://en.cppreference.com/w/cpp/container/multimap/insert + +// Multimap entries +#define i_implement +#include +#define i_key_str +#include + +// Map of int => clist_str. +#define i_type Multimap +#define i_key int +#define i_valclass clist_str // set i_val = clist_str, bind clist_str_clone and clist_str_drop +#define i_cmp -c_default_cmp // like std::greater +#include + +void print(const char* lbl, const Multimap mmap) +{ + printf("%s ", lbl); + c_foreach (e, Multimap, mmap) { + c_foreach (s, clist_str, e.ref->second) + printf("{%d,%s} ", e.ref->first, cstr_str(s.ref)); + } + puts(""); +} + +void insert(Multimap* mmap, int key, const char* str) +{ + clist_str *list = &Multimap_insert(mmap, key, clist_str_init()).ref->second; + clist_str_emplace_back(list, str); +} + +int main(void) +{ + Multimap mmap = {0}; + + // list-initialize + typedef struct {int a; const char* b;} pair; + c_forlist (i, pair, {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}}) + insert(&mmap, i.ref->a, i.ref->b); + print("#1", mmap); + + // insert using value_type + insert(&mmap, 5, "pqr"); + print("#2", mmap); + + // insert using make_pair + insert(&mmap, 6, "uvw"); + print("#3", mmap); + + insert(&mmap, 7, "xyz"); + print("#4", mmap); + + // insert using initialization_list + c_forlist (i, pair, {{5, "one"}, {5, "two"}}) + insert(&mmap, i.ref->a, i.ref->b); + print("#5", mmap); + + // FOLLOWING NOT IN ORIGINAL EXAMPLE: + // erase all entries with key 5 + Multimap_erase(&mmap, 5); + print("+5", mmap); + + Multimap_drop(&mmap); +} diff --git a/misc/examples/sortedmaps/mapmap.c b/misc/examples/sortedmaps/mapmap.c new file mode 100644 index 00000000..d3065659 --- /dev/null +++ b/misc/examples/sortedmaps/mapmap.c @@ -0,0 +1,64 @@ +// create a structure like: std::map>: +#define i_implement +#include + +// People: std::map +#define i_type People +#define i_key_str // name +#define i_val_str // email +#define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override +#include + +// Departments: std::map +#define i_type Departments +#define i_key_str // dep. name +#define i_valclass People +#include + + +void add(Departments* deps, const char* name, const char* email, const char* dep) +{ + People *people = &Departments_emplace(deps, dep, People_init()).ref->second; + People_emplace_or_assign(people, name, email); +} + +int contains(Departments* map, const char* name) +{ + int count = 0; + c_foreach (i, Departments, *map) + if (People_contains(&i.ref->second, name)) + ++count; + return count; +} + +int main(void) +{ + Departments map = {0}; + + add(&map, "Anna Kendro", "Anna@myplace.com", "Support"); + add(&map, "Terry Dane", "Terry@myplace.com", "Development"); + add(&map, "Kik Winston", "Kik@myplace.com", "Finance"); + add(&map, "Nancy Drew", "Nancy@live.com", "Development"); + add(&map, "Nick Denton", "Nick@myplace.com", "Finance"); + add(&map, "Stan Whiteword", "Stan@myplace.com", "Marketing"); + add(&map, "Serena Bath", "Serena@myplace.com", "Support"); + add(&map, "Patrick Dust", "Patrick@myplace.com", "Finance"); + add(&map, "Red Winger", "Red@gmail.com", "Marketing"); + add(&map, "Nick Denton", "Nick@yahoo.com", "Support"); + add(&map, "Colin Turth", "Colin@myplace.com", "Support"); + add(&map, "Dennis Kay", "Dennis@mail.com", "Marketing"); + add(&map, "Anne Dickens", "Anne@myplace.com", "Development"); + + c_foreach (i, Departments, map) + c_forpair (name, email, People, i.ref->second) + printf("%s: %s - %s\n", cstr_str(&i.ref->first), cstr_str(_.name), cstr_str(_.email)); + puts(""); + + printf("found Nick Denton: %d\n", contains(&map, "Nick Denton")); + printf("found Patrick Dust: %d\n", contains(&map, "Patrick Dust")); + printf("found Dennis Kay: %d\n", contains(&map, "Dennis Kay")); + printf("found Serena Bath: %d\n", contains(&map, "Serena Bath")); + puts("Done"); + + Departments_drop(&map); +} diff --git a/misc/examples/sortedmaps/multimap.c b/misc/examples/sortedmaps/multimap.c new file mode 100644 index 00000000..1068a5dc --- /dev/null +++ b/misc/examples/sortedmaps/multimap.c @@ -0,0 +1,102 @@ +#define i_implement +#include + +// Olympics multimap example + +struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = { + {2026, "Milan and Cortina d'Ampezzo", "Italy", "February 6-22"}, + {2022, "Beijing", "China", "February 4-20"}, + {2018, "PyeongChang", "South Korea", "February 9-25"}, + {2014, "Sochi", "Russia", "February 7-23"}, + {2010, "Vancouver", "Canada", "February 12-28"}, + {2006, "Torino", "Italy", "February 10-26"}, + {2002, "Salt Lake City", "United States", "February 8-24"}, + {1998, "Nagano", "Japan", "February 7-22"}, + {1994, "Lillehammer", "Norway", "February 12-27"}, + {1992, "Albertville", "France", "February 8-23"}, + {1988, "Calgary", "Canada", "February 13-28"}, + {1984, "Sarajevo", "Yugoslavia", "February 8-19"}, + {1980, "Lake Placid", "United States", "February 13-24"}, + {1976, "Innsbruck", "Austria", "February 4-15"}, + {1972, "Sapporo", "Japan", "February 3-13"}, + {1968, "Grenoble", "France", "February 6-18"}, + {1964, "Innsbruck", "Austria", "January 29-February 9"}, + {1960, "Squaw Valley", "United States", "February 18-28"}, + {1956, "Cortina d'Ampezzo", "Italy", "January 26 - February 5"}, + {1952, "Oslo", "Norway", "February 14 - 25"}, + {1948, "St. Moritz", "Switzerland", "January 30 - February 8"}, + {1944, "canceled", "canceled", "canceled"}, + {1940, "canceled", "canceled", "canceled"}, + {1936, "Garmisch-Partenkirchen", "Germany", "February 6 - 16"}, + {1932, "Lake Placid", "United States", "February 4 - 15"}, + {1928, "St. Moritz", "Switzerland", "February 11 - 19"}, + {1924, "Chamonix", "France", "January 25 - February 5"}, +}; + +typedef struct { int year; cstr city, date; } OlympicLoc; + +int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b); +OlympicLoc OlympicLoc_clone(OlympicLoc loc); +void OlympicLoc_drop(OlympicLoc* self); + +// Create a clist, can be sorted by year. +#define i_keyclass OlympicLoc // binds _cmp, _clone and _drop. +#define i_tag OL +#include + +// Create a csmap where key is country name +#define i_key_str // binds cstr_equ, cstr_hash, cstr_clone, ++ +#define i_valclass clist_OL // binds clist_OL_clone, clist_OL_drop +#define i_tag OL +#include + +int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b) { + return a->year - b->year; +} + +OlympicLoc OlympicLoc_clone(OlympicLoc loc) { + loc.city = cstr_clone(loc.city); + loc.date = cstr_clone(loc.date); + return loc; +} + +void OlympicLoc_drop(OlympicLoc* self) { + cstr_drop(&self->city); + cstr_drop(&self->date); +} + + +int main(void) +{ + // Define the multimap with destructor defered to when block is completed. + csmap_OL multimap = {0}; + const clist_OL empty = clist_OL_init(); + + for (size_t i = 0; i < c_arraylen(ol_data); ++i) + { + struct OlympicsData* d = &ol_data[i]; + OlympicLoc loc = {.year = d->year, + .city = cstr_from(d->city), + .date = cstr_from(d->date)}; + // Insert an empty list for each new country, and append the entry to the list. + // If country already exist in map, its list is returned from the insert function. + clist_OL* list = &csmap_OL_emplace(&multimap, d->country, empty).ref->second; + clist_OL_push_back(list, loc); + } + + // Sort locations by year for each country. + c_foreach (country, csmap_OL, multimap) + clist_OL_sort(&country.ref->second); + + // Print the multimap: + c_foreach (country, csmap_OL, multimap) + { + // Loop the locations for a country sorted by year + c_foreach (loc, clist_OL, country.ref->second) + printf("%s: %d, %s, %s\n", cstr_str(&country.ref->first), + loc.ref->year, + cstr_str(&loc.ref->city), + cstr_str(&loc.ref->date)); + } + csmap_OL_drop(&multimap); +} diff --git a/misc/examples/sortedmaps/new_smap.c b/misc/examples/sortedmaps/new_smap.c new file mode 100644 index 00000000..ee946c9a --- /dev/null +++ b/misc/examples/sortedmaps/new_smap.c @@ -0,0 +1,67 @@ +#define i_implement +#include +#include + +forward_csmap(PMap, struct Point, int); + +// Use forward declared PMap in struct +typedef struct { + PMap pntmap; + cstr name; +} MyStruct; + +// Point => int map +typedef struct Point { int x, y; } Point; +int point_cmp(const Point* a, const Point* b) { + int c = a->x - b->x; + return c ? c : a->y - b->y; +} + +#define i_type PMap +#define i_key Point +#define i_val int +#define i_cmp point_cmp +#define i_is_forward +#include + +// cstr => cstr map +#define i_type SMap +#define i_key_str +#define i_val_str +#include + +// cstr set +#define i_type SSet +#define i_key_str +#include + + +int main(void) +{ + PMap pmap = c_init(PMap, { + {{42, 14}, 1}, + {{32, 94}, 2}, + {{62, 81}, 3}, + }); + SMap smap = c_init(SMap, { + {"Hello, friend", "this is the mapped value"}, + {"The brown fox", "jumped"}, + {"This is the time", "for all good things"}, + }); + SSet sset = {0}; + + c_forpair (p, i, PMap, pmap) + printf(" (%d,%d: %d)", _.p->x, _.p->y, *_.i); + puts(""); + + c_forpair (i, j, SMap, smap) + printf(" (%s: %s)\n", cstr_str(_.i), cstr_str(_.j)); + + SSet_emplace(&sset, "Hello, friend"); + SSet_emplace(&sset, "Goodbye, foe"); + printf("Found? %s\n", SSet_contains(&sset, "Hello, friend") ? "true" : "false"); + + PMap_drop(&pmap); + SMap_drop(&smap); + SSet_drop(&sset); +} diff --git a/misc/examples/sortedmaps/sorted_map.c b/misc/examples/sortedmaps/sorted_map.c new file mode 100644 index 00000000..89381554 --- /dev/null +++ b/misc/examples/sortedmaps/sorted_map.c @@ -0,0 +1,67 @@ +// https://iq.opengenus.org/containers-cpp-stl/ + +#include +#define i_key int +#define i_val int +#include + +int main(void) +{ + + // empty map containers + csmap_int gquiz1 = {0}, gquiz2 = {0}; + c_defer( + csmap_int_drop(&gquiz1), + csmap_int_drop(&gquiz2) + ){ + // insert elements in random order + csmap_int_insert(&gquiz1, 2, 30); + csmap_int_insert(&gquiz1, 4, 20); + csmap_int_insert(&gquiz1, 7, 10); + csmap_int_insert(&gquiz1, 5, 50); + csmap_int_insert(&gquiz1, 3, 60); + csmap_int_insert(&gquiz1, 1, 40); + csmap_int_insert(&gquiz1, 6, 50); + + // printing map gquiz1 + printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n"); + c_foreach (itr, csmap_int, gquiz1) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // assigning the elements from gquiz1 to gquiz2 + c_foreach (i, csmap_int, gquiz1) + csmap_int_insert(&gquiz2, i.ref->first, i.ref->second); + + // print all elements of the map gquiz2 + printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n"); + c_foreach (itr, csmap_int, gquiz2) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // remove all elements up to element with key=3 in gquiz2 + printf("\ngquiz2 after removal of elements less than key=3 :\n"); + printf("\tKEY\tELEMENT\n"); + csmap_int_erase_range(&gquiz2, csmap_int_begin(&gquiz2), + csmap_int_find(&gquiz2, 3)); + c_foreach (itr, csmap_int, gquiz2) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // remove all elements with key = 4 + int num = csmap_int_erase(&gquiz2, 4); + printf("\ngquiz2.erase(4) : %d removed\n", num); + printf("\tKEY\tELEMENT\n"); + c_foreach (itr, csmap_int, gquiz2) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // lower bound and upper bound for map gquiz1 key = 5 + printf("gquiz1.lower_bound(5) : "); + printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5).ref->first); + printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5).ref->second); + printf("gquiz1.upper_bound(5) : "); + printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5+1).ref->first); + printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5+1).ref->second); + } +} diff --git a/misc/examples/spans/multidim.c b/misc/examples/spans/multidim.c new file mode 100644 index 00000000..798a1126 --- /dev/null +++ b/misc/examples/spans/multidim.c @@ -0,0 +1,67 @@ +// Example based on https://en.cppreference.com/w/cpp/container/mdspan +#define i_val int +#include +#include +#include + +using_cspan3(ispan, int); + +int main(void) +{ + cstack_int v = c_init(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}); + + // View data as contiguous memory representing 24 ints + ispan ms1 = cspan_from(&v); + + // View the same data as a 3D array 2 x 3 x 4 + ispan3 ms3 = cspan_md(v.data, 2, 3, 4); + + puts("ms3:"); + for (int i=0; i != ms3.shape[0]; i++) { + for (int j=0; j != ms3.shape[1]; j++) { + for (int k=0; k != ms3.shape[2]; k++) { + printf(" %2d", *cspan_at(&ms3, i, j, k)); + } + puts(""); + } + puts(""); + } + puts("ss3 = ms3[:, 1:3, 1:3]"); + ispan3 ss3 = ms3; + ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3}); + + for (int i=0; i != ss3.shape[0]; i++) { + for (int j=0; j != ss3.shape[1]; j++) { + for (int k=0; k != ss3.shape[2]; k++) { + printf(" %2d", *cspan_at(&ss3, i, j, k)); + } + puts(""); + } + puts(""); + } + + puts("Iterate ss3 flat:"); + c_foreach (i, ispan3, ss3) + printf(" %d", *i.ref); + puts(""); + + ispan2 ms2 = cspan_submd3(&ms3, 0); + + // write data using 2D view + for (int i=0; i != ms2.shape[0]; i++) + for (int j=0; j != ms2.shape[1]; j++) + *cspan_at(&ms2, i, j) = i*1000 + j; + + puts("\nview data as 1D view:"); + for (int i=0; i != cspan_size(&ms1); i++) + printf(" %d", *cspan_at(&ms1, i)); + puts(""); + + puts("iterate subspan ms3[1]:"); + ispan2 sub = cspan_submd3(&ms3, 1); + c_foreach (i, ispan2, sub) + printf(" %d", *i.ref); + puts(""); + + cstack_int_drop(&v); +} diff --git a/misc/examples/spans/printspan.c b/misc/examples/spans/printspan.c new file mode 100644 index 00000000..cd3c5f4f --- /dev/null +++ b/misc/examples/spans/printspan.c @@ -0,0 +1,52 @@ +// printspan.c + +#include +#define i_implement +#include +#define i_key int +#include +#define i_key int +#include +#define i_key_str +#include + +#include +using_cspan(intspan, int, 1); + +void printMe(intspan container) { + printf("%d:", (int)cspan_size(&container)); + c_foreach (e, intspan, container) + printf(" %d", *e.ref); + puts(""); +} + +int main(void) +{ + intspan sp1 = cspan_init(intspan, {1, 2}); + printMe( sp1 ); + + printMe( c_init(intspan, {1, 2, 3}) ); + + int arr[] = {1, 2, 3, 4, 5, 6}; + intspan sp2 = cspan_from_array(arr); + printMe( c_LITERAL(intspan)cspan_subspan(&sp2, 1, 4) ); + + cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5}); + printMe( c_LITERAL(intspan)cspan_from(&vec) ); + + printMe( sp2 ); + + cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7}); + printMe( c_LITERAL(intspan)cspan_from(&stk) ); + + csset_str set = c_init(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); + printf("%d:", (int)csset_str_size(&set)); + c_foreach (e, csset_str, set) + printf(" %s", cstr_str(e.ref)); + puts(""); + + // cleanup + cvec_int_drop(&vec); + cstack_int_drop(&stk); + csset_str_drop(&set); +} diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c deleted file mode 100644 index ef7ed174..00000000 --- a/misc/examples/splitstr.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#define i_import // cstr + utf8 functions -#include -#define i_implement -#include - -int main(void) -{ - puts("Split with c_fortoken (csview):"); - - c_fortoken (i, "Hello World C99!", " ") - printf("'%.*s'\n", c_SV(i.token)); - - puts("\nSplit with c_formatch (regex):"); - - cregex re = cregex_from("[^ ]+"); - c_formatch (i, &re, " Hello World C99! ") - printf("'%.*s'\n", c_SV(i.match[0])); - - cregex_drop(&re); -} diff --git a/misc/examples/sso_map.c b/misc/examples/sso_map.c deleted file mode 100644 index 4f84b651..00000000 --- a/misc/examples/sso_map.c +++ /dev/null @@ -1,19 +0,0 @@ -#define i_implement -#include -#define i_key_str -#define i_val_str -#include - -int main(void) -{ - cmap_str m = {0}; - cmap_str_emplace(&m, "Test short", "This is a short string"); - cmap_str_emplace(&m, "Test long ", "This is a longer string"); - - c_forpair (k, v, cmap_str, m) - printf("%s: '%s' Len=%" c_ZI ", Is long: %s\n", - cstr_str(_.k), cstr_str(_.v), cstr_size(_.v), - cstr_is_long(_.v) ? "true" : "false"); - - cmap_str_drop(&m); -} diff --git a/misc/examples/sso_substr.c b/misc/examples/sso_substr.c deleted file mode 100644 index 687658df..00000000 --- a/misc/examples/sso_substr.c +++ /dev/null @@ -1,21 +0,0 @@ -#define i_implement -#include -#define i_implement -#include - -int main(void) -{ - cstr str = cstr_lit("We think in generalities, but we live in details."); - csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" - intptr_t pos = cstr_find(&str, "live"); // position of "live" - csview sv2 = cstr_substr_ex(&str, pos, 4); // "live" - csview sv3 = cstr_slice_ex(&str, -8, -1); // "details" - printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); - - cstr_assign(&str, "apples are green or red"); - cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red" - cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples" - printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), - cstr_is_long(&str), cstr_is_long(&s2)); - c_drop (cstr, &str, &s2, &s3); -} diff --git a/misc/examples/stack.c b/misc/examples/stack.c deleted file mode 100644 index 6297fb6f..00000000 --- a/misc/examples/stack.c +++ /dev/null @@ -1,32 +0,0 @@ - -#include - -#define i_tag i -#define i_capacity 100 -#define i_key int -#include - -#define i_tag c -#define i_key char -#include - -int main(void) { - cstack_i stack = {0}; - cstack_c chars = {0}; - - c_forrange (i, 101) - cstack_i_push(&stack, (int)(i*i)); - - printf("%d\n", *cstack_i_top(&stack)); - - c_forrange (i, 90) - cstack_i_pop(&stack); - - c_foreach (i, cstack_i, stack) - printf(" %d", *i.ref); - puts(""); - printf("top: %d\n", *cstack_i_top(&stack)); - - cstack_i_drop(&stack); - cstack_c_drop(&chars); -} diff --git a/misc/examples/strings/cstr_match.c b/misc/examples/strings/cstr_match.c new file mode 100644 index 00000000..be03e981 --- /dev/null +++ b/misc/examples/strings/cstr_match.c @@ -0,0 +1,26 @@ +#define i_implement +#include +#include +#include + +int main(void) +{ + cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"); + + intptr_t pos = cstr_find_at(&ss, 0, "brown"); + printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "" : cstr_str(&ss) + pos); + printf("equals: %d\n", cstr_equals(&ss, "The quick brown fox jumps over the lazy dog.JPG")); + printf("contains: %d\n", cstr_contains(&ss, "umps ove")); + printf("starts_with: %d\n", cstr_starts_with(&ss, "The quick brown")); + printf("ends_with: %d\n", cstr_ends_with(&ss, ".jpg")); + printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); + + cstr s1 = cstr_lit("hell😀 w😀rl🐨"); + csview ch1 = cstr_u8_chr(&s1, 7); + csview ch2 = cstr_u8_chr(&s1, 10); + printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); + printf("ch1: %.*s\n", c_SV(ch1)); + printf("ch2: %.*s\n", c_SV(ch2)); + + c_drop(cstr, &ss, &s1); +} diff --git a/misc/examples/strings/replace.c b/misc/examples/strings/replace.c new file mode 100644 index 00000000..59a56bf7 --- /dev/null +++ b/misc/examples/strings/replace.c @@ -0,0 +1,36 @@ +#define i_implement +#include + +int main(void) +{ + const char *base = "this is a test string."; + const char *s2 = "n example"; + const char *s3 = "sample phrase"; + + // replace signatures used in the same order as described above: + + // Ustring positions: 0123456789*123456789*12345 + cstr s = cstr_from(base); // "this is a test string." + cstr m = cstr_clone(s); + + cstr_append(&m, cstr_str(&m)); + cstr_append(&m, cstr_str(&m)); + printf("%s\n", cstr_str(&m)); + + cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) + printf("(1) %s\n", cstr_str(&s)); + + cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) + printf("(2) %s\n", cstr_str(&s)); + + cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) + printf("(3) %s\n", cstr_str(&s)); + + cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) + printf("(4) %s\n", cstr_str(&s)); + + cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) + printf("(5) %s\n", cstr_str(&s)); + + c_drop(cstr, &s, &m); +} diff --git a/misc/examples/strings/splitstr.c b/misc/examples/strings/splitstr.c new file mode 100644 index 00000000..ef7ed174 --- /dev/null +++ b/misc/examples/strings/splitstr.c @@ -0,0 +1,21 @@ +#include +#define i_import // cstr + utf8 functions +#include +#define i_implement +#include + +int main(void) +{ + puts("Split with c_fortoken (csview):"); + + c_fortoken (i, "Hello World C99!", " ") + printf("'%.*s'\n", c_SV(i.token)); + + puts("\nSplit with c_formatch (regex):"); + + cregex re = cregex_from("[^ ]+"); + c_formatch (i, &re, " Hello World C99! ") + printf("'%.*s'\n", c_SV(i.match[0])); + + cregex_drop(&re); +} diff --git a/misc/examples/strings/sso_map.c b/misc/examples/strings/sso_map.c new file mode 100644 index 00000000..4f84b651 --- /dev/null +++ b/misc/examples/strings/sso_map.c @@ -0,0 +1,19 @@ +#define i_implement +#include +#define i_key_str +#define i_val_str +#include + +int main(void) +{ + cmap_str m = {0}; + cmap_str_emplace(&m, "Test short", "This is a short string"); + cmap_str_emplace(&m, "Test long ", "This is a longer string"); + + c_forpair (k, v, cmap_str, m) + printf("%s: '%s' Len=%" c_ZI ", Is long: %s\n", + cstr_str(_.k), cstr_str(_.v), cstr_size(_.v), + cstr_is_long(_.v) ? "true" : "false"); + + cmap_str_drop(&m); +} diff --git a/misc/examples/strings/sso_substr.c b/misc/examples/strings/sso_substr.c new file mode 100644 index 00000000..687658df --- /dev/null +++ b/misc/examples/strings/sso_substr.c @@ -0,0 +1,21 @@ +#define i_implement +#include +#define i_implement +#include + +int main(void) +{ + cstr str = cstr_lit("We think in generalities, but we live in details."); + csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" + intptr_t pos = cstr_find(&str, "live"); // position of "live" + csview sv2 = cstr_substr_ex(&str, pos, 4); // "live" + csview sv3 = cstr_slice_ex(&str, -8, -1); // "details" + printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); + + cstr_assign(&str, "apples are green or red"); + cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red" + cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples" + printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), + cstr_is_long(&str), cstr_is_long(&s2)); + c_drop (cstr, &str, &s2, &s3); +} diff --git a/misc/examples/strings/sview_split.c b/misc/examples/strings/sview_split.c new file mode 100644 index 00000000..ac275da0 --- /dev/null +++ b/misc/examples/strings/sview_split.c @@ -0,0 +1,20 @@ +#define i_implement +#include +#define i_implement +#include + +int main(void) +{ + // No memory allocations or string length calculations! + const csview date = c_sv("2021/03/12"); + intptr_t pos = 0; + const csview year = csview_token(date, "/", &pos); + const csview month = csview_token(date, "/", &pos); + const csview day = csview_token(date, "/", &pos); + + printf("%.*s, %.*s, %.*s\n", c_SV(year), c_SV(month), c_SV(day)); + + cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); + printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); + c_drop(cstr, &y, &m, &d); +} diff --git a/misc/examples/strings/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c new file mode 100644 index 00000000..1d54486f --- /dev/null +++ b/misc/examples/strings/utf8replace_c.c @@ -0,0 +1,25 @@ +#define i_implement +#include + +int main(void) +{ + cstr hello = cstr_lit("hell😀 w😀rld"); + printf("%s\n", cstr_str(&hello)); + + /* replace second smiley at utf8 codepoint pos 7 */ + cstr_u8_replace_at(&hello, + cstr_u8_to_pos(&hello, 7), + 1, + c_sv("🐨") + ); + printf("%s\n", cstr_str(&hello)); + + c_foreach (c, cstr, hello) + printf("%.*s,", c_SV(c.u8.chr)); + + cstr str = cstr_lit("scooby, dooby doo"); + cstr_replace(&str, "oo", "00"); + printf("\n%s\n", cstr_str(&str)); + + c_drop(cstr, &hello, &str); +} diff --git a/misc/examples/strings/utf8replace_rs.rs b/misc/examples/strings/utf8replace_rs.rs new file mode 100644 index 00000000..8b163b4e --- /dev/null +++ b/misc/examples/strings/utf8replace_rs.rs @@ -0,0 +1,22 @@ +pub fn main() { + let mut hello = String::from("hell😀 w😀rld"); + println!("{}", hello); + + /* replace second smiley at utf8 codepoint pos 7 */ + hello.replace_range( + hello + .char_indices() + .nth(7) + .map(|(pos, ch)| (pos..pos + ch.len_utf8())) + .unwrap(), + "🐨", + ); + println!("{}", hello); + + for c in hello.chars() { + print!("{},", c); + } + + let str = "If you find the time, you will find the winner"; + println!("\n{}", str.replace("find", "match")); +} diff --git a/misc/examples/sview_split.c b/misc/examples/sview_split.c deleted file mode 100644 index ac275da0..00000000 --- a/misc/examples/sview_split.c +++ /dev/null @@ -1,20 +0,0 @@ -#define i_implement -#include -#define i_implement -#include - -int main(void) -{ - // No memory allocations or string length calculations! - const csview date = c_sv("2021/03/12"); - intptr_t pos = 0; - const csview year = csview_token(date, "/", &pos); - const csview month = csview_token(date, "/", &pos); - const csview day = csview_token(date, "/", &pos); - - printf("%.*s, %.*s, %.*s\n", c_SV(year), c_SV(month), c_SV(day)); - - cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); - printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); - c_drop(cstr, &y, &m, &d); -} diff --git a/misc/examples/triples.c b/misc/examples/triples.c deleted file mode 100644 index 9f2fcc1e..00000000 --- a/misc/examples/triples.c +++ /dev/null @@ -1,72 +0,0 @@ -// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ - -#include -#include - -int gcd(int a, int b) { - while (b) { - int t = a % b; - a = b; - b = t; - } - return a; -} - -void triples_vanilla(int n) { - for (int c = 5, i = 0; n; ++c) { - for (int a = 1; a < c; ++a) { - for (int b = a + 1; b < c; ++b) { - if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c && gcd(a, b) == 1) { - printf("%d: {%d, %d, %d}\n", ++i, a, b, c); - if (--n == 0) goto done; - } - } - } - } - done:; -} - -struct triples { - int size, count; - int a, b, c; - int cco_state; -}; - -int triples_coro(struct triples* t) { - cco_routine(t) { - t->count = 0; - for (t->c = 5; t->size; ++t->c) { - for (t->a = 1; t->a < t->c; ++t->a) { - for (t->b = t->a + 1; t->b < t->c; ++t->b) { - if ((int64_t)t->a*t->a + (int64_t)t->b*t->b == (int64_t)t->c*t->c) { - if (t->count++ == t->size) - cco_return; - cco_yield(); - } - } - } - } - cco_cleanup: - puts("done"); - } - return 0; -} - -int main(void) -{ - puts("Vanilla triples:"); - triples_vanilla(5); - - puts("\nCoroutine triples:"); - struct triples t = {.size=INT32_MAX}; - int n = 0; - - while (triples_coro(&t)) { - if (gcd(t.a, t.b) > 1) - continue; - if (t.c < 100) - printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c); - else - cco_stop(&t); - } -} diff --git a/misc/examples/unordered_set.c b/misc/examples/unordered_set.c deleted file mode 100644 index dd899d78..00000000 --- a/misc/examples/unordered_set.c +++ /dev/null @@ -1,45 +0,0 @@ -// https://iq.opengenus.org/containers-cpp-stl/ -// C program to demonstrate various function of stc cset -#define i_implement -#include -#define i_key_str -#include - -int main(void) -{ - // declaring set for storing string data-type - cset_str stringSet = {0}; - c_defer( - cset_str_drop(&stringSet) - ){ - // inserting various string, same string will be stored - // once in set - cset_str_emplace(&stringSet, "code"); - cset_str_emplace(&stringSet, "in"); - cset_str_emplace(&stringSet, "C"); - cset_str_emplace(&stringSet, "is"); - cset_str_emplace(&stringSet, "fast"); - - const char* key = "slow"; - - // find returns end iterator if key is not found, - // else it returns iterator to that key - - if (cset_str_find(&stringSet, key).ref == NULL) - printf("\"%s\" not found\n", key); - else - printf("Found \"%s\"\n", key); - - key = "C"; - if (!cset_str_contains(&stringSet, key)) - printf("\"%s\" not found\n", key); - else - printf("Found \"%s\"\n", key); - - // now iterating over whole set and printing its - // content - printf("All elements :\n"); - c_foreach (itr, cset_str, stringSet) - printf("%s\n", cstr_str(itr.ref)); - } -} diff --git a/misc/examples/utf8replace_c.c b/misc/examples/utf8replace_c.c deleted file mode 100644 index 1d54486f..00000000 --- a/misc/examples/utf8replace_c.c +++ /dev/null @@ -1,25 +0,0 @@ -#define i_implement -#include - -int main(void) -{ - cstr hello = cstr_lit("hell😀 w😀rld"); - printf("%s\n", cstr_str(&hello)); - - /* replace second smiley at utf8 codepoint pos 7 */ - cstr_u8_replace_at(&hello, - cstr_u8_to_pos(&hello, 7), - 1, - c_sv("🐨") - ); - printf("%s\n", cstr_str(&hello)); - - c_foreach (c, cstr, hello) - printf("%.*s,", c_SV(c.u8.chr)); - - cstr str = cstr_lit("scooby, dooby doo"); - cstr_replace(&str, "oo", "00"); - printf("\n%s\n", cstr_str(&str)); - - c_drop(cstr, &hello, &str); -} diff --git a/misc/examples/utf8replace_rs.rs b/misc/examples/utf8replace_rs.rs deleted file mode 100644 index 8b163b4e..00000000 --- a/misc/examples/utf8replace_rs.rs +++ /dev/null @@ -1,22 +0,0 @@ -pub fn main() { - let mut hello = String::from("hell😀 w😀rld"); - println!("{}", hello); - - /* replace second smiley at utf8 codepoint pos 7 */ - hello.replace_range( - hello - .char_indices() - .nth(7) - .map(|(pos, ch)| (pos..pos + ch.len_utf8())) - .unwrap(), - "🐨", - ); - println!("{}", hello); - - for c in hello.chars() { - print!("{},", c); - } - - let str = "If you find the time, you will find the winner"; - println!("\n{}", str.replace("find", "match")); -} diff --git a/misc/examples/vectors/lower_bound.c b/misc/examples/vectors/lower_bound.c new file mode 100644 index 00000000..bea828f2 --- /dev/null +++ b/misc/examples/vectors/lower_bound.c @@ -0,0 +1,66 @@ +#include + +#define i_key int +#define i_cmp_native +#include + +#define i_key int +#include + +int main(void) +{ + // TEST SORTED VECTOR + { + int key, *res; + cvec_int vec = c_init(cvec_int, {40, 600, 1, 7000, 2, 500, 30}); + + cvec_int_sort(&vec); + + key = 100; + res = cvec_int_lower_bound(&vec, key).ref; + if (res) + printf("Sorted Vec %d: lower bound: %d\n", key, *res); // 500 + + key = 10; + cvec_int_iter it1 = cvec_int_lower_bound(&vec, key); + if (it1.ref) + printf("Sorted Vec %3d: lower_bound: %d\n", key, *it1.ref); // 30 + + key = 600; + cvec_int_iter it2 = cvec_int_binary_search(&vec, key); + if (it2.ref) + printf("Sorted Vec %d: bin. search: %d\n", key, *it2.ref); // 600 + + c_foreach (i, cvec_int, it1, it2) + printf(" %d\n", *i.ref); + + puts(""); + cvec_int_drop(&vec); + } + + // TEST SORTED SET + { + int key, *res; + csset_int set = c_init(csset_int, {40, 600, 1, 7000, 2, 500, 30}); + + key = 100; + res = csset_int_lower_bound(&set, key).ref; + if (res) + printf("Sorted Set %d: lower bound: %d\n", key, *res); // 500 + + key = 10; + csset_int_iter it1 = csset_int_lower_bound(&set, key); + if (it1.ref) + printf("Sorted Set %3d: lower bound: %d\n", key, *it1.ref); // 30 + + key = 600; + csset_int_iter it2 = csset_int_find(&set, key); + if (it2.ref) + printf("Sorted Set %d: find : %d\n", key, *it2.ref); // 600 + + c_foreach (i, csset_int, it1, it2) + printf(" %d\n", *i.ref); + + csset_int_drop(&set); + } +} diff --git a/misc/examples/vectors/new_vec.c b/misc/examples/vectors/new_vec.c new file mode 100644 index 00000000..88efd55a --- /dev/null +++ b/misc/examples/vectors/new_vec.c @@ -0,0 +1,43 @@ +#include +#include + +forward_cvec(cvec_i32, int); +forward_cvec(cvec_pnt, struct Point); + +typedef struct MyStruct { + cvec_i32 intvec; + cvec_pnt pntvec; +} MyStruct; + +#define i_key int +#define i_tag i32 +#define i_is_forward +#include + +typedef struct Point { int x, y; } Point; + +#define i_key Point +#define i_tag pnt +#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) +#define i_eq(a, b) a->x == b->x && a->y == b->y +#define i_is_forward +#include + +int main(void) +{ + MyStruct my = {0}; + + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){42, 14}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 94}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){62, 81}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 91}); + + cvec_pnt_sort(&my.pntvec); + + c_foreach (i, cvec_pnt, my.pntvec) + printf(" (%d %d)", i.ref->x, i.ref->y); + puts(""); + + cvec_i32_drop(&my.intvec); + cvec_pnt_drop(&my.pntvec); +} diff --git a/misc/examples/vectors/stack.c b/misc/examples/vectors/stack.c new file mode 100644 index 00000000..6297fb6f --- /dev/null +++ b/misc/examples/vectors/stack.c @@ -0,0 +1,32 @@ + +#include + +#define i_tag i +#define i_capacity 100 +#define i_key int +#include + +#define i_tag c +#define i_key char +#include + +int main(void) { + cstack_i stack = {0}; + cstack_c chars = {0}; + + c_forrange (i, 101) + cstack_i_push(&stack, (int)(i*i)); + + printf("%d\n", *cstack_i_top(&stack)); + + c_forrange (i, 90) + cstack_i_pop(&stack); + + c_foreach (i, cstack_i, stack) + printf(" %d", *i.ref); + puts(""); + printf("top: %d\n", *cstack_i_top(&stack)); + + cstack_i_drop(&stack); + cstack_c_drop(&chars); +} diff --git a/misc/examples/vikings.c b/misc/examples/vikings.c deleted file mode 100644 index d6125854..00000000 --- a/misc/examples/vikings.c +++ /dev/null @@ -1,59 +0,0 @@ -#define i_implement -#include - -typedef struct Viking { - cstr name; - cstr country; -} Viking; - -void Viking_drop(Viking* vk) { - cstr_drop(&vk->name); - cstr_drop(&vk->country); -} - -// Define Viking lookup struct with hash, cmp, and convertion functions between Viking and RViking structs: - -typedef struct RViking { - const char* name; - const char* country; -} RViking; - -static inline int RViking_cmp(const RViking* rx, const RViking* ry) { - int c = strcmp(rx->name, ry->name); - return c ? c : strcmp(rx->country, ry->country); -} - -static inline Viking Viking_from(RViking raw) { // note: parameter is by value - return c_LITERAL(Viking){cstr_from(raw.name), cstr_from(raw.country)}; -} - -static inline RViking Viking_toraw(const Viking* vp) { - return c_LITERAL(RViking){cstr_str(&vp->name), cstr_str(&vp->country)}; -} - -// With this in place, we define the Viking => int hash map type: -#define i_type Vikings -#define i_keyclass Viking // key type -#define i_rawclass RViking // lookup type -#define i_keyfrom Viking_from -#define i_opt c_no_clone -#define i_hash(rp) cstrhash(rp->name) ^ cstrhash(rp->country) -#define i_val int // mapped type -#include - -int main(void) -{ - Vikings vikings = {0}; - Vikings_emplace(&vikings, c_LITERAL(RViking){"Einar", "Norway"}, 20); - Vikings_emplace(&vikings, c_LITERAL(RViking){"Olaf", "Denmark"}, 24); - Vikings_emplace(&vikings, c_LITERAL(RViking){"Harald", "Iceland"}, 12); - Vikings_emplace(&vikings, c_LITERAL(RViking){"Björn", "Sweden"}, 10); - - Vikings_value* v = Vikings_get_mut(&vikings, c_LITERAL(RViking){"Einar", "Norway"}); - v->second += 3; // add 3 hp points to Einar - - c_forpair (vk, hp, Vikings, vikings) { - printf("%s of %s has %d hp\n", cstr_str(&_.vk->name), cstr_str(&_.vk->country), *_.hp); - } - Vikings_drop(&vikings); -} -- cgit v1.2.3 From 2d67f4040f6eecd41f1b864b43c62823ed75aff0 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 21 Jul 2023 00:37:28 +0200 Subject: Renamed badly abbreviated names in crand.h. Moved coroutine.h from algo subfolder to stc. Updated coroutine.h and docs. --- docs/ccommon_api.md | 7 +- docs/cpque_api.md | 4 +- docs/crandom_api.md | 47 +++-- include/stc/algo/coroutine.h | 274 ------------------------- include/stc/algorithm.h | 8 + include/stc/calgo.h | 9 - include/stc/coroutine.h | 273 ++++++++++++++++++++++++ include/stc/crand.h | 43 ++-- misc/examples/algorithms/forfilter.c | 3 +- misc/examples/algorithms/forloops.c | 2 +- misc/examples/algorithms/random.c | 20 +- misc/examples/bitsets/prime.c | 22 +- misc/examples/coroutines/cointerleave.c | 2 +- misc/examples/coroutines/coread.c | 2 +- misc/examples/coroutines/coroutines.c | 2 +- misc/examples/coroutines/cotasks1.c | 2 +- misc/examples/coroutines/cotasks2.c | 12 +- misc/examples/coroutines/dining_philosophers.c | 2 +- misc/examples/coroutines/generator.c | 2 +- misc/examples/coroutines/scheduler.c | 2 +- misc/examples/coroutines/triples.c | 2 +- misc/examples/linkedlists/list.c | 2 +- misc/examples/make.sh | 8 +- misc/examples/priorityqueues/priority.c | 6 +- misc/examples/queues/new_queue.c | 6 +- misc/examples/queues/queue.c | 8 +- misc/examples/sortedmaps/gauss2.c | 4 +- misc/examples/spans/mdspan.c | 51 +++++ 28 files changed, 436 insertions(+), 389 deletions(-) delete mode 100644 include/stc/algo/coroutine.h create mode 100644 include/stc/algorithm.h delete mode 100644 include/stc/calgo.h create mode 100644 include/stc/coroutine.h create mode 100644 misc/examples/spans/mdspan.c diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 1e1ae1aa..9189d7e8 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -392,8 +392,7 @@ cco_routine scope; Use `if-else-if` constructs instead. | | `cco_return;` | Return from coroutine (inside cco_routine) | | | Task objects: | | | | `cco_task_struct(Name, ...);` | Define a coroutine task struct | -| | `cco_await_task(task, ...);` | Await for task to finish or optionally yield a value | -| | `cco_block_task(task);` | Run blocking until task is finished (stackless) | +| | `cco_task_await(task, ...);` | Await for task to finish or optionally yield a value | | | Semaphores: | | | | `cco_sem` | Semaphore type | | `cco_sem` | `cco_sem_from(long value)` | Create semaphore | @@ -414,7 +413,9 @@ cco_routine scope; Use `if-else-if` constructs instead. | `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | | `void` | `cco_block_on(cocall) { }` | Run blocking until cocall is finished | -| `void` | `cco_block_on(cocall, int *result) { }`| Run blocking until cocall is finished | +| `void` | `cco_block_on(cocall, int *result) {}`| Run blocking until cocall is finished | +| | `cco_task_block_on(task) {}` | Run blocking until task is finished | +| | `cco_task_block_on(task, rt, STACKSZ) {}`| Run blocking until task is finished | | | Time functions: | | | `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | | | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | diff --git a/docs/cpque_api.md b/docs/cpque_api.md index 4cde927b..247424b4 100644 --- a/docs/cpque_api.md +++ b/docs/cpque_api.md @@ -72,14 +72,14 @@ int main(void) { intptr_t N = 10000000; crand_t rng = crand_init(1234); - crand_unif_t dist = crand_unif_init(0, N * 10); + crand_uniform_t dist = crand_uniform_init(0, N * 10); // Define heap cpque_i heap = {0}; // Push ten million random numbers to priority queue. c_forrange (N) - cpque_i_push(&heap, crand_unif(&rng, &dist)); + cpque_i_push(&heap, crand_uniform(&rng, &dist)); // Add some negative ones. int nums[] = {-231, -32, -873, -4, -343}; diff --git a/docs/crandom_api.md b/docs/crandom_api.md index 22a4f4dd..88924784 100644 --- a/docs/crandom_api.md +++ b/docs/crandom_api.md @@ -1,30 +1,29 @@ # STC [crand](../include/stc/crand.h): Pseudo Random Number Generator ![Random](pics/random.jpg) -This features a *64-bit PRNG* named **stc64**, and can generate bounded uniform and normal +This features a *64-bit PRNG* named **crand64**, and can generate bounded uniform and normal distributed random numbers. See [random](https://en.cppreference.com/w/cpp/header/random) for similar c++ functionality. ## Description -**stc64** is a novel, extremely fast PRNG by Tyge Løvset, suited for parallel usage. It features -Weyl-sequences as part of its state. It is inspired on *sfc64*, but has a different output function +**crand64** is a novel, very fast PRNG, suited for parallel usage. It features a +Weyl-sequence as part of its state. It is based on *sfc64*, but has a different output function and state size. -**sfc64** is the fastest among *pcg*, *xoshiro`**`*, and *lehmer*. It is equally fast as *sfc64* on -most platforms. *wyrand* is faster on platforms with fast 128-bit multiplication, and has 2^64 period -length (https://github.com/lemire/SwiftWyhash/issues/10). However, *wyrand* is not suited for massive -parallel usage due to its limited total minimal period length. +**sfc64** is the fastest among *pcg*, *xoshiro`**`*, and *lehmer*. It is equally fast or faster than +*sfc64* on most platforms. *wyrand* is faster on platforms with fast 128-bit multiplication, and has +2^64 period (https://github.com/lemire/SwiftWyhash/issues/10). *wyrand* is not suited for massive +parallel usage due to its limited minimal period. -**stc64** does not require multiplication or 128-bit integer operations. It has 320 bit state, -but updates only 256 bit per generated number. +**crand64** does not require multiplication or 128-bit integer operations. It has 320 bit state, +where 64-bits are constant per prng instance created. There is no *jump function*, but each odd number Weyl-increment (state[4]) starts a new -unique 2^64 *minimum* length period. For a single thread, a minimum period of 2^127 is generated -when the Weyl-increment is incremented by 2 every 2^64 output. +unique 2^64 *minimum* length period, i.e. virtually unlimitied number of unique threads. -**stc64** passes *PractRand* (tested up to 8TB output), Vigna's Hamming weight test, and simple +**crand64** passes *PractRand* (tested up to 8TB output), Vigna's Hamming weight test, and simple correlation tests, i.e. *n* interleaved streams with only one-bit differences in initial state. Also 32-bit and 16-bit versions passes PractRand up to their size limits. @@ -41,27 +40,27 @@ All crand definitions and prototypes are available by including a single header ## Methods ```c -void csrand(uint64_t seed); // seed global stc64 prng +void csrand(uint64_t seed); // seed global crand64 prng uint64_t crand(void); // global crand_u64(rng) double crandf(void); // global crand_f64(rng) -crand_t crand_init(uint64_t seed); // stc64_init(s) is deprecated +crand_t crand_init(uint64_t seed); uint64_t crand_u64(crand_t* rng); // range [0, 2^64 - 1] double crand_f64(crand_t* rng); // range [0.0, 1.0) -crand_unif_t crand_unif_init(int64_t low, int64_t high); // uniform-distribution -int64_t crand_unif(crand_t* rng, crand_unif_t* dist); // range [low, high] +crand_uniform_t crand_uniform_init(int64_t low, int64_t high); // uniform-distribution range +int64_t crand_uniform(crand_t* rng, crand_uniform_t* dist); -crand_norm_t crand_norm_init(double mean, double stddev); // normal-distribution -double crand_norm(crand_t* rng, crand_norm_t* dist); +crand_normal_t crand_normal_init(double mean, double stddev); // normal-gauss distribution +double crand_normal(crand_t* rng, crand_normal_t* dist); ``` ## Types | Name | Type definition | Used to represent... | |:-------------------|:------------------------------------------|:-----------------------------| | `crand_t` | `struct {uint64_t state[4];}` | The PRNG engine type | -| `crand_unif_t` | `struct {int64_t lower; uint64_t range;}` | Integer uniform distribution | -| `crand_norm_t` | `struct {double mean, stddev;}` | Normal distribution type | +| `crand_uniform_t` | `struct {int64_t lower; uint64_t range;}` | Integer uniform distribution | +| `crand_normal_t` | `struct {double mean, stddev;}` | Normal distribution type | ## Example ```c @@ -86,17 +85,17 @@ int main(void) // Setup random engine with normal distribution. uint64_t seed = time(NULL); crand_t rng = crand_init(seed); - crand_norm_t dist = crand_norm_init(Mean, StdDev); + crand_normal_t dist = crand_normal_init(Mean, StdDev); // Create histogram map - csmap_i mhist = csmap_i_init(); + csmap_i mhist = {0}; c_forrange (N) { - int index = (int)round(crand_norm(&rng, &dist)); + int index = (int)round(crand_normal(&rng, &dist)); csmap_i_emplace(&mhist, index, 0).ref->second += 1; } // Print the gaussian bar chart - cstr bar = cstr_init(); + cstr bar = {0}; c_foreach (i, csmap_i, mhist) { int n = (int)(i.ref->second * StdDev * Scale * 2.5 / N); if (n > 0) { diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h deleted file mode 100644 index 7c6989c3..00000000 --- a/include/stc/algo/coroutine.h +++ /dev/null @@ -1,274 +0,0 @@ -/* MIT License - * - * Copyright (c) 2023 Tyge Løvset - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef STC_COROUTINE_INCLUDED -#define STC_COROUTINE_INCLUDED -/* -#include -#include - -struct iterpair { - int max_x, max_y; - int x, y; - int cco_state; // required member -}; - -int iterpair(struct iterpair* I) { - cco_routine(I) { - for (I->x = 0; I->x < I->max_x; I->x++) - for (I->y = 0; I->y < I->max_y; I->y++) - cco_yield(); - - cco_cleanup: // required if there is cleanup code - puts("final"); - } - return 0; // CCO_DONE -} - -int main(void) { - struct iterpair it = {.max_x=3, .max_y=3}; - int n = 0; - while (iterpair(&it)) - { - printf("%d %d\n", it.x, it.y); - // example of early stop: - if (++n == 7) cco_stop(&it); // signal to stop/finalize in next - } - return 0; -} -*/ -#include "../ccommon.h" - -enum { - CCO_STATE_CLEANUP = -1, - CCO_STATE_DONE = -2, -}; -typedef enum { - CCO_DONE = 0, - CCO_AWAIT = 1<<0, - CCO_YIELD = 1<<1, -} cco_result; - -#define cco_initial(co) ((co)->cco_state == 0) -#define cco_suspended(co) ((co)->cco_state > 0) -#define cco_done(co) ((co)->cco_state == CCO_STATE_DONE) - -#define cco_routine(co) \ - for (int *_state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ - _resume: switch (*_state) case 0: // thanks, @liigo! - -#define cco_yield() cco_yield_v(CCO_YIELD) -#define cco_yield_v(ret) \ - do { \ - *_state = __LINE__; return ret; goto _resume; \ - case __LINE__:; \ - } while (0) - -#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT) -#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__) -#define cco_await_v_1(promise) cco_await_v_2(promise, ) -#define cco_await_v_2(promise, ret) \ - do { \ - *_state = __LINE__; \ - case __LINE__: if (!(promise)) {return ret; goto _resume;} \ - } while (0) - -/* cco_await_on(): assumes coroutine returns a cco_result value (int) */ -#define cco_await_on(corocall) \ - do { \ - *_state = __LINE__; \ - case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \ - } while (0) - -/* cco_block_on(): assumes coroutine returns a cco_result value (int) */ -#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) -#define cco_block_on_1(corocall) while ((corocall) != CCO_DONE) -#define cco_block_on_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) - -#define cco_cleanup \ - *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP - -#define cco_return \ - do { \ - *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ - goto _resume; \ - } while (0) - -#define cco_yield_final() cco_yield_final_v(CCO_YIELD) -#define cco_yield_final_v(value) \ - do { \ - *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ - return value; \ - } while (0) - -#define cco_stop(co) \ - do { \ - int* _s = &(co)->cco_state; \ - if (*_s > 0) *_s = CCO_STATE_CLEANUP; \ - else if (*_s == 0) *_s = CCO_STATE_DONE; \ - } while (0) - -#define cco_reset(co) \ - (void)((co)->cco_state = 0) - -/* - * Tasks (optional) - */ - -struct cco_runtime; - -#define cco_task_struct(Name, ...) \ - struct Name { \ - int (*cco_fn)(struct Name*, struct cco_runtime*); \ - int cco_state, cco_expect; \ - __VA_ARGS__ \ - } - -typedef cco_task_struct(cco_task, /**/) cco_task; - -typedef struct cco_runtime { - int result, top; - cco_task* stack[]; -} cco_runtime; - -#define cco_cast_task(task) \ - ((cco_task *)(task) + 0*sizeof((task)->cco_fn(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) - -#define cco_resume(task, rt) \ - (task)->cco_fn(task, rt) - -#define cco_block_task(...) c_MACRO_OVERLOAD(cco_block_task, __VA_ARGS__) -#define cco_block_task_1(task) cco_block_task_3(task, rt, 16) -#define cco_block_task_3(task, rt, STACKDEPTH) \ - for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ - (((rt.result = cco_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) - -#define cco_await_task(...) c_MACRO_OVERLOAD(cco_await_task, __VA_ARGS__) -#define cco_await_task_2(task, rt) cco_await_task_3(task, rt, CCO_DONE) -#define cco_await_task_3(task, rt, resultbits) \ - do { \ - cco_runtime* _rt = rt; \ - (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = ~(resultbits); \ - cco_yield_v(CCO_AWAIT); \ - } while (0) - -/* - * Semaphore - */ - -typedef struct { intptr_t count; } cco_sem; - -#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT) -#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__) -#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, ) -#define cco_sem_await_v_2(sem, ret) \ - do { \ - cco_await_v_2((sem)->count > 0, ret); \ - --(sem)->count; \ - } while (0) - -#define cco_sem_release(sem) ++(sem)->count -#define cco_sem_from(value) ((cco_sem){value}) -#define cco_sem_set(sem, value) ((sem)->count = value) - -/* - * Timer - */ - -#ifdef _WIN32 - #ifdef __cplusplus - #define _c_LINKC extern "C" __declspec(dllimport) - #else - #define _c_LINKC __declspec(dllimport) - #endif - #if 1 // _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__ - #define _c_getsystime GetSystemTimeAsFileTime - #else - #define _c_getsystime GetSystemTimePreciseAsFileTime - #endif - struct _FILETIME; - _c_LINKC void _c_getsystime(struct _FILETIME*); - _c_LINKC void Sleep(unsigned long); - - static inline double cco_time(void) { /* seconds since epoch */ - unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */ - _c_getsystime((struct _FILETIME*)&quad); - return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */ - } - - static inline void cco_sleep(double sec) { - Sleep((unsigned long)(sec*1000.0)); - } -#else - #include - static inline double cco_time(void) { /* seconds since epoch */ - struct timeval tv; - gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec*1e-6; - } - - static inline void cco_sleep(double sec) { - struct timeval tv; - tv.tv_sec = (time_t)sec; - tv.tv_usec = (suseconds_t)((sec - (double)(long)sec)*1e6); - select(0, NULL, NULL, NULL, &tv); - } -#endif - -typedef struct { double interval, start; } cco_timer; - -#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT) -#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__) -#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, ) -#define cco_timer_await_v_3(tm, sec, ret) \ - do { \ - cco_timer_start(tm, sec); \ - cco_await_v_2(cco_timer_expired(tm), ret); \ - } while (0) - -static inline void cco_timer_start(cco_timer* tm, double sec) { - tm->interval = sec; - tm->start = cco_time(); -} - -static inline cco_timer cco_timer_from(double sec) { - cco_timer tm = {.interval=sec, .start=cco_time()}; - return tm; -} - -static inline void cco_timer_restart(cco_timer* tm) { - tm->start = cco_time(); -} - -static inline bool cco_timer_expired(cco_timer* tm) { - return cco_time() - tm->start >= tm->interval; -} - -static inline double cco_timer_elapsed(cco_timer* tm) { - return cco_time() - tm->start; -} - -static inline double cco_timer_remaining(cco_timer* tm) { - return tm->start + tm->interval - cco_time(); -} - -#endif diff --git a/include/stc/algorithm.h b/include/stc/algorithm.h new file mode 100644 index 00000000..cf3ab328 --- /dev/null +++ b/include/stc/algorithm.h @@ -0,0 +1,8 @@ +#ifndef STC_CALGO_INCLUDED +#define STC_CALGO_INCLUDED + +#include "algo/raii.h" +#include "algo/crange.h" +#include "algo/filter.h" + +#endif diff --git a/include/stc/calgo.h b/include/stc/calgo.h deleted file mode 100644 index 63ef97b9..00000000 --- a/include/stc/calgo.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef STC_CALGO_INCLUDED -#define STC_CALGO_INCLUDED - -#include "algo/raii.h" -#include "algo/crange.h" -#include "algo/filter.h" -#include "algo/coroutine.h" - -#endif diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h new file mode 100644 index 00000000..f89d20af --- /dev/null +++ b/include/stc/coroutine.h @@ -0,0 +1,273 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef STC_COROUTINE_INCLUDED +#define STC_COROUTINE_INCLUDED +/* +#include +#include + +struct iterpair { + int max_x, max_y; + int x, y; + int cco_state; // required member +}; + +int iterpair(struct iterpair* I) { + cco_routine(I) { + for (I->x = 0; I->x < I->max_x; I->x++) + for (I->y = 0; I->y < I->max_y; I->y++) + cco_yield(); + + cco_cleanup: // required if there is cleanup code + puts("final"); + } + return 0; // CCO_DONE +} + +int main(void) { + struct iterpair it = {.max_x=3, .max_y=3}; + int n = 0; + while (iterpair(&it)) + { + printf("%d %d\n", it.x, it.y); + // example of early stop: + if (++n == 7) cco_stop(&it); // signal to stop/finalize in next + } + return 0; +} +*/ +#include "ccommon.h" + +enum { + CCO_STATE_CLEANUP = -1, + CCO_STATE_DONE = -2, +}; +typedef enum { + CCO_DONE = 0, + CCO_AWAIT = 1<<0, + CCO_YIELD = 1<<1, +} cco_result; + +#define cco_initial(co) ((co)->cco_state == 0) +#define cco_suspended(co) ((co)->cco_state > 0) +#define cco_done(co) ((co)->cco_state == CCO_STATE_DONE) + +#define cco_routine(co) \ + for (int* _state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ + _resume: switch (*_state) case 0: // thanks, @liigo! + +#define cco_yield() cco_yield_v(CCO_YIELD) +#define cco_yield_v(ret) \ + do { \ + *_state = __LINE__; return ret; goto _resume; \ + case __LINE__:; \ + } while (0) + +#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT) +#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__) +#define cco_await_v_1(promise) cco_await_v_2(promise, ) +#define cco_await_v_2(promise, ret) \ + do { \ + *_state = __LINE__; \ + case __LINE__: if (!(promise)) {return ret; goto _resume;} \ + } while (0) + +/* cco_await_on(): assumes coroutine returns a cco_result value (int) */ +#define cco_await_on(corocall) \ + do { \ + *_state = __LINE__; \ + case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \ + } while (0) + +/* cco_block_on(): assumes coroutine returns a cco_result value (int) */ +#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) +#define cco_block_on_1(corocall) while ((corocall) != CCO_DONE) +#define cco_block_on_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) + +#define cco_cleanup \ + *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP + +#define cco_return \ + do { \ + *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ + goto _resume; \ + } while (0) + +#define cco_yield_final() cco_yield_final_v(CCO_YIELD) +#define cco_yield_final_v(value) \ + do { \ + *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ + return value; \ + } while (0) + +#define cco_stop(co) \ + do { \ + int* _s = &(co)->cco_state; \ + if (*_s > 0) *_s = CCO_STATE_CLEANUP; \ + else if (*_s == 0) *_s = CCO_STATE_DONE; \ + } while (0) + +#define cco_reset(co) \ + (void)((co)->cco_state = 0) + +/* + * Tasks (optional) + */ + +struct cco_runtime; + +#define cco_task_struct(Name, ...) \ + struct Name { \ + int (*cco_func)(struct Name*, struct cco_runtime*); \ + int cco_state, cco_expect; \ + __VA_ARGS__ \ + } + +typedef cco_task_struct(cco_task, /**/) cco_task; + +typedef struct cco_runtime { + int result, top; cco_task* stack[]; +} cco_runtime; + +#define cco_cast_task(task) \ + ((cco_task *)(task) + 0*sizeof((task)->cco_func(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) + +#define cco_resume(task, rt) \ + (task)->cco_func(task, rt) + +#define cco_task_await(...) c_MACRO_OVERLOAD(cco_task_await, __VA_ARGS__) +#define cco_task_await_2(task, rt) cco_task_await_3(task, rt, CCO_DONE) +#define cco_task_await_3(task, rt, resultbits) \ + do { \ + cco_runtime* _rt = rt; \ + (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = (resultbits); \ + cco_yield_v(CCO_AWAIT); \ + } while (0) + +#define cco_task_block_on(...) c_MACRO_OVERLOAD(cco_task_block_on, __VA_ARGS__) +#define cco_task_block_on_1(task) cco_task_block_on_3(task, _rt, 16) +#define cco_task_block_on_3(task, rt, STACKDEPTH) \ + for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ + (((rt.result = cco_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) + +/* + * Semaphore + */ + +typedef struct { intptr_t count; } cco_sem; + +#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT) +#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__) +#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, ) +#define cco_sem_await_v_2(sem, ret) \ + do { \ + cco_await_v_2((sem)->count > 0, ret); \ + --(sem)->count; \ + } while (0) + +#define cco_sem_release(sem) ++(sem)->count +#define cco_sem_from(value) ((cco_sem){value}) +#define cco_sem_set(sem, value) ((sem)->count = value) + +/* + * Timer + */ + +#ifdef _WIN32 + #ifdef __cplusplus + #define _c_LINKC extern "C" __declspec(dllimport) + #else + #define _c_LINKC __declspec(dllimport) + #endif + #if 1 // _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__ + #define _c_getsystime GetSystemTimeAsFileTime + #else + #define _c_getsystime GetSystemTimePreciseAsFileTime + #endif + struct _FILETIME; + _c_LINKC void _c_getsystime(struct _FILETIME*); + _c_LINKC void Sleep(unsigned long); + + static inline double cco_time(void) { /* seconds since epoch */ + unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */ + _c_getsystime((struct _FILETIME*)&quad); + return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */ + } + + static inline void cco_sleep(double sec) { + Sleep((unsigned long)(sec*1000.0)); + } +#else + #include + static inline double cco_time(void) { /* seconds since epoch */ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec*1e-6; + } + + static inline void cco_sleep(double sec) { + struct timeval tv; + tv.tv_sec = (time_t)sec; + tv.tv_usec = (suseconds_t)((sec - (double)(long)sec)*1e6); + select(0, NULL, NULL, NULL, &tv); + } +#endif + +typedef struct { double interval, start; } cco_timer; + +#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT) +#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__) +#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, ) +#define cco_timer_await_v_3(tm, sec, ret) \ + do { \ + cco_timer_start(tm, sec); \ + cco_await_v_2(cco_timer_expired(tm), ret); \ + } while (0) + +static inline void cco_timer_start(cco_timer* tm, double sec) { + tm->interval = sec; + tm->start = cco_time(); +} + +static inline cco_timer cco_timer_from(double sec) { + cco_timer tm = {.interval=sec, .start=cco_time()}; + return tm; +} + +static inline void cco_timer_restart(cco_timer* tm) { + tm->start = cco_time(); +} + +static inline bool cco_timer_expired(cco_timer* tm) { + return cco_time() - tm->start >= tm->interval; +} + +static inline double cco_timer_elapsed(cco_timer* tm) { + return cco_time() - tm->start; +} + +static inline double cco_timer_remaining(cco_timer* tm) { + return tm->start + tm->interval - cco_time(); +} + +#endif diff --git a/include/stc/crand.h b/include/stc/crand.h index 0a6aa9e0..32722762 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -32,20 +32,20 @@ int main(void) { uint64_t seed = 123456789; crand_t rng = crand_init(seed); - crand_unif_t dist1 = crand_unif_init(1, 6); - crand_norm_t dist3 = crand_norm_init(1.0, 10.0); + crand_uniform_t dist1 = crand_uniform_init(1, 6); + crand_normal_t dist3 = crand_normal_init(1.0, 10.0); uint64_t i = crand_u64(&rng); - int64_t iu = crand_unif(&rng, &dist1); - double xn = crand_norm(&rng, &dist3); + int64_t iu = crand_uniform(&rng, &dist1); + double xn = crand_normal(&rng, &dist3); } */ #include #include typedef struct crand { uint64_t state[5]; } crand_t; -typedef struct crand_unif { int64_t lower; uint64_t range, threshold; } crand_unif_t; -typedef struct crand_norm { double mean, stddev, next; int has_next; } crand_norm_t; +typedef struct crand_uniform { int64_t lower; uint64_t range, threshold; } crand_uniform_t; +typedef struct crand_normal { double mean, stddev, next; int has_next; } crand_normal_t; /* PRNG crand_t. * Very fast PRNG suited for parallel usage with Weyl-sequence parameter. @@ -67,14 +67,14 @@ STC_API double crandf(void); STC_API crand_t crand_init(uint64_t seed); /* Unbiased bounded uniform distribution. range [low, high] */ -STC_API crand_unif_t crand_unif_init(int64_t low, int64_t high); -STC_API int64_t crand_unif(crand_t* rng, crand_unif_t* dist); +STC_API crand_uniform_t crand_uniform_init(int64_t low, int64_t high); +STC_API int64_t crand_uniform(crand_t* rng, crand_uniform_t* dist); /* Normal/gaussian distribution. */ -STC_INLINE crand_norm_t crand_norm_init(double mean, double stddev) - { crand_norm_t r = {mean, stddev, 0.0, 0}; return r; } +STC_INLINE crand_normal_t crand_normal_init(double mean, double stddev) + { crand_normal_t r = {mean, stddev, 0.0, 0}; return r; } -STC_API double crand_norm(crand_t* rng, crand_norm_t* dist); +STC_API double crand_normal(crand_t* rng, crand_normal_t* dist); /* Main crand_t prng */ STC_INLINE uint64_t crand_u64(crand_t* rng) { @@ -95,11 +95,10 @@ STC_INLINE double crand_f64(crand_t* rng) { /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) -/* Global random() */ -static crand_t crand_global = {{ - 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04, - 0x504f333d3aa0b359, 0x9e3779b97f4a7c15, - 0x6a09e667a754166b +/* Global random seed */ +static crand_t crand_global = {{ // csrand(0) + 0x9e3779b97f4a7c15, 0x6f68261b57e7a770, + 0xe220a838bf5c9dde, 0x7c17d1800457b1ba, 0x1, }}; STC_DEF void csrand(uint64_t seed) @@ -116,20 +115,20 @@ STC_DEF crand_t crand_init(uint64_t seed) { s[0] = seed + 0x9e3779b97f4a7c15; s[1] = (s[0] ^ (s[0] >> 30))*0xbf58476d1ce4e5b9; s[2] = (s[1] ^ (s[1] >> 27))*0x94d049bb133111eb; - s[3] = (s[2] ^ (s[2] >> 31)); - s[4] = ((seed + 0x6aa069ea2fb1a4d) << 1) | 1; + s[3] = s[0] ^ s[2] ^ (s[2] >> 31); + s[4] = (seed << 1) | 1; return rng; } /* Init unbiased uniform uint RNG with bounds [low, high] */ -STC_DEF crand_unif_t crand_unif_init(int64_t low, int64_t high) { - crand_unif_t dist = {low, (uint64_t) (high - low + 1)}; +STC_DEF crand_uniform_t crand_uniform_init(int64_t low, int64_t high) { + crand_uniform_t dist = {low, (uint64_t) (high - low + 1)}; dist.threshold = (uint64_t)(0 - dist.range) % dist.range; return dist; } /* Int64 uniform distributed RNG, range [low, high]. */ -STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) { +STC_DEF int64_t crand_uniform(crand_t* rng, crand_uniform_t* d) { uint64_t lo, hi; #ifdef c_umul128 do { c_umul128(crand_u64(rng), d->range, &lo, &hi); } while (lo < d->threshold); @@ -140,7 +139,7 @@ STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) { } /* Normal distribution PRNG. Marsaglia polar method */ -STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) { +STC_DEF double crand_normal(crand_t* rng, crand_normal_t* dist) { double u1, u2, s, m; if (dist->has_next++ & 1) return dist->next*dist->stddev + dist->mean; diff --git a/misc/examples/algorithms/forfilter.c b/misc/examples/algorithms/forfilter.c index f3c008b3..644b8459 100644 --- a/misc/examples/algorithms/forfilter.c +++ b/misc/examples/algorithms/forfilter.c @@ -3,8 +3,7 @@ #include #define i_implement #include -#include -#include +#include #define i_type IVec #define i_key int diff --git a/misc/examples/algorithms/forloops.c b/misc/examples/algorithms/forloops.c index 72d745f8..300eee18 100644 --- a/misc/examples/algorithms/forloops.c +++ b/misc/examples/algorithms/forloops.c @@ -1,5 +1,5 @@ #include -#include +#include #define i_type IVec #define i_key int diff --git a/misc/examples/algorithms/random.c b/misc/examples/algorithms/random.c index b7c0f277..ccd0711d 100644 --- a/misc/examples/algorithms/random.c +++ b/misc/examples/algorithms/random.c @@ -4,11 +4,11 @@ int main(void) { - const int N = 1000000000; + long long N = 1000000000; const uint64_t seed = (uint64_t)time(NULL), range = 1000000; crand_t rng = crand_init(seed); - int64_t sum; + long long sum; clock_t diff, before; printf("Compare speed of full and unbiased ranged random numbers...\n"); @@ -18,19 +18,19 @@ int main(void) sum += (uint32_t)crand_u64(&rng); } diff = clock() - before; - printf("full range\t\t: %f secs, %d, avg: %f\n", - (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); + printf("full range\t\t: %f secs, %lld, avg: %f\n", + (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N)); - crand_unif_t dist1 = crand_unif_init(0, range); + crand_uniform_t dist1 = crand_uniform_init(0, range); rng = crand_init(seed); sum = 0; before = clock(); c_forrange (N) { - sum += crand_unif(&rng, &dist1); // unbiased + sum += crand_uniform(&rng, &dist1); // unbiased } diff = clock() - before; - printf("unbiased 0-%" PRIu64 "\t: %f secs, %d, avg: %f\n", - range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); + printf("unbiased 0-%" PRIu64 "\t: %f secs, %lld, avg: %f\n", + range, (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N)); sum = 0; rng = crand_init(seed); @@ -39,7 +39,7 @@ int main(void) sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased } diff = clock() - before; - printf("biased 0-%" PRIu64 " \t: %f secs, %d, avg: %f\n", - range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); + printf("biased 0-%" PRIu64 " \t: %f secs, %lld, avg: %f\n", + range, (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N)); } diff --git a/misc/examples/bitsets/prime.c b/misc/examples/bitsets/prime.c index cb3b095a..e5764d83 100644 --- a/misc/examples/bitsets/prime.c +++ b/misc/examples/bitsets/prime.c @@ -2,23 +2,23 @@ #include #include #include -#include -#include +#include +typedef long long llong; -cbits sieveOfEratosthenes(int64_t n) +cbits sieveOfEratosthenes(llong n) { cbits bits = cbits_with_size(n/2 + 1, true); - int64_t q = (int64_t)sqrt((double) n) + 1; - for (int64_t i = 3; i < q; i += 2) { - int64_t j = i; + llong q = (llong)sqrt((double) n) + 1; + for (llong i = 3; i < q; i += 2) { + llong j = i; for (; j < n; j += 2) { if (cbits_test(&bits, j>>1)) { i = j; break; } } - for (int64_t j = i*i; j < n; j += i*2) + for (llong j = i*i; j < n; j += i*2) cbits_reset(&bits, j>>1); } return bits; @@ -26,12 +26,12 @@ cbits sieveOfEratosthenes(int64_t n) int main(void) { - int n = 1000000000; - printf("Computing prime numbers up to %d\n", n); + llong n = 100000000; + printf("Computing prime numbers up to %lld\n", n); clock_t t = clock(); cbits primes = sieveOfEratosthenes(n + 1); - int np = (int)cbits_count(&primes); + llong np = cbits_count(&primes); t = clock() - t; puts("Show all the primes in the range [2, 1000):"); @@ -50,7 +50,7 @@ int main(void) printf("%lld ", *i.ref); if (c_flt_getcount(i) % 10 == 0) puts(""); } - printf("Number of primes: %d, time: %.2f\n\n", np, (double)t/CLOCKS_PER_SEC); + printf("Number of primes: %lld, time: %.2f\n\n", np, (double)t/CLOCKS_PER_SEC); cbits_drop(&primes); } diff --git a/misc/examples/coroutines/cointerleave.c b/misc/examples/coroutines/cointerleave.c index 599ceaab..ea0d4dac 100644 --- a/misc/examples/coroutines/cointerleave.c +++ b/misc/examples/coroutines/cointerleave.c @@ -1,6 +1,6 @@ // https://www.youtube.com/watch?v=8sEe-4tig_A #include -#include +#include #define i_type IVec #define i_key int #include diff --git a/misc/examples/coroutines/coread.c b/misc/examples/coroutines/coread.c index a13f6be5..56248108 100644 --- a/misc/examples/coroutines/coread.c +++ b/misc/examples/coroutines/coread.c @@ -1,6 +1,6 @@ #define i_implement #include -#include +#include #include // Read file line by line using coroutines: diff --git a/misc/examples/coroutines/coroutines.c b/misc/examples/coroutines/coroutines.c index b8dfaa13..de0fcda5 100644 --- a/misc/examples/coroutines/coroutines.c +++ b/misc/examples/coroutines/coroutines.c @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c index c87582f1..27999ccf 100644 --- a/misc/examples/coroutines/cotasks1.c +++ b/misc/examples/coroutines/cotasks1.c @@ -4,7 +4,7 @@ #include #define i_static #include -#include +#include struct next_value { int val; diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c index 293583bc..9ca69bda 100644 --- a/misc/examples/coroutines/cotasks2.c +++ b/misc/examples/coroutines/cotasks2.c @@ -4,7 +4,7 @@ #include #define i_static #include -#include +#include cco_task_struct (next_value, int val; @@ -45,7 +45,7 @@ int produce_items(struct produce_items* p, cco_runtime* rt) while (true) { // await for next CCO_YIELD in next_value() - cco_await_task(&p->next, rt, CCO_YIELD); + cco_task_await(&p->next, rt, CCO_YIELD); cstr_printf(&p->str, "item %d", p->next.val); print_time(); printf("produced %s\n", cstr_str(&p->str)); @@ -71,7 +71,7 @@ int consume_items(struct consume_items* c, cco_runtime* rt) for (c->i = 1; c->i <= c->n; ++c->i) { printf("consume #%d\n", c->i); - cco_await_task(&c->produce, rt, CCO_YIELD); + cco_task_await(&c->produce, rt, CCO_YIELD); print_time(); printf("consumed %s\n", cstr_str(&c->produce.str)); } @@ -87,12 +87,12 @@ int main(void) { struct consume_items consume = { .n=5, - .cco_fn=consume_items, - .produce={.cco_fn=produce_items, .next={.cco_fn=next_value}}, + .cco_func=consume_items, + .produce={.cco_func=produce_items, .next={.cco_func=next_value}}, }; int count = 0; - cco_block_task(&consume) + cco_task_block_on(&consume) { ++count; //cco_sleep(0.001); diff --git a/misc/examples/coroutines/dining_philosophers.c b/misc/examples/coroutines/dining_philosophers.c index a5063a42..abe09204 100644 --- a/misc/examples/coroutines/dining_philosophers.c +++ b/misc/examples/coroutines/dining_philosophers.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include // Define the number of philosophers and forks enum { diff --git a/misc/examples/coroutines/generator.c b/misc/examples/coroutines/generator.c index a15f9ba5..f9e59fea 100644 --- a/misc/examples/coroutines/generator.c +++ b/misc/examples/coroutines/generator.c @@ -1,7 +1,7 @@ // https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ -#include #include +#include typedef struct { int size; diff --git a/misc/examples/coroutines/scheduler.c b/misc/examples/coroutines/scheduler.c index 38defd0f..78461277 100644 --- a/misc/examples/coroutines/scheduler.c +++ b/misc/examples/coroutines/scheduler.c @@ -1,6 +1,6 @@ // https://www.youtube.com/watch?v=8sEe-4tig_A #include -#include +#include struct Task { int (*fn)(struct Task*); diff --git a/misc/examples/coroutines/triples.c b/misc/examples/coroutines/triples.c index 9f2fcc1e..fe1ca7c3 100644 --- a/misc/examples/coroutines/triples.c +++ b/misc/examples/coroutines/triples.c @@ -1,7 +1,7 @@ // https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ -#include #include +#include int gcd(int a, int b) { while (b) { diff --git a/misc/examples/linkedlists/list.c b/misc/examples/linkedlists/list.c index ad8bebb8..09591314 100644 --- a/misc/examples/linkedlists/list.c +++ b/misc/examples/linkedlists/list.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #define i_type DList diff --git a/misc/examples/make.sh b/misc/examples/make.sh index 7135ffdf..b362f275 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -38,8 +38,8 @@ fi if [ $run = 0 ] ; then for i in */*.c ; do - #out=$(basename $i .c).exe - out=$(dirname $i)/$(basename $i .c).exe + out=$(basename $i .c).exe + #out=$(dirname $i)/$(basename $i .c).exe echo $comp -I../../include $i $clibs $oflag$out $comp -I../../include $i $clibs $oflag$out done @@ -47,8 +47,8 @@ else for i in */*.c ; do echo $comp -I../../include $i $clibs $comp -I../../include $i $clibs - #out=$(basename $i .c).exe - out=$(dirname $i)/$(basename $i .c).exe + out=$(basename $i .c).exe + #out=$(dirname $i)/$(basename $i .c).exe if [ -f $out ]; then ./$out; fi done fi diff --git a/misc/examples/priorityqueues/priority.c b/misc/examples/priorityqueues/priority.c index bf2e188a..18684e73 100644 --- a/misc/examples/priorityqueues/priority.c +++ b/misc/examples/priorityqueues/priority.c @@ -11,21 +11,21 @@ int main(void) { intptr_t N = 10000000; crand_t rng = crand_init((uint64_t)time(NULL)); - crand_unif_t dist = crand_unif_init(0, N * 10); + crand_uniform_t dist = crand_uniform_init(0, N * 10); cpque_i heap = {0}; // Push ten million random numbers to priority queue printf("Push %" c_ZI " numbers\n", N); c_forrange (N) - cpque_i_push(&heap, crand_unif(&rng, &dist)); + cpque_i_push(&heap, crand_uniform(&rng, &dist)); // push some negative numbers too. c_forlist (i, int, {-231, -32, -873, -4, -343}) cpque_i_push(&heap, *i.ref); c_forrange (N) - cpque_i_push(&heap, crand_unif(&rng, &dist)); + cpque_i_push(&heap, crand_uniform(&rng, &dist)); puts("Extract the hundred smallest."); c_forrange (100) { diff --git a/misc/examples/queues/new_queue.c b/misc/examples/queues/new_queue.c index f3592df6..3904c50c 100644 --- a/misc/examples/queues/new_queue.c +++ b/misc/examples/queues/new_queue.c @@ -23,19 +23,19 @@ int point_cmp(const Point* a, const Point* b) { int main(void) { int n = 50000000; crand_t rng = crand_init((uint64_t)time(NULL)); - crand_unif_t dist = crand_unif_init(0, n); + crand_uniform_t dist = crand_uniform_init(0, n); IQ Q = {0}; // Push 50'000'000 random numbers onto the queue. c_forrange (n) - IQ_push(&Q, (int)crand_unif(&rng, &dist)); + IQ_push(&Q, (int)crand_uniform(&rng, &dist)); // Push or pop on the queue 50 million times printf("befor: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q)); c_forrange (n) { - int r = (int)crand_unif(&rng, &dist); + int r = (int)crand_uniform(&rng, &dist); if (r & 3) IQ_push(&Q, r); else diff --git a/misc/examples/queues/queue.c b/misc/examples/queues/queue.c index 56b5beb9..913524cc 100644 --- a/misc/examples/queues/queue.c +++ b/misc/examples/queues/queue.c @@ -7,20 +7,20 @@ int main(void) { int n = 100000000; - crand_unif_t dist; + crand_uniform_t dist; crand_t rng = crand_init(1234); - dist = crand_unif_init(0, n); + dist = crand_uniform_init(0, n); cqueue_i queue = {0}; // Push ten million random numbers onto the queue. c_forrange (n) - cqueue_i_push(&queue, (int)crand_unif(&rng, &dist)); + cqueue_i_push(&queue, (int)crand_uniform(&rng, &dist)); // Push or pop on the queue ten million times printf("%d\n", n); c_forrange (n) { // forrange uses initial n only. - int r = (int)crand_unif(&rng, &dist); + int r = (int)crand_uniform(&rng, &dist); if (r & 1) ++n, cqueue_i_push(&queue, r); else diff --git a/misc/examples/sortedmaps/gauss2.c b/misc/examples/sortedmaps/gauss2.c index 1ab8ade5..02ce4bc5 100644 --- a/misc/examples/sortedmaps/gauss2.c +++ b/misc/examples/sortedmaps/gauss2.c @@ -21,14 +21,14 @@ int main(void) printf("Mean %f, StdDev %f\n", Mean, StdDev); // Setup random engine with normal distribution. - crand_norm_t dist = crand_norm_init(Mean, StdDev); + crand_normal_t dist = crand_normal_init(Mean, StdDev); // Create and init histogram map with defered destruct csmap_int hist = {0}; cstr bar = {0}; c_forrange (N) { - int index = (int)round(crand_norm(&rng, &dist)); + int index = (int)round(crand_normal(&rng, &dist)); csmap_int_insert(&hist, index, 0).ref->second += 1; } diff --git a/misc/examples/spans/mdspan.c b/misc/examples/spans/mdspan.c new file mode 100644 index 00000000..4427299c --- /dev/null +++ b/misc/examples/spans/mdspan.c @@ -0,0 +1,51 @@ +#include +#include +#include + +using_cspan3(DSpan, double); + +int main(void) { + const int nx=5, ny=4, nz=3; + double* data = c_new_n(double, nx*ny*nz); + + printf("\nMultidim span ms[5, 4, 3], fortran ordered"); + DSpan3 ms = cspan_md_order('F', data, nx, ny, nz); // Fortran, not 'C' + + int idx = 0; + c_forrange (i, ms.shape[0]) + c_forrange (j, ms.shape[1]) + c_forrange (k, ms.shape[2]) + *cspan_at(&ms, i, j, k) = ++idx; + + cspan_transpose(&ms); + + printf(", transposed:\n\n"); + c_forrange (i, ms.shape[0]) { + c_forrange (j, ms.shape[1]) { + c_forrange (k, ms.shape[2]) + printf(" %3g", *cspan_at(&ms, i, j, k)); + puts(""); + } + puts(""); + } + + DSpan2 sub; + + puts("Slicing:"); + printf("\nms[0, :, :] "); + sub = cspan_slice(DSpan2, &ms, {0}, {c_ALL}, {c_ALL}); + c_foreach (i, DSpan2, sub) printf(" %g", *i.ref); + puts(""); + + printf("\nms[:, 0, :] "); + sub = cspan_slice(DSpan2, &ms, {c_ALL}, {0}, {c_ALL}); + c_foreach (i, DSpan2, sub) printf(" %g", *i.ref); + puts(""); + + sub = cspan_slice(DSpan2, &ms, {c_ALL}, {c_ALL}, {0}); + printf("\nms[:, :, 0] "); + c_foreach (i, DSpan2, sub) printf(" %g", *i.ref); + puts(""); + + free(data); +} -- cgit v1.2.3 From dbcc13635402bd466675f4f41e865d02abc6f918 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 21 Jul 2023 10:49:45 +0200 Subject: NB! Changed some coroutine API for consistency/simplicity: Added full task support. --- docs/ccommon_api.md | 30 ++++++-------- include/stc/ccommon.h | 2 +- include/stc/coroutine.h | 44 ++++++++++---------- misc/examples/coroutines/cointerleave.c | 2 +- misc/examples/coroutines/coread.c | 2 +- misc/examples/coroutines/coroutines.c | 8 ++-- misc/examples/coroutines/cotasks1.c | 2 +- misc/examples/coroutines/cotasks2.c | 4 +- misc/examples/smartpointers/map_box.c | 34 +++++++++++++++ misc/examples/smartpointers/map_ptr.c | 34 +++++++++++++++ misc/examples/smartpointers/rawptr_elements.c | 59 --------------------------- misc/examples/spans/mdspan.c | 12 +++--- 12 files changed, 119 insertions(+), 114 deletions(-) create mode 100644 misc/examples/smartpointers/map_box.c create mode 100644 misc/examples/smartpointers/map_ptr.c delete mode 100644 misc/examples/smartpointers/rawptr_elements.c diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 9189d7e8..0752beb5 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -374,36 +374,32 @@ cco_routine scope; Use `if-else-if` constructs instead. | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| -| | Function / 'keywords': | | -|`cco_result` | Enum `CCO_DONE=0`, `CCO_YIELD`, `CCO_AWAIT` | Recommended return values in coroutines | -| | Function / 'keywords': | | +|`cco_result` | `CCO_DONE`, `CCO_AWAIT`, `CCO_YIELD` | Default set of return values from coroutines | | | `cco_cleanup:` | Label for cleanup position in coroutine | | `bool` | `cco_done(co)` | Is coroutine done? | -| | `cco_routine(co) { }` | The coroutine scope | +| | `cco_routine(co) {}` | The coroutine scope | | | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)| -| | `cco_yield_v();` | Yield/suspend execution (return void) | | | `cco_yield_v(ret);` | Yield/suspend execution (return ret) | -| | `cco_yield_final();` | Yield final time, enables cleanup-state | -| | `cco_yield_final(ret);` | Yield a final value (e.g. CCO_ERROR) | +| | `cco_yield_final();` | Yield final suspend, enter cleanup-state | +| | `cco_yield_final(ret);` | Yield a final value | | | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| -| | `cco_await_v(condition);` | Suspend until condition is true (return void) | -| | `cco_await_v(condition, ret);` | Suspend until condition is true (return ret)| -| | `cco_await_on(cocall);` | Await on sub-coroutine to finish (return its ret) | +| | `cco_call_await(cocall);` | Await for subcoro to finish (returns its ret value) | +| | `cco_call_await(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) | | | `cco_return;` | Return from coroutine (inside cco_routine) | | | Task objects: | | | | `cco_task_struct(Name, ...);` | Define a coroutine task struct | -| | `cco_task_await(task, ...);` | Await for task to finish or optionally yield a value | +| | `cco_task_await(task, cco_runtime* rt);`| Await for task to finish | +| | `cco_task_await(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) | +|`cco_result`| `cco_task_resume(task, rt);` | Resume suspended task | | | Semaphores: | | | | `cco_sem` | Semaphore type | | `cco_sem` | `cco_sem_from(long value)` | Create semaphore | | | `cco_sem_set(sem, long value)` | Set semaphore value | | | `cco_sem_await(sem)` | Await for the semaphore count > 0 | -| | `cco_sem_await(sem, ret)` | Await with ret on the semaphore | | | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | | | Timers: | | | | `cco_timer` | Timer type | | | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)| -| | `cco_timer_await(tm, double sec, ret)`| Await secs for timer with ret value | | | `cco_timer_start(tm, double sec)` | Start timer for secs duration | | | `cco_timer_restart(tm)` | Restart timer with same duration | | `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | @@ -412,10 +408,10 @@ cco_routine scope; Use `if-else-if` constructs instead. | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_block_on(cocall) { }` | Run blocking until cocall is finished | -| `void` | `cco_block_on(cocall, int *result) {}`| Run blocking until cocall is finished | -| | `cco_task_block_on(task) {}` | Run blocking until task is finished | -| | `cco_task_block_on(task, rt, STACKSZ) {}`| Run blocking until task is finished | +| `void` | `cco_call_blocking(cocall) {}` | Run blocking until cocall is finished | +| `void` | `cco_call_blocking(cocall, int* outres) {}`| Run blocking until cocall is finished | +| | `cco_task_blocking(task) {}` | Run blocking until task is finished | +| | `cco_task_blocking(task, rt, STACKSZ) {}`| Run blocking until task is finished | | | Time functions: | | | `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | | | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 1f9ea80d..316a8ee7 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -69,7 +69,7 @@ typedef long long _llong; #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T))) #define c_LITERAL(T) (T) #endif -#define c_new_n(T, n) ((T*)malloc(sizeof(T)*(n))) +#define c_new_n(T, n) ((T*)malloc(sizeof(T)*(size_t)(n))) #define c_malloc(sz) malloc(c_i2u(sz)) #define c_calloc(n, sz) calloc(c_i2u(n), c_i2u(sz)) #define c_realloc(p, sz) realloc(p, c_i2u(sz)) diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h index f89d20af..42905744 100644 --- a/include/stc/coroutine.h +++ b/include/stc/coroutine.h @@ -83,26 +83,27 @@ typedef enum { case __LINE__:; \ } while (0) -#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT) -#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__) -#define cco_await_v_1(promise) cco_await_v_2(promise, ) -#define cco_await_v_2(promise, ret) \ +#define cco_await(promise) cco_await_and_return(promise, CCO_AWAIT) +#define cco_await_v(promise) cco_await_and_return(promise, ) +#define cco_await_and_return(promise, ret) \ do { \ *_state = __LINE__; \ case __LINE__: if (!(promise)) {return ret; goto _resume;} \ } while (0) -/* cco_await_on(): assumes coroutine returns a cco_result value (int) */ -#define cco_await_on(corocall) \ +/* cco_call_await(): assumes coroutine returns a cco_result value (int) */ +#define cco_call_await(...) c_MACRO_OVERLOAD(cco_call_await, __VA_ARGS__) +#define cco_call_await_1(corocall) cco_call_await_2(corocall, CCO_DONE) +#define cco_call_await_2(corocall, resultbits) \ do { \ *_state = __LINE__; \ - case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \ + case __LINE__: { int _r = corocall; if (!(_r & ~(resultbits))) {return _r; goto _resume;} } \ } while (0) -/* cco_block_on(): assumes coroutine returns a cco_result value (int) */ -#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) -#define cco_block_on_1(corocall) while ((corocall) != CCO_DONE) -#define cco_block_on_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) +/* cco_call_blocking(): assumes coroutine returns a cco_result value (int) */ +#define cco_call_blocking(...) c_MACRO_OVERLOAD(cco_call_blocking, __VA_ARGS__) +#define cco_call_blocking_1(corocall) while ((corocall) != CCO_DONE) +#define cco_call_blocking_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) #define cco_cleanup \ *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP @@ -152,7 +153,7 @@ typedef struct cco_runtime { #define cco_cast_task(task) \ ((cco_task *)(task) + 0*sizeof((task)->cco_func(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) -#define cco_resume(task, rt) \ +#define cco_task_resume(task, rt) \ (task)->cco_func(task, rt) #define cco_task_await(...) c_MACRO_OVERLOAD(cco_task_await, __VA_ARGS__) @@ -164,11 +165,11 @@ typedef struct cco_runtime { cco_yield_v(CCO_AWAIT); \ } while (0) -#define cco_task_block_on(...) c_MACRO_OVERLOAD(cco_task_block_on, __VA_ARGS__) -#define cco_task_block_on_1(task) cco_task_block_on_3(task, _rt, 16) -#define cco_task_block_on_3(task, rt, STACKDEPTH) \ +#define cco_task_blocking(...) c_MACRO_OVERLOAD(cco_task_blocking, __VA_ARGS__) +#define cco_task_blocking_1(task) cco_task_blocking_3(task, _rt, 16) +#define cco_task_blocking_3(task, rt, STACKDEPTH) \ for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ - (((rt.result = cco_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) + (((rt.result = cco_task_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) /* * Semaphore @@ -176,12 +177,11 @@ typedef struct cco_runtime { typedef struct { intptr_t count; } cco_sem; -#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT) -#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__) -#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, ) -#define cco_sem_await_v_2(sem, ret) \ +#define cco_sem_await(sem) cco_sem_await_and_return(sem, CCO_AWAIT) +#define cco_sem_await_v(sem) cco_sem_await_and_return(sem, ) +#define cco_sem_await_and_return(sem, ret) \ do { \ - cco_await_v_2((sem)->count > 0, ret); \ + cco_await_and_return((sem)->count > 0, ret); \ --(sem)->count; \ } while (0) @@ -241,7 +241,7 @@ typedef struct { double interval, start; } cco_timer; #define cco_timer_await_v_3(tm, sec, ret) \ do { \ cco_timer_start(tm, sec); \ - cco_await_v_2(cco_timer_expired(tm), ret); \ + cco_await_and_return(cco_timer_expired(tm), ret); \ } while (0) static inline void cco_timer_start(cco_timer* tm, double sec) { diff --git a/misc/examples/coroutines/cointerleave.c b/misc/examples/coroutines/cointerleave.c index ea0d4dac..f3710ba3 100644 --- a/misc/examples/coroutines/cointerleave.c +++ b/misc/examples/coroutines/cointerleave.c @@ -49,7 +49,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - cco_block_on(interleaved(&g)) { + cco_call_blocking(interleaved(&g)) { printf("%d ", g.value); } puts(""); diff --git a/misc/examples/coroutines/coread.c b/misc/examples/coroutines/coread.c index 56248108..ebaaf19d 100644 --- a/misc/examples/coroutines/coread.c +++ b/misc/examples/coroutines/coread.c @@ -33,7 +33,7 @@ int main(void) { struct file_read g = {__FILE__}; int n = 0; - cco_block_on(file_read(&g)) + cco_call_blocking(file_read(&g)) { printf("%3d %s\n", ++n, cstr_str(&g.line)); //if (n == 10) cco_stop(&g); diff --git a/misc/examples/coroutines/coroutines.c b/misc/examples/coroutines/coroutines.c index de0fcda5..489c3ed6 100644 --- a/misc/examples/coroutines/coroutines.c +++ b/misc/examples/coroutines/coroutines.c @@ -84,13 +84,13 @@ struct combined { int combined(struct combined* g) { cco_routine(g) { - cco_await_on(prime(&g->prm)); - cco_await_on(fibonacci(&g->fib)); + cco_call_await(prime(&g->prm)); + cco_call_await(fibonacci(&g->fib)); // Reuse the g->prm context and extend the count: g->prm.count = 8, g->prm.result += 2; cco_reset(&g->prm); - cco_await_on(prime(&g->prm)); + cco_call_await(prime(&g->prm)); cco_cleanup: puts("final combined"); @@ -103,7 +103,7 @@ int main(void) struct combined c = {.prm={.count=8}, .fib={14}}; int res; - cco_block_on(combined(&c), &res) { + cco_call_blocking(combined(&c), &res) { if (res == CCO_YIELD) printf("Prime(%d)=%lld, Fib(%d)=%lld\n", c.prm.idx, c.prm.result, diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c index 27999ccf..e4afbe2b 100644 --- a/misc/examples/coroutines/cotasks1.c +++ b/misc/examples/coroutines/cotasks1.c @@ -88,7 +88,7 @@ int main(void) struct consume_items consume = {.n=5}; int count = 0; - cco_block_on(consume_items(&consume, &produce)) + cco_call_blocking(consume_items(&consume, &produce)) { ++count; //cco_sleep(0.001); diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c index 9ca69bda..24a9f23f 100644 --- a/misc/examples/coroutines/cotasks2.c +++ b/misc/examples/coroutines/cotasks2.c @@ -77,7 +77,7 @@ int consume_items(struct consume_items* c, cco_runtime* rt) } cco_cleanup: cco_stop(&c->produce); - cco_resume(&c->produce, rt); + cco_task_resume(&c->produce, rt); puts("done consume"); } return 0; @@ -92,7 +92,7 @@ int main(void) }; int count = 0; - cco_task_block_on(&consume) + cco_task_blocking(&consume) { ++count; //cco_sleep(0.001); diff --git a/misc/examples/smartpointers/map_box.c b/misc/examples/smartpointers/map_box.c new file mode 100644 index 00000000..f651b302 --- /dev/null +++ b/misc/examples/smartpointers/map_box.c @@ -0,0 +1,34 @@ +#include +#include +#define i_implement +#include + +#define i_type IBox +#define i_key long +#include // unique_ptr alike. + +// cmap of cstr => IBox +#define i_type Boxmap +#define i_key_str +#define i_valboxed IBox // i_valboxed: use properties from IBox automatically +#include + + +int main(void) +{ + Boxmap map = {0}; + + puts("Map cstr => IBox:"); + Boxmap_insert(&map, cstr_from("Test1"), IBox_make(1)); + Boxmap_insert(&map, cstr_from("Test2"), IBox_make(2)); + + // Simpler: emplace() implicitly creates cstr from const char* and IBox from long! + Boxmap_emplace(&map, "Test3", 3); + Boxmap_emplace(&map, "Test4", 4); + + c_forpair (name, number, Boxmap, map) + printf("%s: %ld\n", cstr_str(_.name), *_.number->get); + puts(""); + + Boxmap_drop(&map); +} diff --git a/misc/examples/smartpointers/map_ptr.c b/misc/examples/smartpointers/map_ptr.c new file mode 100644 index 00000000..453322c5 --- /dev/null +++ b/misc/examples/smartpointers/map_ptr.c @@ -0,0 +1,34 @@ +#include +#include +#define i_implement +#include + +// cmap of cstr => long* +#define i_type Ptrmap +#define i_key_str +#define i_val long* +#define i_valraw long +#define i_valfrom(raw) c_new(long, raw) +#define i_valto(x) **x +#define i_valclone(x) c_new(long, *x) +#define i_valdrop(x) c_free(*x) +#include + +int main(void) +{ + Ptrmap map = {0}; + + puts("Map cstr => long*:"); + Ptrmap_insert(&map, cstr_from("Test1"), c_new(long, 1)); + Ptrmap_insert(&map, cstr_from("Test2"), c_new(long, 2)); + + // Simple: emplace() implicitly creates cstr from const char* and an owned long* from long! + Ptrmap_emplace(&map, "Test3", 3); + Ptrmap_emplace(&map, "Test4", 4); + + c_forpair (name, number, Ptrmap, map) + printf("%s: %ld\n", cstr_str(_.name), **_.number); + puts(""); + + Ptrmap_drop(&map); +} diff --git a/misc/examples/smartpointers/rawptr_elements.c b/misc/examples/smartpointers/rawptr_elements.c deleted file mode 100644 index 694ce12e..00000000 --- a/misc/examples/smartpointers/rawptr_elements.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#define i_implement -#include - -// Create cmap of cstr => long* -#define i_type SIPtrMap -#define i_key_str -#define i_val long* -#define i_valraw long -#define i_valfrom(raw) c_new(long, raw) -#define i_valto(x) **x -#define i_valclone(x) c_new(long, *x) -#define i_valdrop(x) c_free(*x) -#include - -// Alternatively, using cbox: -#define i_type IBox -#define i_key long -#include // unique_ptr alike. - -// cmap of cstr => IBox -#define i_type SIBoxMap -#define i_key_str -#define i_valboxed IBox // i_valboxed: use properties from IBox automatically -#include - -int main(void) -{ - // These have the same behaviour, except IBox has a get member: - SIPtrMap map1 = {0}; - SIBoxMap map2 = {0}; - - printf("\nMap cstr => long*:\n"); - SIPtrMap_insert(&map1, cstr_from("Test1"), c_new(long, 1)); - SIPtrMap_insert(&map1, cstr_from("Test2"), c_new(long, 2)); - - // Emplace implicitly creates cstr from const char* and an owned long* from long! - SIPtrMap_emplace(&map1, "Test3", 3); - SIPtrMap_emplace(&map1, "Test4", 4); - - c_forpair (name, number, SIPtrMap, map1) - printf("%s: %ld\n", cstr_str(_.name), **_.number); - - puts("\nMap cstr => IBox:"); - SIBoxMap_insert(&map2, cstr_from("Test1"), IBox_make(1)); - SIBoxMap_insert(&map2, cstr_from("Test2"), IBox_make(2)); - - // Emplace implicitly creates cstr from const char* and IBox from long! - SIBoxMap_emplace(&map2, "Test3", 3); - SIBoxMap_emplace(&map2, "Test4", 4); - - c_forpair (name, number, SIBoxMap, map2) - printf("%s: %ld\n", cstr_str(_.name), *_.number->get); - puts(""); - - SIPtrMap_drop(&map1); - SIBoxMap_drop(&map2); -} diff --git a/misc/examples/spans/mdspan.c b/misc/examples/spans/mdspan.c index 4427299c..db601850 100644 --- a/misc/examples/spans/mdspan.c +++ b/misc/examples/spans/mdspan.c @@ -12,17 +12,17 @@ int main(void) { DSpan3 ms = cspan_md_order('F', data, nx, ny, nz); // Fortran, not 'C' int idx = 0; - c_forrange (i, ms.shape[0]) - c_forrange (j, ms.shape[1]) - c_forrange (k, ms.shape[2]) + for (int i = 0; i < ms.shape[0]; ++i) + for (int j = 0; j < ms.shape[1]; ++j) + for (int k = 0; k < ms.shape[2]; ++k) *cspan_at(&ms, i, j, k) = ++idx; cspan_transpose(&ms); printf(", transposed:\n\n"); - c_forrange (i, ms.shape[0]) { - c_forrange (j, ms.shape[1]) { - c_forrange (k, ms.shape[2]) + for (int i = 0; i < ms.shape[0]; ++i) { + for (int j = 0; j < ms.shape[1]; ++j) { + for (int k = 0; k < ms.shape[2]; ++k) printf(" %3g", *cspan_at(&ms, i, j, k)); puts(""); } -- cgit v1.2.3 From f3794f2b86b6f7f85096a0c2e9ca5720aed53300 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 21 Jul 2023 11:22:48 +0200 Subject: Removed c_foreach_rv() - only worked for cvec, so not general. --- README.md | 1 - docs/ccommon_api.md | 3 +-- include/stc/ccommon.h | 4 ---- misc/examples/algorithms/forloops.c | 4 ---- misc/examples/linkedlists/list.c | 4 ++-- 5 files changed, 3 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 6bbe50ee..b49214d4 100644 --- a/README.md +++ b/README.md @@ -640,7 +640,6 @@ STC is generally very memory efficient. Memory usage for the different container - Added new crand.h API & header. Old crandom.h is deprecated. - Added `c_const_cast()` typesafe macro. - Removed RAII macros usage from examples -- Renamed c_foreach_r => `c_foreach_rv` - Renamed c_flt_count(i) => `c_flt_counter(i)` - Renamed c_flt_last(i) => `c_flt_getcount(i)` - Renamed c_ARRAYLEN() => c_arraylen() diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 0752beb5..11d425e5 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -3,13 +3,12 @@ --- ## Ranged for-loops -### c_foreach, c_foreach_rv, c_forpair +### c_foreach, c_forpair | Usage | Description | |:-----------------------------------------|:------------------------------------------| | `c_foreach (it, ctype, container)` | Iteratate all elements | | `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | -| `c_foreach_rv (it, ctype, container)` | Iteratate in reverse (cstack, cvec, cdeq) | | `c_forpair (key, val, ctype, container)` | Iterate with structured binding | ```c diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 316a8ee7..77f754fa 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -191,10 +191,6 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { for (C##_iter it = start, *_endref = (C##_iter*)(finish).ref \ ; it.ref != (C##_value*)_endref; C##_next(&it)) -#define c_foreach_rv(it, C, cnt) \ - for (C##_iter it = {.ref=C##_end(&cnt).end - 1, .end=(cnt).data - 1} \ - ; it.ref != it.end; --it.ref) - #define c_forpair(key, val, C, cnt) /* structured binding */ \ for (struct {C##_iter it; const C##_key* key; C##_mapped* val;} _ = {.it=C##_begin(&cnt)} \ ; _.it.ref && (_.key = &_.it.ref->first, _.val = &_.it.ref->second) \ diff --git a/misc/examples/algorithms/forloops.c b/misc/examples/algorithms/forloops.c index 300eee18..a83d4a53 100644 --- a/misc/examples/algorithms/forloops.c +++ b/misc/examples/algorithms/forloops.c @@ -41,10 +41,6 @@ int main(void) c_foreach (i, IVec, vec) printf(" %d", *i.ref); - puts("\n\nc_foreach_r: reverse"); - c_foreach_rv (i, IVec, vec) - printf(" %d", *i.ref); - puts("\n\nc_foreach in map:"); c_foreach (i, IMap, map) printf(" (%d %d)", i.ref->first, i.ref->second); diff --git a/misc/examples/linkedlists/list.c b/misc/examples/linkedlists/list.c index 09591314..518cc09b 100644 --- a/misc/examples/linkedlists/list.c +++ b/misc/examples/linkedlists/list.c @@ -12,10 +12,10 @@ int main(void) { const int n = 3000000; DList list = {0}; - crand_t rng = crand_init(1234567); + csrand(1234567); int m = 0; c_forrange (n) - DList_push_back(&list, crand_f64(&rng)*n + 100), ++m; + DList_push_back(&list, crandf()*n + 100), ++m; double sum = 0.0; printf("sumarize %d:\n", m); -- cgit v1.2.3 From 674b8b5db87dac8b470feae5d2c0ef30846a6bb7 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 21 Jul 2023 11:37:07 +0200 Subject: Renamed crange_make(...) => crange_init(...), deprecated crange_make(). --- docs/ccommon_api.md | 12 ++++++------ include/stc/algo/crange.h | 13 +++++++------ misc/examples/algorithms/forfilter.c | 4 ++-- misc/examples/bitsets/prime.c | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 11d425e5..0e8d9719 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -81,16 +81,16 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i); ### crange A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: ```c -crange crange_make(stop); // will generate 0, 1, ..., stop-1 -crange crange_make(start, stop); // will generate start, start+1, ... stop-1 -crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop +crange crange_init(stop); // will generate 0, 1, ..., stop-1 +crange crange_init(start, stop); // will generate start, start+1, ... stop-1 +crange crange_init(start, stop, step); // will generate start, start+step, ... upto-not-including stop // note that step may be negative. crange_iter crange_begin(crange* self); crange_iter crange_end(crange* self); void crange_next(crange_iter* it); // 1. All primes less than 32: -crange r1 = crange_make(3, 32, 2); +crange r1 = crange_init(3, 32, 2); printf("2"); // first prime c_forfilter (i, crange, r1, isPrime(*i.ref)) printf(" %lld", *i.ref); @@ -98,7 +98,7 @@ c_forfilter (i, crange, r1, isPrime(*i.ref)) // 2. The first 11 primes: printf("2"); -crange range = crange_make(3, INT64_MAX, 2); +crange range = crange_init(3, INT64_MAX, 2); c_forfilter (i, crange, range, isPrime(*i.ref) && c_flt_take(10) @@ -139,7 +139,7 @@ bool isPrime(long long i) { int main(void) { // Get 10 prime numbers starting from 1000. Skip the first 15 primes, // then select every 25th prime (including the initial). - crange R = crange_make(1001, INT64_MAX, 2); // 1001, 1003, ... + crange R = crange_init(1001, INT64_MAX, 2); // 1001, 1003, ... c_forfilter (i, crange, R, isPrime(*i.ref) && diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h index 03162a2d..faeda162 100644 --- a/include/stc/algo/crange.h +++ b/include/stc/algo/crange.h @@ -27,14 +27,14 @@ int main(void) { - crange r1 = crange_make(80, 90); + crange r1 = crange_init(80, 90); c_foreach (i, crange, r1) printf(" %lld", *i.ref); puts(""); // use a temporary crange object. int a = 100, b = INT32_MAX; - crange r2 = crange_make(a, b, 8); + crange r2 = crange_init(a, b, 8); c_forfilter (i, crange, r2, c_flt_skip(i, 10) && c_flt_take(i, 3)) @@ -51,11 +51,12 @@ typedef long long crange_value; typedef struct { crange_value start, end, step, value; } crange; typedef struct { crange_value *ref, end, step; } crange_iter; -#define crange_make(...) c_MACRO_OVERLOAD(crange_make, __VA_ARGS__) -#define crange_make_1(stop) crange_make_3(0, stop, 1) -#define crange_make_2(start, stop) crange_make_3(start, stop, 1) +#define crange_make crange_init // [deprecated] +#define crange_init(...) c_MACRO_OVERLOAD(crange_init, __VA_ARGS__) +#define crange_init_1(stop) crange_init_3(0, stop, 1) +#define crange_init_2(start, stop) crange_init_3(start, stop, 1) -STC_INLINE crange crange_make_3(crange_value start, crange_value stop, crange_value step) +STC_INLINE crange crange_init_3(crange_value start, crange_value stop, crange_value step) { crange r = {start, stop - (step > 0), step}; return r; } STC_INLINE crange_iter crange_begin(crange* self) diff --git a/misc/examples/algorithms/forfilter.c b/misc/examples/algorithms/forfilter.c index 644b8459..c1426045 100644 --- a/misc/examples/algorithms/forfilter.c +++ b/misc/examples/algorithms/forfilter.c @@ -54,7 +54,7 @@ fn main() { void demo2(void) { IVec vector = {0}; - crange r = crange_make(INT64_MAX); + crange r = crange_init(INT64_MAX); c_forfilter (x, crange, r, c_flt_skipwhile(x, *x.ref != 11) && (*x.ref % 2) != 0 && @@ -124,7 +124,7 @@ void demo5(void) { #define flt_even(i) ((*i.ref & 1) == 0) #define flt_mid_decade(i) ((*i.ref % 10) != 0) - crange R = crange_make(1963, INT32_MAX); + crange R = crange_init(1963, INT32_MAX); c_forfilter (i, crange, R, c_flt_skip(i,15) && diff --git a/misc/examples/bitsets/prime.c b/misc/examples/bitsets/prime.c index e5764d83..462526a2 100644 --- a/misc/examples/bitsets/prime.c +++ b/misc/examples/bitsets/prime.c @@ -41,7 +41,7 @@ int main(void) puts("\n"); puts("Show the last 50 primes using a temporary crange generator:"); - crange range = crange_make(n - 1, 0, -2); + crange range = crange_init(n - 1, 0, -2); c_forfilter (i, crange, range, cbits_test(&primes, *i.ref/2) && -- cgit v1.2.3 From 684769d5fb56c9ad4dadbca2ef872b49a8cdf695 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 23 Jul 2023 23:40:15 +0200 Subject: Update benchmark files. --- misc/benchmarks/plotbench/cvec_benchmark.cpp | 6 +++--- misc/benchmarks/plotbench/plot.py | 2 +- misc/benchmarks/plotbench/run_all.bat | 2 +- misc/benchmarks/plotbench/run_clang.sh | 2 +- misc/benchmarks/plotbench/run_gcc.sh | 2 +- misc/benchmarks/plotbench/run_vc.bat | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/misc/benchmarks/plotbench/cvec_benchmark.cpp b/misc/benchmarks/plotbench/cvec_benchmark.cpp index 3b4c3d7d..45b9cf93 100644 --- a/misc/benchmarks/plotbench/cvec_benchmark.cpp +++ b/misc/benchmarks/plotbench/cvec_benchmark.cpp @@ -71,18 +71,18 @@ Sample test_stc_vector() { s.test[INSERT].t1 = clock(); container con = cvec_x_init(); csrand(seed); - c_forrange (N) cvec_x_push_back(&con, crand() & mask1); + c_forrange (N) cvec_x_push(&con, crand() & mask1); s.test[INSERT].t2 = clock(); s.test[INSERT].sum = cvec_x_size(&con); s.test[ERASE].t1 = clock(); - c_forrange (N) { cvec_x_pop_back(&con); } + c_forrange (N) { cvec_x_pop(&con); } s.test[ERASE].t2 = clock(); s.test[ERASE].sum = cvec_x_size(&con); cvec_x_drop(&con); }{ csrand(seed); container con = cvec_x_init(); - c_forrange (N) cvec_x_push_back(&con, crand() & mask2); + c_forrange (N) cvec_x_push(&con, crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; //cvec_x_iter it, end = cvec_x_end(&con); diff --git a/misc/benchmarks/plotbench/plot.py b/misc/benchmarks/plotbench/plot.py index e65631b7..8e684ccc 100644 --- a/misc/benchmarks/plotbench/plot.py +++ b/misc/benchmarks/plotbench/plot.py @@ -4,7 +4,7 @@ import pandas as pd import matplotlib.pyplot as plt #sns.set_theme(style="whitegrid") -comp = ['All compilers', 'Mingw-g++-11.3.0', 'Win-Clang-14.0.1', 'VC-19.28'] +comp = ['All compilers', 'Mingw-g++-13.1.0', 'Win-Clang-16.0.5', 'VC-19.36'] n = int(sys.argv[1]) if len(sys.argv) > 1 else 0 file = sys.argv[2] if len(sys.argv) > 2 else 'plot_win.csv' df = pd.read_csv(file) diff --git a/misc/benchmarks/plotbench/run_all.bat b/misc/benchmarks/plotbench/run_all.bat index 98913a50..23a62eed 100644 --- a/misc/benchmarks/plotbench/run_all.bat +++ b/misc/benchmarks/plotbench/run_all.bat @@ -4,4 +4,4 @@ echo gcc sh run_gcc.sh >> %out% echo clang sh run_clang.sh >> %out% -REM call run_vc.bat >> %out% +call run_vc.bat >> %out% diff --git a/misc/benchmarks/plotbench/run_clang.sh b/misc/benchmarks/plotbench/run_clang.sh index 59d577d9..fc3e90ec 100644 --- a/misc/benchmarks/plotbench/run_clang.sh +++ b/misc/benchmarks/plotbench/run_clang.sh @@ -6,7 +6,7 @@ clang++ -DNDEBUG -I../../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp clang++ -DNDEBUG -I../../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp clang++ -DNDEBUG -I../../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp -c='Win-Clang-14.0.1' +c='Win-Clang-16.0.5' ./cdeq_benchmark$exe $c ./clist_benchmark$exe $c ./cmap_benchmark$exe $c diff --git a/misc/benchmarks/plotbench/run_gcc.sh b/misc/benchmarks/plotbench/run_gcc.sh index 73b979d3..0bd2d6ee 100644 --- a/misc/benchmarks/plotbench/run_gcc.sh +++ b/misc/benchmarks/plotbench/run_gcc.sh @@ -4,7 +4,7 @@ g++ -DNDEBUG -I../../include -O3 -o cmap_benchmark cmap_benchmark.cpp g++ -DNDEBUG -I../../include -O3 -o csmap_benchmark csmap_benchmark.cpp g++ -DNDEBUG -I../../include -O3 -o cvec_benchmark cvec_benchmark.cpp -c='Mingw-g++-11.3.0' +c='Mingw-g++-13.1.0' ./cdeq_benchmark $c ./clist_benchmark $c ./cmap_benchmark $c diff --git a/misc/benchmarks/plotbench/run_vc.bat b/misc/benchmarks/plotbench/run_vc.bat index dc4938f8..a162fb64 100644 --- a/misc/benchmarks/plotbench/run_vc.bat +++ b/misc/benchmarks/plotbench/run_vc.bat @@ -6,9 +6,9 @@ cl.exe -nologo -EHsc -std:c++latest -I../include -O2 clist_benchmark.cpp >nul cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cmap_benchmark.cpp >nul cl.exe -nologo -EHsc -std:c++latest -I../include -O2 csmap_benchmark.cpp >nul cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cvec_benchmark.cpp >nul -del *.obj >nul +if exist *obj del *.obj -set c=VC-19.28 +set c=VC-19.36 cdeq_benchmark.exe %c% clist_benchmark.exe %c% cmap_benchmark.exe %c% -- cgit v1.2.3 From 890e210893d96a6658a838331fa233b4a58723c7 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 23 Jul 2023 23:43:55 +0200 Subject: Internal: Reorganized cqueue and cdeq: spliced out header and impl in cqueue.h to priv/cqueue_hdr.h and priv/cqueue_imp.h. --- include/stc/cdeq.h | 19 ++-- include/stc/cqueue.h | 206 +----------------------------------------- include/stc/priv/cqueue_hdr.h | 117 ++++++++++++++++++++++++ include/stc/priv/cqueue_imp.h | 129 ++++++++++++++++++++++++++ 4 files changed, 261 insertions(+), 210 deletions(-) create mode 100644 include/stc/priv/cqueue_hdr.h create mode 100644 include/stc/priv/cqueue_imp.h diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 056ef005..9892f6f1 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -20,16 +20,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include "priv/linkage.h" + +#ifndef CDEQ_H_INCLUDED +#include "ccommon.h" +#include "forward.h" +#include +#include +#endif // CDEQ_H_INCLUDED + #define _i_prefix cdeq_ #define _pop _pop_front #define _pull _pull_front -#ifdef i_more - #include "cqueue.h" - #define i_more -#else - #define i_more - #include "cqueue.h" -#endif +#include "priv/cqueue_hdr.h" #undef _pop STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value); @@ -122,6 +125,8 @@ _cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw raw) /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) +#include "priv/cqueue_imp.h" + STC_DEF _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value) { intptr_t start = (self->start - 1) & self->capmask; diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 5d38ca89..8a609b96 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -32,211 +32,11 @@ #ifndef _i_prefix #define _i_prefix cqueue_ #endif -#include "priv/template.h" - -#ifndef i_is_forward -_cx_DEFTYPES(_c_cdeq_types, _cx_Self, i_key); -#endif -typedef i_keyraw _cx_raw; - -STC_API _cx_Self _cx_MEMB(_with_capacity)(const intptr_t n); -STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n); -STC_API void _cx_MEMB(_clear)(_cx_Self* self); -STC_API void _cx_MEMB(_drop)(_cx_Self* self); -STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); // push_back -STC_API void _cx_MEMB(_shrink_to_fit)(_cx_Self *self); -STC_API _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n); - -#define _cdeq_toidx(self, pos) (((pos) - (self)->start) & (self)->capmask) -#define _cdeq_topos(self, idx) (((self)->start + (idx)) & (self)->capmask) - -STC_INLINE _cx_Self _cx_MEMB(_init)(void) - { _cx_Self cx = {0}; return cx; } -STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } -STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } - -#if !defined i_no_emplace -STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) - { return _cx_MEMB(_push)(self, i_keyfrom(raw)); } -#endif - -#if defined _i_has_eq || defined _i_has_cmp -STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other); -#endif - -#if !defined i_no_clone -STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); -STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val) - { return i_keyclone(val); } -#endif // !i_no_clone -STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) - { return _cdeq_toidx(self, self->end); } -STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) - { return self->capmask; } -STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) - { return self->start == self->end; } -STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval) - { return i_keyto(pval); } - -STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) - { return self->data + self->start; } - -STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) - { return self->data + ((self->end - 1) & self->capmask); } - -STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { // pop_front - c_assert(!_cx_MEMB(_empty)(self)); - i_keydrop((self->data + self->start)); - self->start = (self->start + 1) & self->capmask; -} - -STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { // move front out of queue - c_assert(!_cx_MEMB(_empty)(self)); - intptr_t s = self->start; - self->start = (s + 1) & self->capmask; - return self->data[s]; -} - -STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { - if (self->data == other->data) return; - _cx_MEMB(_drop)(self); - *self = _cx_MEMB(_clone)(*other); -} - -STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { - return c_LITERAL(_cx_iter){ - _cx_MEMB(_empty)(self) ? NULL : self->data + self->start, - self->start, self - }; -} - -STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) - { return c_LITERAL(_cx_iter){.pos=self->end, ._s=self}; } - -STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { - if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; } - else { it->ref -= it->pos; it->pos = 0; } - if (it->pos == it->_s->end) it->ref = NULL; -} - -STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) - { return _cdeq_toidx(self, it.pos); } - -STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) - { self->end = (self->end + n) & self->capmask; } +#include "priv/cqueue_hdr.h" /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) - -STC_DEF _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n) { - intptr_t len = _cx_MEMB(_size)(it._s); - intptr_t pos = it.pos, idx = _cdeq_toidx(it._s, pos); - it.pos = (pos + n) & it._s->capmask; - it.ref += it.pos - pos; - if (!c_LTu(idx + n, len)) it.ref = NULL; - return it; -} - -STC_DEF void -_cx_MEMB(_clear)(_cx_Self* self) { - c_foreach (i, _cx_Self, *self) - { i_keydrop(i.ref); } - self->start = 0, self->end = 0; -} - -STC_DEF void -_cx_MEMB(_drop)(_cx_Self* self) { - _cx_MEMB(_clear)(self); - i_free(self->data); -} - -STC_DEF _cx_Self -_cx_MEMB(_with_capacity)(const intptr_t n) { - _cx_Self cx = {0}; - _cx_MEMB(_reserve)(&cx, n); - return cx; -} - -STC_DEF bool -_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n) { - if (n <= self->capmask) - return true; - intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1); - _cx_value* d = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data); - if (!d) - return false; - intptr_t head = oldcap - self->start; - if (self->start <= self->end) - ; - else if (head < self->end) { - self->start = newcap - head; - c_memmove(d + self->start, d + oldcap - head, head*c_sizeof *d); - } else { - c_memmove(d + oldcap, d, self->end*c_sizeof *d); - self->end += oldcap; - } - self->capmask = newcap - 1; - self->data = d; - return true; -} - -STC_DEF _cx_value* -_cx_MEMB(_push)(_cx_Self* self, i_key value) { // push_back - intptr_t end = (self->end + 1) & self->capmask; - if (end == self->start) { // full - _cx_MEMB(_reserve)(self, self->capmask + 3); // => 2x expand - end = (self->end + 1) & self->capmask; - } - _cx_value *v = self->data + self->end; - self->end = end; - *v = value; - return v; -} - -STC_DEF void -_cx_MEMB(_shrink_to_fit)(_cx_Self *self) { - intptr_t sz = _cx_MEMB(_size)(self), j = 0; - if (sz > self->capmask/2) - return; - _cx_Self out = _cx_MEMB(_with_capacity)(sz); - if (!out.data) - return; - c_foreach (i, _cx_Self, *self) - out.data[j++] = *i.ref; - out.end = sz; - i_free(self->data); - *self = out; -} - -#if !defined i_no_clone -STC_DEF _cx_Self -_cx_MEMB(_clone)(_cx_Self cx) { - intptr_t sz = _cx_MEMB(_size)(&cx), j = 0; - _cx_Self out = _cx_MEMB(_with_capacity)(sz); - if (out.data) - c_foreach (i, _cx_Self, cx) - out.data[j++] = i_keyclone((*i.ref)); - out.end = sz; - return out; -} -#endif // i_no_clone - -#if defined _i_has_eq || defined _i_has_cmp -STC_DEF bool -_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; - for (_cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other); - i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) - { - const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); - if (!(i_eq((&_rx), (&_ry)))) return false; - } - return true; -} -#endif +#include "priv/cqueue_imp.h" #endif // IMPLEMENTATION -#include "priv/template2.h" #define CQUEUE_H_INCLUDED +#include "priv/template2.h" diff --git a/include/stc/priv/cqueue_hdr.h b/include/stc/priv/cqueue_hdr.h new file mode 100644 index 00000000..90539f36 --- /dev/null +++ b/include/stc/priv/cqueue_hdr.h @@ -0,0 +1,117 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "template.h" +#ifndef i_is_forward +_cx_DEFTYPES(_c_cdeq_types, _cx_Self, i_key); +#endif +typedef i_keyraw _cx_raw; + +STC_API _cx_Self _cx_MEMB(_with_capacity)(const intptr_t n); +STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n); +STC_API void _cx_MEMB(_clear)(_cx_Self* self); +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); // push_back +STC_API void _cx_MEMB(_shrink_to_fit)(_cx_Self *self); +STC_API _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n); + +#define _cdeq_toidx(self, pos) (((pos) - (self)->start) & (self)->capmask) +#define _cdeq_topos(self, idx) (((self)->start + (idx)) & (self)->capmask) + +STC_INLINE _cx_Self _cx_MEMB(_init)(void) + { _cx_Self cx = {0}; return cx; } +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } + +#if !defined i_no_emplace +STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push)(self, i_keyfrom(raw)); } +#endif + +#if defined _i_has_eq || defined _i_has_cmp +STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other); +#endif + +#if !defined i_no_clone +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); +STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val) + { return i_keyclone(val); } +#endif // !i_no_clone +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) + { return _cdeq_toidx(self, self->end); } +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) + { return self->capmask; } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) + { return self->start == self->end; } +STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval) + { return i_keyto(pval); } + +STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) + { return self->data + self->start; } + +STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) + { return self->data + ((self->end - 1) & self->capmask); } + +STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { // pop_front + c_assert(!_cx_MEMB(_empty)(self)); + i_keydrop((self->data + self->start)); + self->start = (self->start + 1) & self->capmask; +} + +STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { // move front out of queue + c_assert(!_cx_MEMB(_empty)(self)); + intptr_t s = self->start; + self->start = (s + 1) & self->capmask; + return self->data[s]; +} + +STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { + if (self->data == other->data) return; + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); +} + +STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { + return c_LITERAL(_cx_iter){ + _cx_MEMB(_empty)(self) ? NULL : self->data + self->start, + self->start, self + }; +} + +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) + { return c_LITERAL(_cx_iter){.pos=self->end, ._s=self}; } + +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { + if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; } + else { it->ref -= it->pos; it->pos = 0; } + if (it->pos == it->_s->end) it->ref = NULL; +} + +STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) + { return _cdeq_toidx(self, it.pos); } + +STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) + { self->end = (self->end + n) & self->capmask; } diff --git a/include/stc/priv/cqueue_imp.h b/include/stc/priv/cqueue_imp.h new file mode 100644 index 00000000..2ad9c811 --- /dev/null +++ b/include/stc/priv/cqueue_imp.h @@ -0,0 +1,129 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +STC_DEF _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n) { + intptr_t len = _cx_MEMB(_size)(it._s); + intptr_t pos = it.pos, idx = _cdeq_toidx(it._s, pos); + it.pos = (pos + n) & it._s->capmask; + it.ref += it.pos - pos; + if (!c_LTu(idx + n, len)) it.ref = NULL; + return it; +} + +STC_DEF void +_cx_MEMB(_clear)(_cx_Self* self) { + c_foreach (i, _cx_Self, *self) + { i_keydrop(i.ref); } + self->start = 0, self->end = 0; +} + +STC_DEF void +_cx_MEMB(_drop)(_cx_Self* self) { + _cx_MEMB(_clear)(self); + i_free(self->data); +} + +STC_DEF _cx_Self +_cx_MEMB(_with_capacity)(const intptr_t n) { + _cx_Self cx = {0}; + _cx_MEMB(_reserve)(&cx, n); + return cx; +} + +STC_DEF bool +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n) { + if (n <= self->capmask) + return true; + intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1); + _cx_value* d = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data); + if (!d) + return false; + intptr_t head = oldcap - self->start; + if (self->start <= self->end) + ; + else if (head < self->end) { + self->start = newcap - head; + c_memmove(d + self->start, d + oldcap - head, head*c_sizeof *d); + } else { + c_memmove(d + oldcap, d, self->end*c_sizeof *d); + self->end += oldcap; + } + self->capmask = newcap - 1; + self->data = d; + return true; +} + +STC_DEF _cx_value* +_cx_MEMB(_push)(_cx_Self* self, i_key value) { // push_back + intptr_t end = (self->end + 1) & self->capmask; + if (end == self->start) { // full + _cx_MEMB(_reserve)(self, self->capmask + 3); // => 2x expand + end = (self->end + 1) & self->capmask; + } + _cx_value *v = self->data + self->end; + self->end = end; + *v = value; + return v; +} + +STC_DEF void +_cx_MEMB(_shrink_to_fit)(_cx_Self *self) { + intptr_t sz = _cx_MEMB(_size)(self), j = 0; + if (sz > self->capmask/2) + return; + _cx_Self out = _cx_MEMB(_with_capacity)(sz); + if (!out.data) + return; + c_foreach (i, _cx_Self, *self) + out.data[j++] = *i.ref; + out.end = sz; + i_free(self->data); + *self = out; +} + +#if !defined i_no_clone +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self cx) { + intptr_t sz = _cx_MEMB(_size)(&cx), j = 0; + _cx_Self out = _cx_MEMB(_with_capacity)(sz); + if (out.data) + c_foreach (i, _cx_Self, cx) + out.data[j++] = i_keyclone((*i.ref)); + out.end = sz; + return out; +} +#endif // i_no_clone + +#if defined _i_has_eq || defined _i_has_cmp +STC_DEF bool +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; + for (_cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other); + i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) + { + const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); + if (!(i_eq((&_rx), (&_ry)))) return false; + } + return true; +} +#endif -- cgit v1.2.3 From 82668241cad0acdb6a56b0a520f496f06be9ff9a Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 23 Jul 2023 23:47:01 +0200 Subject: Updated singleheader.py/singleupdate.sh scripts to update stcsingle repository. --- src/singleheader.py | 18 ++++++++++-------- src/singleupdate.sh | 53 ++++++++++++++++++++++++++++------------------------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/singleheader.py b/src/singleheader.py index 2255568d..637edbcb 100644 --- a/src/singleheader.py +++ b/src/singleheader.py @@ -68,12 +68,14 @@ def process_file( if __name__ == "__main__": - print( - process_file( - abspath(sys.argv[1]), - [], - # We use an include guard instead of `#pragma once` because Godbolt will - # cause complaints about `#pragma once` when they are used in URL includes. - [abspath(sys.argv[1])], + with open(sys.argv[2], "w", newline='\n') as f: + print( + process_file( + abspath(sys.argv[1]), + [], + # We use an include guard instead of `#pragma once` because Godbolt will + # cause complaints about `#pragma once` when they are used in URL includes. + [abspath(sys.argv[1])], + ), + file=f ) - ) diff --git a/src/singleupdate.sh b/src/singleupdate.sh index 8a621e57..e706dd97 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -1,27 +1,30 @@ d=$(git rev-parse --show-toplevel) -mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc -python singleheader.py $d/include/c11/fmt.h > $d/../stcsingle/c11/fmt.h -python singleheader.py $d/include/stc/calgo.h > $d/../stcsingle/stc/calgo.h -python singleheader.py $d/include/stc/carc.h > $d/../stcsingle/stc/carc.h -python singleheader.py $d/include/stc/cbits.h > $d/../stcsingle/stc/cbits.h -python singleheader.py $d/include/stc/cbox.h > $d/../stcsingle/stc/cbox.h -python singleheader.py $d/include/stc/ccommon.h > $d/../stcsingle/stc/ccommon.h -python singleheader.py $d/include/stc/cdeq.h > $d/../stcsingle/stc/cdeq.h -python singleheader.py $d/include/stc/clist.h > $d/../stcsingle/stc/clist.h -python singleheader.py $d/include/stc/cmap.h > $d/../stcsingle/stc/cmap.h -python singleheader.py $d/include/stc/coption.h > $d/../stcsingle/stc/coption.h -python singleheader.py $d/include/stc/cpque.h > $d/../stcsingle/stc/cpque.h -python singleheader.py $d/include/stc/cqueue.h > $d/../stcsingle/stc/cqueue.h -python singleheader.py $d/include/stc/crand.h > $d/../stcsingle/stc/crand.h -python singleheader.py $d/include/stc/cregex.h > $d/../stcsingle/stc/cregex.h -python singleheader.py $d/include/stc/cset.h > $d/../stcsingle/stc/cset.h -python singleheader.py $d/include/stc/csmap.h > $d/../stcsingle/stc/csmap.h -python singleheader.py $d/include/stc/cspan.h > $d/../stcsingle/stc/cspan.h -python singleheader.py $d/include/stc/csset.h > $d/../stcsingle/stc/csset.h -python singleheader.py $d/include/stc/cstack.h > $d/../stcsingle/stc/cstack.h -python singleheader.py $d/include/stc/cstr.h > $d/../stcsingle/stc/cstr.h -python singleheader.py $d/include/stc/csview.h > $d/../stcsingle/stc/csview.h -python singleheader.py $d/include/stc/cvec.h > $d/../stcsingle/stc/cvec.h -python singleheader.py $d/include/stc/extend.h > $d/../stcsingle/stc/extend.h -python singleheader.py $d/include/stc/forward.h > $d/../stcsingle/stc/forward.h +mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc/algo +python singleheader.py $d/include/c11/fmt.h $d/../stcsingle/c11/fmt.h +python singleheader.py $d/include/stc/algorithm.h $d/../stcsingle/stc/algorithm.h +python singleheader.py $d/include/stc/coroutine.h $d/../stcsingle/stc/coroutine.h +python singleheader.py $d/include/stc/algo/sort.h $d/../stcsingle/stc/algo/sort.h +python singleheader.py $d/include/stc/carc.h $d/../stcsingle/stc/carc.h +python singleheader.py $d/include/stc/cbits.h $d/../stcsingle/stc/cbits.h +python singleheader.py $d/include/stc/cbox.h $d/../stcsingle/stc/cbox.h +python singleheader.py $d/include/stc/ccommon.h $d/../stcsingle/stc/ccommon.h +python singleheader.py $d/include/stc/cdeq.h $d/../stcsingle/stc/cdeq.h +python singleheader.py $d/include/stc/clist.h $d/../stcsingle/stc/clist.h +python singleheader.py $d/include/stc/cmap.h $d/../stcsingle/stc/cmap.h +python singleheader.py $d/include/stc/coption.h $d/../stcsingle/stc/coption.h +python singleheader.py $d/include/stc/cpque.h $d/../stcsingle/stc/cpque.h +python singleheader.py $d/include/stc/cqueue.h $d/../stcsingle/stc/cqueue.h +python singleheader.py $d/include/stc/crand.h $d/../stcsingle/stc/crand.h +python singleheader.py $d/include/stc/cregex.h $d/../stcsingle/stc/cregex.h +python singleheader.py $d/include/stc/cset.h $d/../stcsingle/stc/cset.h + +python singleheader.py $d/include/stc/csmap.h $d/../stcsingle/stc/csmap.h +python singleheader.py $d/include/stc/cspan.h $d/../stcsingle/stc/cspan.h +python singleheader.py $d/include/stc/csset.h $d/../stcsingle/stc/csset.h +python singleheader.py $d/include/stc/cstack.h $d/../stcsingle/stc/cstack.h +python singleheader.py $d/include/stc/cstr.h $d/../stcsingle/stc/cstr.h +python singleheader.py $d/include/stc/csview.h $d/../stcsingle/stc/csview.h +python singleheader.py $d/include/stc/cvec.h $d/../stcsingle/stc/cvec.h +python singleheader.py $d/include/stc/extend.h $d/../stcsingle/stc/extend.h +python singleheader.py $d/include/stc/forward.h $d/../stcsingle/stc/forward.h echo "$d/../stcsingle headers updated" -- cgit v1.2.3 From e8aed0431140fd0d202d302f19f756046858bad7 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 23 Jul 2023 23:48:00 +0200 Subject: Updated docs. --- README.md | 60 +++--- docs/algorithm_api.md | 434 +++++++++++++++++++++++++++++++++++++++ docs/ccommon_api.md | 557 -------------------------------------------------- docs/cspan_api.md | 11 +- 4 files changed, 470 insertions(+), 592 deletions(-) create mode 100644 docs/algorithm_api.md delete mode 100644 docs/ccommon_api.md diff --git a/README.md b/README.md index b49214d4..6351fc07 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ STC - Smart Template Containers =============================== -### [Version 4.3 RC3](#version-history) - +### [Version 4.3 Released](#version-history) +- See details for breaking changes. --- Description ----------- @@ -33,10 +33,10 @@ Containers Algorithms ---------- -- [***Ranged for-loops*** - c_foreach, c_forpair, c_forlist](docs/ccommon_api.md#ranged-for-loops) -- [***Range algorithms*** - c_forrange, crange, c_forfilter](docs/ccommon_api.md#range-algorithms) -- [***Generic algorithms*** - c_init, c_find_if, c_erase_if, csort, etc.](docs/ccommon_api.md#generic-algorithms) -- [***Coroutines*** - Simon Tatham's coroutines done right.](docs/ccommon_api.md#coroutines) +- [***Ranged for-loops*** - c_foreach, c_forpair, c_forlist](docs/algorithm_api.md#ranged-for-loops) +- [***Range algorithms*** - c_forrange, crange, c_forfilter](docs/algorithm_api.md#range-algorithms) +- [***Generic algorithms*** - c_init, c_find_if, c_erase_if, csort, etc.](docs/algorithm_api.md#generic-algorithms) +- [***Coroutines*** - ergonomic portable coroutines](docs/coroutine_api.md) - [***Regular expressions*** - Rob Pike's Plan 9 regexp modernized!](docs/cregex_api.md) - [***Random numbers*** - a very fast *PRNG* based on *SFC64*](docs/crandom_api.md) - [***Command line argument parser*** - similar to *getopt()*](docs/coption_api.md) @@ -61,12 +61,11 @@ List of contents --- ## Highlights -- **No boilerplate code** - Specify only the required template parameters, e.g. ***cmp***- and/or ***clone***-, ***drop***- functions, and leave the rest as defaults. +- **Minimal boilerplate code** - Specify only the required template parameters, and leave the rest as defaults. - **Fully type safe** - Because of templating, it avoids error-prone casting of container types and elements back and forth from the containers. -- **User friendly** - Just include the headers and you are good. The API and functionality is very close to c++ STL and is fully listed in the docs. -- **Unparalleled performance** - Maps and sets are much faster than the C++ STL containers, the remaining are similar in speed. +- **High performance** - Unordered maps and sets, queues and deques are significantly faster than the C++ STL containers, the remaining are similar or close to STL in speed (See graph below). - **Fully memory managed** - Containers destructs keys/values via default or user supplied drop function. They may be cloned if element types are clonable. Also, smart pointers are supported and can be stored in containers. See [***carc***](docs/carc_api.md) and [***cbox***](docs/cbox_api.md). -- **Uniform, easy-to-learn API** - Intuitive method/type names and uniform usage across the various containers. +- **Uniform, easy-to-learn API** - Just include the headers and you are good. The API and functionality resembles c++ STL and is fully listed in the docs. Intuitive method/type names and uniform usage across the various containers. - **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed for comparison and calculation is asking for trouble. STC only uses signed numbers in the API for this reason. - **Small footprint** - Small source code and generated executables. The executable from the example below using *four different* container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux. - **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section. @@ -95,17 +94,17 @@ So instead of calling e.g. `cvec_str_push(&vec, cstr_from("Hello"))`, you may ca same element access syntax. E.g.: - `c_foreach (it, MyInts, myints) *it.ref += 42;` works for any container defined as `MyInts` with `int` elements. - - `c_foreach (it, MyInts, it1, it2) *it.ref += 42;` iterates from `it1` up to `it2`. + - `c_foreach (it, MyInts, it1, it2) *it.ref += 42;` iterates from `it1` up to not including `it2`. --- ## Performance STC is a fast and memory efficient library, and code compiles fast: -![Benchmark](misc/benchmarks/pics/benchmark.gif) +![Benchmark](docs/pics/Figure_1.png) Benchmark notes: -- The barchart shows average test times over three platforms: Mingw64 10.30, Win-Clang 12, VC19. CPU: Ryzen 7 2700X CPU @4Ghz. +- The barchart shows average test times over three compilers: **Mingw64 13.1.0, Win-Clang 16.0.5, VC-19-36**. CPU: **Ryzen 7 5700X**. - Containers uses value types `uint64_t` and pairs of `uint64_t` for the maps. - Black bars indicates performance variation between various platforms/compilers. - Iterations are repeated 4 times over n elements. @@ -615,19 +614,20 @@ STC is generally very memory efficient. Memory usage for the different container ## Version 4.3 - Some breaking changes. -- coroutines: much improved with some new API and added features. -- cspan: Support for column-major (fortran order) multidim spans and transposed views. -- Removed default comparison for clist, cvec and cdeq (as with cstack and cqueue). - - Using i_key_str, i_keyclass, i_keyboxed still expects comparisons defined. - - Define i_cmp_native to enable built-in i_key types comparisons (<, ==). -- cstr and csview are now shared linked by default. Static linking by defining i_static. -- New cdeq and cqueue implementation(s), using circular buffer. -- Renamed i_extern => i_import. - - Define i_import before #include will also define utf8 case conversions. - - Define i_import before #include will also define cstr + utf8 tables. -- Renamed c_make() => c_init() macro for initialization lists. -- Renamed input enum flags for cregex functions. -- Removed deprecated crandom.h. Use crand.h with new API. +- **coroutines**: much improved with some new API and added features. +- **cspan**: Rewritten to add support for **column-major** order (fortran) multidim spans and transposed views. +- Removed default comparison for **clist**, **cvec** and **cdeq** (like cstack and cqueue). + - Define `i_cmp_native` to enable built-in i_key types comparisons (<, ==). + - Use of `i_keyclass` still expects comparison functions defined. + - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined. +- **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. +- All new faster and smaller **cqueue** and **cdeq** implementations, using a circular buffer. +- Renamed i_extern => `i_import`. + - Define `i_import` before `#include ` will also define utf8 case conversions. + - Define `i_import` before `#include ` will also define cstr + utf8 tables. +- Renamed c_make() => ***c_init()*** macro for initializing containers with element lists. +- Renamed input enum flags for ***cregex***-functions. +- Removed deprecated . Use `` with the new API. - Removed deprecated uppercase flow-control macro names. - Improved default string hash function. @@ -653,8 +653,8 @@ Major changes: - Customizable allocator [per templated container type](https://github.com/tylov/STC/discussions/44#discussioncomment-4891925). - Updates on **cregex** with several [new unicode character classes](docs/cregex_api.md#regex-cheatsheet). - Algorithms: - - [crange](docs/ccommon_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - - [c_forfilter](docs/ccommon_api.md#c_forfilter) - ranges-like view filtering. + - [crange](docs/algorithm_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. + - [c_forfilter](docs/algorithm_api.md#c_forfilter) - ranges-like view filtering. - [csort](include/stc/algo/sort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. - Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. - Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. @@ -715,10 +715,10 @@ Major changes: - Renamed: *csptr_X_make()* to `carc_X_from()`. - Renamed: *cstr_new()* to `cstr_lit(literal)`, and *cstr_assign_fmt()* to `cstr_printf()`. - Renamed: *c_default_fromraw()* to `c_default_from()`. -- Changed: the [**c_apply**](docs/ccommon_api.md) macros API. +- Changed: the [**c_apply**](docs/algorithm_api.md) macros API. - Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`. - Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly. - Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions. - Added: `i_opt` template parameter: compile-time options: `c_no_cmp`, `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` - Added: [**cbox**](docs/cbox_api.md) type: smart pointer, similar to [Rust Box](https://doc.rust-lang.org/rust-by-example/std/box.html) and [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr). -- Added: [**c_forpair**](docs/ccommon_api.md) macro: for-loop with "structured binding" +- Added: [**c_forpair**](docs/algorithm_api.md) macro: for-loop with "structured binding" diff --git a/docs/algorithm_api.md b/docs/algorithm_api.md new file mode 100644 index 00000000..490771b5 --- /dev/null +++ b/docs/algorithm_api.md @@ -0,0 +1,434 @@ +# STC Algorithms + +"No raw loops" - Sean Parent +## Ranged for-loops + +### c_foreach, c_forpair +```c +#include +``` + +| Usage | Description | +|:-----------------------------------------|:------------------------------------------| +| `c_foreach (it, ctype, container)` | Iteratate all elements | +| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | +| `c_forpair (key, val, ctype, container)` | Iterate with structured binding | + +```c +#define i_key int +#define i_val int +#define i_tag ii +#include +... +csmap_ii map = c_init(csmap_ii, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} }); + +c_foreach (i, csmap_ii, map) + printf(" %d", i.ref->first); +// 3 5 7 12 23 +// same without using c_foreach: +for (csmap_ii_iter i = csmap_ii_begin(&map); i.ref; csmap_ii_next(&i)) + printf(" %d", i.ref->first); + +csmap_ii_iter it = csmap_ii_find(&map, 7); +// iterate from it to end +c_foreach (i, csmap_ii, it, csmap_ii_end(&map)) + printf(" %d", i.ref->first); +// 7 12 23 + +// structured binding: +c_forpair (id, count, csmap_ii, map) + printf(" (%d %d)", *_.id, *_.count); +// (3 2) (5 4) (7 3) (12 5) (23 1) +``` + +### c_forlist +Iterate compound literal array elements. Additional to `i.ref`, you can access `i.size` and `i.index` for the input list/element. +```c +// apply multiple push_backs +c_forlist (i, int, {1, 2, 3}) + cvec_i_push_back(&vec, *i.ref); + +// insert in existing map +c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) + cmap_ii_insert(&map, i.ref->first, i.ref->second); + +// string literals pushed to a stack of cstr: +c_forlist (i, const char*, {"Hello", "crazy", "world"}) + cstack_str_emplace(&stk, *i.ref); +``` +--- + +## Integer range loops + +### c_forrange +Abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop. + +| Usage | Python equivalent | +|:---------------------------------------------|:-------------------------------------| +| `c_forrange (stop)` | `for _ in range(stop):` | +| `c_forrange (i, stop) // i type = long long` | `for i in range(stop):` | +| `c_forrange (i, start, stop)` | `for i in range(start, stop):` | +| `c_forrange (i, start, stop, step)` | `for i in range(start, stop, step):` | + +```c +c_forrange (5) printf("x"); +// xxxxx +c_forrange (i, 5) printf(" %lld", i); +// 0 1 2 3 4 +c_forrange (i, -3, 3) printf(" %lld", i); +// -3 -2 -1 0 1 2 +c_forrange (i, 30, 0, -5) printf(" %lld", i); +// 30 25 20 15 10 5 +``` + +### crange: Integer range generator object +A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: +```c +crange crange_init(stop); // will generate 0, 1, ..., stop-1 +crange crange_init(start, stop); // will generate start, start+1, ... stop-1 +crange crange_init(start, stop, step); // will generate start, start+step, ... upto-not-including stop + // note that step may be negative. +crange_iter crange_begin(crange* self); +crange_iter crange_end(crange* self); +void crange_next(crange_iter* it); + +// 1. All primes less than 32: +crange r1 = crange_init(3, 32, 2); +printf("2"); // first prime +c_forfilter (i, crange, r1, isPrime(*i.ref)) + printf(" %lld", *i.ref); +// 2 3 5 7 11 13 17 19 23 29 31 + +// 2. The first 11 primes: +printf("2"); +crange range = crange_init(3, INT64_MAX, 2); +c_forfilter (i, crange, range, + isPrime(*i.ref) && + c_flt_take(10) +){ + printf(" %lld", *i.ref); +} +// 2 3 5 7 11 13 17 19 23 29 31 +``` + +### c_forfilter +Iterate a container or a crange with chained `&&` filtering. + +| Usage | Description | +|:----------------------------------------------------|:---------------------------------------| +| `c_forfilter (it, ctype, container, filter)` | Filter out items in chain with && | +| `c_forfilter_it (it, ctype, startit, filter)` | Filter from startit iterator position | + +| Built-in filter | Description | +|:----------------------------------|:-------------------------------------------| +| `c_flt_skip(it, numItems)` | Skip numItems (inc count) | +| `c_flt_take(it, numItems)` | Take numItems (inc count) | +| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false | +| `c_flt_takewhile(it, predicate)` | Take items until predicate is false | +| `c_flt_counter(it)` | Increment current and return count | +| `c_flt_getcount(it)` | Number of items passed skip*/take*/counter | + +[ [Run this example](https://godbolt.org/z/n9aYrYPv8) ] +```c +#include +#include + +bool isPrime(long long i) { + for (long long j=2; j*j <= i; ++j) + if (i % j == 0) return false; + return true; +} + +int main(void) { + // Get 10 prime numbers starting from 1000. Skip the first 15 primes, + // then select every 25th prime (including the initial). + crange R = crange_init(1001, INT64_MAX, 2); // 1001, 1003, ... + + c_forfilter (i, crange, R, + isPrime(*i.ref) && + c_flt_skip(i, 15) && + c_flt_counter(i) % 25 == 1 && + c_flt_take(i, 10) + ){ + printf(" %lld", *i.ref); + } +} +// out: 1097 1289 1481 1637 1861 2039 2243 2417 2657 2803 +``` +Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false. + +--- +## Generic algorithms + +### c_init, c_drop + +Make any container from an initializer list: +```c +#define i_key_str // owned cstr string value type +#include + +#define i_key int +#define i_val int +#include +... +// Initializes with const char*, internally converted to cstr! +cset_str myset = c_init(cset_str, {"This", "is", "the", "story"}); + +int x = 7, y = 8; +cmap_int mymap = c_init(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); +``` +Drop multiple containers of the same type: +```c +c_drop(cset_str, &myset, &myset2); +``` + +### c_find_if, c_erase_if, c_eraseremove_if +Find or erase linearily in containers using a predicate +- For `c_find_if(iter, C, c, pred)`, ***iter*** is in/out and must be declared prior to call. +- Use `c_erase_if(iter, C, c, pred)` with **clist**, **cmap**, **cset**, **csmap**, and **csset**. +- Use `c_eraseremove_if(iter, C, c, pred)` with **cstack**, **cvec**, **cdeq**, and **cqueue**. +```c +// Search vec for first value > 2: +cvec_i_iter i; +c_find_if(i, cvec_i, vec, *i.ref > 2); +if (i.ref) printf("%d\n", *i.ref); + +// Erase all values > 2 in vec: +c_eraseremove_if(i, cvec_i, vec, *i.ref > 2); + +// Search map for a string containing "hello" and erase it: +cmap_str_iter it, it1 = ..., it2 = ...; +c_find_if(it, csmap_str, it1, it2, cstr_contains(it.ref, "hello")); +if (it.ref) cmap_str_erase_at(&map, it); + +// Erase all strings containing "hello" in a sorted map: +c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello")); +``` + +### sort_n_ - two times faster qsort + +The **sort_n**, **sort_ij** algorithm is about twice as fast as *qsort()*, and often simpler to use. +You may customize `i_tag` and the comparison function `i_cmp` or `i_less`. + +There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c). +```c +#define i_key int +#include +#include + +int main(void) { + int nums[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}; + ints_sort_n(nums, c_arraylen(nums)); // note: function name derived from i_key + c_forrange (i, c_arraylen(arr)) printf(" %d", arr[i]); +} +``` +Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is +possible and very fast. Note that `i_more` must be defined to retain specified template parameters for use by sort: +```c +#define i_type MyDeq +#define i_key int +#define i_more +#include // deque +#include +#include + +int main(void) { + MyDeq deq = c_init(MyDeq, {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}); + MyDeq_sort_n(&deq, MyDeq_size(&deq)); + c_foreach (i, MyDeq, deq) printf(" %d", *i.ref); + MyDeq_drop(&deq); +} +``` + +### c_new, c_delete + +- `c_new(Type, val)` - Allocate *and init* a new object on the heap +- `c_delete(Type, ptr)` - Drop *and free* an object allocated on the heap. NULL is OK. +```c +#include + +cstr *str_p = c_new(cstr, cstr_from("Hello")); +printf("%s\n", cstr_str(str_p)); +c_delete(cstr, str_p); +``` + +### c_malloc, c_calloc, c_realloc, c_free +Memory allocator wrappers that uses signed sizes. + +### c_arraylen +Return number of elements in an array. array must not be a pointer! +```c +int array[] = {1, 2, 3, 4}; +intptr_t n = c_arraylen(array); +``` + +### c_swap, c_const_cast +```c +// Safe macro for swapping internals of two objects of same type: +c_swap(cmap_int, &map1, &map2); + +// Type-safe casting a from const (pointer): +const char cs[] = "Hello"; +char* s = c_const_cast(char*, cs); // OK +int* ip = c_const_cast(int*, cs); // issues a warning! +``` + +### Predefined template parameter functions + +**crawstr** - Non-owned `const char*` "class" element type: `#define i_keyclass crawstr` +```c +typedef const char* crawstr; +int crawstr_cmp(const crawstr* x, const crawstr* y); +bool crawstr_eq(const crawstr* x, const crawstr* y); +uint64_t crawstr_hash(const crawstr* x); +``` +Default implementations +```c +int c_default_cmp(const Type*, const Type*); // <=> +bool c_default_less(const Type*, const Type*); // < +bool c_default_eq(const Type*, const Type*); // == +uint64_t c_default_hash(const Type*); +Type c_default_clone(Type val); // return val +Type c_default_toraw(const Type* p); // return *p +void c_default_drop(Type* p); // does nothing +``` +--- +## RAII scope macros +General ***defer*** mechanics for resource acquisition. These macros allows you to specify the +freeing of the resources at the point where the acquisition takes place. +The **checkauto** utility described below, ensures that the `c_auto*` macros are used correctly. + +| Usage | Description | +|:---------------------------------------|:----------------------------------------------------------| +| `c_defer (drop...)` | Defer `drop...` to end of scope | +| `c_scope (init, drop)` | Execute `init` and defer `drop` to end of scope | +| `c_scope (init, pred, drop)` | Adds a predicate in order to exit early if init failed | +| `c_with (Type var=init, drop)` | Declare `var`. Defer `drop...` to end of scope | +| `c_with (Type var=init, pred, drop)` | Adds a predicate in order to exit early if init failed | +| `c_auto (Type, var1,...,var4)` | `c_with (Type var1=Type_init(), Type_drop(&var1))` ... | +| `continue` | Exit a defer-block without resource leak | + +```c +#include // or +... +// `c_defer` executes the expression(s) when leaving scope. +// Note: does not require inclusion of "raii.h". +cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); +c_defer (cstr_drop(&s1), cstr_drop(&s2)) +{ + printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); +} + +// `c_scope` syntactically "binds" initialization and defer. +static pthread_mutex_t mut; +c_scope (pthread_mutex_lock(&mut), pthread_mutex_unlock(&mut)) +{ + /* Do syncronized work. */ +} + +// `c_with` is similar to python `with`: declare a variable and defer the drop call. +c_with (cstr str = cstr_lit("Hello"), cstr_drop(&str)) +{ + cstr_append(&str, " world"); + printf("%s\n", cstr_str(&str)); +} + +// `c_auto` automatically initialize and drops up to 4 variables: +c_auto (cstr, s1, s2) +{ + cstr_append(&s1, "Hello"); + cstr_append(&s1, " world"); + cstr_append(&s2, "Cool"); + cstr_append(&s2, " stuff"); + printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); +} +``` +**Example 1**: Use multiple **c_with** in sequence: +```c +bool ok = false; +c_with (uint8_t* buf = malloc(BUF_SIZE), buf != NULL, free(buf)) +c_with (FILE* fp = fopen(fname, "rb"), fp != NULL, fclose(fp)) +{ + int n = fread(buf, 1, BUF_SIZE, fp); + if (n <= 0) continue; // auto cleanup! NB do not break or return here. + ... + ok = true; +} +return ok; +``` +**Example 2**: Load each line of a text file into a vector of strings: +```c +#include +#define i_implement +#include + +#define i_key_str +#include + +// receiver should check errno variable +cvec_str readFile(const char* name) +{ + cvec_str vec = {0}; // returned + c_with (FILE* fp = fopen(name, "r"), fp != NULL, fclose(fp)) + c_with (cstr line = {0}, cstr_drop(&line)) + while (cstr_getline(&line, fp)) + cvec_str_emplace(&vec, cstr_str(&line)); + return vec; +} + +int main(void) +{ + c_with (cvec_str vec = readFile(__FILE__), cvec_str_drop(&vec)) + c_foreach (i, cvec_str, vec) + printf("| %s\n", cstr_str(i.ref)); +} +``` + +### The **checkauto** utility program (for RAII) +The **checkauto** program will check the source code for any misuses of the `c_auto*` macros which +may lead to resource leakages. The `c_auto*`- macros are implemented as one-time executed **for-loops**, +so any `return` or `break` appearing within such a block will lead to resource leaks, as it will disable +the cleanup/drop method to be called. A `break` may originally be intended to break a loop or switch +outside the `c_auto` scope. + +NOTE: One must always make sure to unwind temporary allocated resources before a `return` in C. However, by using `c_auto*`-macros, +- it is much easier to automatically detect misplaced return/break between resource acquisition and destruction. +- it prevents forgetting to call the destructor at the end. + +The **checkauto** utility will report any misusages. The following example shows how to correctly break/return +from a `c_auto` scope: +```c +int flag = 0; +for (int i = 0; i 0) break; + ... +} +``` diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md deleted file mode 100644 index 0e8d9719..00000000 --- a/docs/ccommon_api.md +++ /dev/null @@ -1,557 +0,0 @@ -# STC Algorithms - ---- -## Ranged for-loops - -### c_foreach, c_forpair - -| Usage | Description | -|:-----------------------------------------|:------------------------------------------| -| `c_foreach (it, ctype, container)` | Iteratate all elements | -| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | -| `c_forpair (key, val, ctype, container)` | Iterate with structured binding | - -```c -#define i_key int -#define i_val int -#define i_tag ii -#include -... -csmap_ii map = c_init(csmap_ii, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} }); - -c_foreach (i, csmap_ii, map) - printf(" %d", i.ref->first); -// 3 5 7 12 23 -// same without using c_foreach: -for (csmap_ii_iter i = csmap_ii_begin(&map); i.ref; csmap_ii_next(&i)) - printf(" %d", i.ref->first); - -csmap_ii_iter it = csmap_ii_find(&map, 7); -// iterate from it to end -c_foreach (i, csmap_ii, it, csmap_ii_end(&map)) - printf(" %d", i.ref->first); -// 7 12 23 - -// structured binding: -c_forpair (id, count, csmap_ii, map) - printf(" (%d %d)", *_.id, *_.count); -// (3 2) (5 4) (7 3) (12 5) (23 1) -``` - -### c_forlist -Iterate compound literal array elements. Additional to `i.ref`, you can access `i.size` and `i.index` for the input list/element. -```c -// apply multiple push_backs -c_forlist (i, int, {1, 2, 3}) - cvec_i_push_back(&vec, *i.ref); - -// insert in existing map -c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) - cmap_ii_insert(&map, i.ref->first, i.ref->second); - -// string literals pushed to a stack of cstr: -c_forlist (i, const char*, {"Hello", "crazy", "world"}) - cstack_str_emplace(&stk, *i.ref); -``` - ---- -## Range algorithms - -### c_forrange -Abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop. - -| Usage | Python equivalent | -|:---------------------------------------------|:-------------------------------------| -| `c_forrange (stop)` | `for _ in range(stop):` | -| `c_forrange (i, stop) // i type = long long` | `for i in range(stop):` | -| `c_forrange (i, start, stop)` | `for i in range(start, stop):` | -| `c_forrange (i, start, stop, step)` | `for i in range(start, stop, step):` | - -```c -c_forrange (5) printf("x"); -// xxxxx -c_forrange (i, 5) printf(" %lld", i); -// 0 1 2 3 4 -c_forrange (i, -3, 3) printf(" %lld", i); -// -3 -2 -1 0 1 2 -c_forrange (i, 30, 0, -5) printf(" %lld", i); -// 30 25 20 15 10 5 -``` - -### crange -A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: -```c -crange crange_init(stop); // will generate 0, 1, ..., stop-1 -crange crange_init(start, stop); // will generate start, start+1, ... stop-1 -crange crange_init(start, stop, step); // will generate start, start+step, ... upto-not-including stop - // note that step may be negative. -crange_iter crange_begin(crange* self); -crange_iter crange_end(crange* self); -void crange_next(crange_iter* it); - -// 1. All primes less than 32: -crange r1 = crange_init(3, 32, 2); -printf("2"); // first prime -c_forfilter (i, crange, r1, isPrime(*i.ref)) - printf(" %lld", *i.ref); -// 2 3 5 7 11 13 17 19 23 29 31 - -// 2. The first 11 primes: -printf("2"); -crange range = crange_init(3, INT64_MAX, 2); -c_forfilter (i, crange, range, - isPrime(*i.ref) && - c_flt_take(10) -){ - printf(" %lld", *i.ref); -} -// 2 3 5 7 11 13 17 19 23 29 31 -``` - -### c_forfilter -Iterate a container/range with chained range filtering. - -| Usage | Description | -|:----------------------------------------------------|:---------------------------------------| -| `c_forfilter (it, ctype, container, filter)` | Filter out items in chain with && | -| `c_forfilter_it (it, ctype, startit, filter)` | Filter from startit position | - -| Built-in filter | Description | -|:----------------------------------|:-------------------------------------------| -| `c_flt_skip(it, numItems)` | Skip numItems (inc count) | -| `c_flt_take(it, numItems)` | Take numItems (inc count) | -| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false | -| `c_flt_takewhile(it, predicate)` | Take items until predicate is false | -| `c_flt_counter(it)` | Increment current and return count | -| `c_flt_getcount(it)` | Number of items passed skip*/take*/counter | - -[ [Run this example](https://godbolt.org/z/n9aYrYPv8) ] -```c -#include -#include - -bool isPrime(long long i) { - for (long long j=2; j*j <= i; ++j) - if (i % j == 0) return false; - return true; -} - -int main(void) { - // Get 10 prime numbers starting from 1000. Skip the first 15 primes, - // then select every 25th prime (including the initial). - crange R = crange_init(1001, INT64_MAX, 2); // 1001, 1003, ... - - c_forfilter (i, crange, R, - isPrime(*i.ref) && - c_flt_skip(i, 15) && - c_flt_counter(i) % 25 == 1 && - c_flt_take(i, 10) - ){ - printf(" %lld", *i.ref); - } -} -// out: 1097 1289 1481 1637 1861 2039 2243 2417 2657 2803 -``` -Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false. - ---- -## Generic algorithms - -### c_init, c_drop - -Make any container from an initializer list: -```c -#define i_key_str // owned cstr string value type -#include - -#define i_key int -#define i_val int -#include -... -// Initializes with const char*, internally converted to cstr! -cset_str myset = c_init(cset_str, {"This", "is", "the", "story"}); - -int x = 7, y = 8; -cmap_int mymap = c_init(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); -``` -Drop multiple containers of the same type: -```c -c_drop(cset_str, &myset, &myset2); -``` - -### c_find_if, c_erase_if, c_eraseremove_if -Find or erase linearily in containers using a predicate -- For `c_find_if(iter, C, c, pred)`, ***iter*** is in/out and must be declared prior to call. -- Use `c_erase_if(iter, C, c, pred)` with **clist**, **cmap**, **cset**, **csmap**, and **csset**. -- Use `c_eraseremove_if(iter, C, c, pred)` with **cstack**, **cvec**, **cdeq**, and **cqueue**. -```c -// Search vec for first value > 2: -cvec_i_iter i; -c_find_if(i, cvec_i, vec, *i.ref > 2); -if (i.ref) printf("%d\n", *i.ref); - -// Erase all values > 2 in vec: -c_eraseremove_if(i, cvec_i, vec, *i.ref > 2); - -// Search map for a string containing "hello" and erase it: -cmap_str_iter it, it1 = ..., it2 = ...; -c_find_if(it, csmap_str, it1, it2, cstr_contains(it.ref, "hello")); -if (it.ref) cmap_str_erase_at(&map, it); - -// Erase all strings containing "hello" in a sorted map: -c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello")); -``` - -### sort_n_ - two times faster qsort - -The **sort_n**, **sort_ij** algorithm is about twice as fast as *qsort()*, and often simpler to use. -You may customize `i_tag` and the comparison function `i_cmp` or `i_less`. - -There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c). -```c -#define i_key int -#include -#include - -int main(void) { - int nums[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}; - intarray_sort_n(nums, c_arraylen(nums)); - c_forrange (i, c_arraylen(arr)) printf(" %d", arr[i]); -} -``` -Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is -possible and very fast. Note that `i_more` must be defined to retain specified template parameters for use by sort: -```c -#define i_type MyDeq -#define i_key int -#define i_more -#include // deque -#include -#include - -int main(void) { - MyDeq deq = c_init(MyDeq, {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}); - MyDeq_sort_n(&deq, MyDeq_size(&deq)); - c_foreach (i, MyDeq, deq) printf(" %d", *i.ref); - MyDeq_drop(&deq); -} -``` - -### c_new, c_delete - -- `c_new(Type, val)` - Allocate *and init* a new object on the heap -- `c_delete(Type, ptr)` - Drop *and free* an object allocated on the heap. NULL is OK. -```c -#include - -cstr *str_p = c_new(cstr, cstr_from("Hello")); -printf("%s\n", cstr_str(str_p)); -c_delete(cstr, str_p); -``` - -### c_malloc, c_calloc, c_realloc, c_free -Memory allocator wrappers that uses signed sizes. - -### c_arraylen -Return number of elements in an array. array must not be a pointer! -```c -int array[] = {1, 2, 3, 4}; -intptr_t n = c_arraylen(array); -``` - -### c_swap, c_const_cast -```c -// Safe macro for swapping internals of two objects of same type: -c_swap(cmap_int, &map1, &map2); - -// Type-safe casting a from const (pointer): -const char cs[] = "Hello"; -char* s = c_const_cast(char*, cs); // OK -int* ip = c_const_cast(int*, cs); // issues a warning! -``` - -### Predefined template parameter functions - -**crawstr** - Non-owned `const char*` "class" element type: `#define i_keyclass crawstr` -```c -typedef const char* crawstr; -int crawstr_cmp(const crawstr* x, const crawstr* y); -bool crawstr_eq(const crawstr* x, const crawstr* y); -uint64_t crawstr_hash(const crawstr* x); -``` -Default implementations -```c -int c_default_cmp(const Type*, const Type*); // <=> -bool c_default_less(const Type*, const Type*); // < -bool c_default_eq(const Type*, const Type*); // == -uint64_t c_default_hash(const Type*); -Type c_default_clone(Type val); // return val -Type c_default_toraw(const Type* p); // return *p -void c_default_drop(Type* p); // does nothing -``` - ---- -## Coroutines -This is a much improved implementation of -[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html), -which utilizes the *Duff's device* trick. Tatham's implementation is not typesafe, -and it always allocates the coroutine's internal state dynamically. But crucially, -it does not let the coroutine do self-cleanup on early finish - i.e. it -only frees the initial dynamically allocated memory. - -In this implementation, a coroutine may have any signature, but it should -take a struct pointer as parameter, which must contain the member `int cco_state;` -The struct should normally store all the *local* variables to be used in the -coroutine. It can also store input and output data if desired. - -The coroutine example below generates Pythagorian triples, but the calling loop -skips the triples which are upscaled version of smaller ones, by checking -the gcd() function. It also ensures that it stops when the diagonal size >= 100: - -[ [Run this code](https://godbolt.org/z/coqqrfbd5) ] -```c -#include -#include - -struct triples { - int n; // input: max number of triples to be generated. - int a, b, c; - int cco_state; // required member -}; - -int triples(struct triples* i) { // coroutine - cco_routine(i) { - for (i->c = 5; i->n; ++i->c) { - for (i->a = 1; i->a < i->c; ++i->a) { - for (i->b = i->a + 1; i->b < i->c; ++i->b) { - if ((int64_t)i->a*i->a + (int64_t)i->b*i->b == (int64_t)i->c*i->c) { - cco_yield(); - if (--i->n == 0) - cco_return; - } - } - } - } - cco_cleanup: - puts("done"); - } - return 0; -} - -int gcd(int a, int b) { // greatest common denominator - while (b) { - int t = a % b; - a = b; - b = t; - } - return a; -} - -int main(void) -{ - struct triples t = {.n=INT32_MAX}; - int n = 0; - - while (triples(&t)) { - // Skip triples with GCD(a,b) > 1 - if (gcd(t.a, t.b) > 1) - continue; - - // Stop when c >= 100 - if (t.c < 100) - printf("%d: [%d, %d, %d]\n", ++n, t.a, t.b, t.c); - else - cco_stop(&t); // cleanup in next coroutine call/resume - } -} -``` -### Coroutine API -To resume the coroutine from where it was suspended with *cco_yield()*: call the coroutine again. - -**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement from a -cco_routine scope; Use `if-else-if` constructs instead. - -| | Function / operator | Description | -|:----------|:-------------------------------------|:----------------------------------------| -|`cco_result` | `CCO_DONE`, `CCO_AWAIT`, `CCO_YIELD` | Default set of return values from coroutines | -| | `cco_cleanup:` | Label for cleanup position in coroutine | -| `bool` | `cco_done(co)` | Is coroutine done? | -| | `cco_routine(co) {}` | The coroutine scope | -| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)| -| | `cco_yield_v(ret);` | Yield/suspend execution (return ret) | -| | `cco_yield_final();` | Yield final suspend, enter cleanup-state | -| | `cco_yield_final(ret);` | Yield a final value | -| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| -| | `cco_call_await(cocall);` | Await for subcoro to finish (returns its ret value) | -| | `cco_call_await(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) | -| | `cco_return;` | Return from coroutine (inside cco_routine) | -| | Task objects: | | -| | `cco_task_struct(Name, ...);` | Define a coroutine task struct | -| | `cco_task_await(task, cco_runtime* rt);`| Await for task to finish | -| | `cco_task_await(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) | -|`cco_result`| `cco_task_resume(task, rt);` | Resume suspended task | -| | Semaphores: | | -| | `cco_sem` | Semaphore type | -| `cco_sem` | `cco_sem_from(long value)` | Create semaphore | -| | `cco_sem_set(sem, long value)` | Set semaphore value | -| | `cco_sem_await(sem)` | Await for the semaphore count > 0 | -| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | -| | Timers: | | -| | `cco_timer` | Timer type | -| | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)| -| | `cco_timer_start(tm, double sec)` | Start timer for secs duration | -| | `cco_timer_restart(tm)` | Restart timer with same duration | -| `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | -| `double` | `cco_timer_elapsed(tm)` | Return seconds elapsed | -| `double` | `cco_timer_remaining(tm)` | Return seconds remaining | -| | From caller side: | | -| `void` | `cco_stop(co)` | Next call of coroutine finalizes | -| `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_call_blocking(cocall) {}` | Run blocking until cocall is finished | -| `void` | `cco_call_blocking(cocall, int* outres) {}`| Run blocking until cocall is finished | -| | `cco_task_blocking(task) {}` | Run blocking until task is finished | -| | `cco_task_blocking(task, rt, STACKSZ) {}`| Run blocking until task is finished | -| | Time functions: | | -| `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | -| | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | - ---- -## RAII scope macros -General ***defer*** mechanics for resource acquisition. These macros allows you to specify the -freeing of the resources at the point where the acquisition takes place. -The **checkauto** utility described below, ensures that the `c_auto*` macros are used correctly. - -| Usage | Description | -|:---------------------------------------|:----------------------------------------------------------| -| `c_defer (drop...)` | Defer `drop...` to end of scope | -| `c_scope (init, drop)` | Execute `init` and defer `drop` to end of scope | -| `c_scope (init, pred, drop)` | Adds a predicate in order to exit early if init failed | -| `c_with (Type var=init, drop)` | Declare `var`. Defer `drop...` to end of scope | -| `c_with (Type var=init, pred, drop)` | Adds a predicate in order to exit early if init failed | -| `c_auto (Type, var1,...,var4)` | `c_with (Type var1=Type_init(), Type_drop(&var1))` ... | -| `continue` | Exit a defer-block without resource leak | - -```c -#include // or -... -// `c_defer` executes the expression(s) when leaving scope. -// Note: does not require inclusion of "raii.h". -cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); -c_defer (cstr_drop(&s1), cstr_drop(&s2)) -{ - printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); -} - -// `c_scope` syntactically "binds" initialization and defer. -static pthread_mutex_t mut; -c_scope (pthread_mutex_lock(&mut), pthread_mutex_unlock(&mut)) -{ - /* Do syncronized work. */ -} - -// `c_with` is similar to python `with`: declare a variable and defer the drop call. -c_with (cstr str = cstr_lit("Hello"), cstr_drop(&str)) -{ - cstr_append(&str, " world"); - printf("%s\n", cstr_str(&str)); -} - -// `c_auto` automatically initialize and drops up to 4 variables: -c_auto (cstr, s1, s2) -{ - cstr_append(&s1, "Hello"); - cstr_append(&s1, " world"); - cstr_append(&s2, "Cool"); - cstr_append(&s2, " stuff"); - printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); -} -``` -**Example 1**: Use multiple **c_with** in sequence: -```c -bool ok = false; -c_with (uint8_t* buf = malloc(BUF_SIZE), buf != NULL, free(buf)) -c_with (FILE* fp = fopen(fname, "rb"), fp != NULL, fclose(fp)) -{ - int n = fread(buf, 1, BUF_SIZE, fp); - if (n <= 0) continue; // auto cleanup! NB do not break or return here. - ... - ok = true; -} -return ok; -``` -**Example 2**: Load each line of a text file into a vector of strings: -```c -#include -#define i_implement -#include - -#define i_key_str -#include - -// receiver should check errno variable -cvec_str readFile(const char* name) -{ - cvec_str vec = {0}; // returned - c_with (FILE* fp = fopen(name, "r"), fp != NULL, fclose(fp)) - c_with (cstr line = {0}, cstr_drop(&line)) - while (cstr_getline(&line, fp)) - cvec_str_emplace(&vec, cstr_str(&line)); - return vec; -} - -int main(void) -{ - c_with (cvec_str vec = readFile(__FILE__), cvec_str_drop(&vec)) - c_foreach (i, cvec_str, vec) - printf("| %s\n", cstr_str(i.ref)); -} -``` - -### The **checkauto** utility program (for RAII) -The **checkauto** program will check the source code for any misuses of the `c_auto*` macros which -may lead to resource leakages. The `c_auto*`- macros are implemented as one-time executed **for-loops**, -so any `return` or `break` appearing within such a block will lead to resource leaks, as it will disable -the cleanup/drop method to be called. A `break` may originally be intended to break a loop or switch -outside the `c_auto` scope. - -NOTE: One must always make sure to unwind temporary allocated resources before a `return` in C. However, by using `c_auto*`-macros, -- it is much easier to automatically detect misplaced return/break between resource acquisition and destruction. -- it prevents forgetting to call the destructor at the end. - -The **checkauto** utility will report any misusages. The following example shows how to correctly break/return -from a `c_auto` scope: -```c -int flag = 0; -for (int i = 0; i 0) break; - ... -} -``` diff --git a/docs/cspan_api.md b/docs/cspan_api.md index e1c92bbf..1312ae6d 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -21,10 +21,11 @@ using_cspan4(S, ValueType); // define span types S, S2, S3, S4 with ``` ## Methods -All functions are type-safe. Note that the span argument itself is generally not side-effect safe, -i.e., it may be expanded multiple times. However, all index arguments are safe, e.g. -`cspan_at(&ms3, i++, j++, k++)` is allowed. If the number of arguments does not match the span rank, -a compile error is issued. Runtime bounds checks are enabled by default (define `STC_NDEBUG` or `NDEBUG` to disable). +All functions are type-safe. NOTE: the span argument itself is generally **not** side-effect safe - +it may be expanded multiple times. However, all index arguments are safe, e.g. +`cspan_at(&ms3, i++, j++, k++)` is safe, but `cspan_at(&spans[n++], i, j)` is an error! If the number +of arguments does not match the span rank, a compile error is issued. Runtime bounds checks are enabled +by default (define `STC_NDEBUG` or `NDEBUG` to disable). ```c SpanType cspan_init(TYPE SpanType, {v1, v2, ...}); // make a 1-d cspan from values SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from a cvec, cstack, cpque (heap) @@ -45,7 +46,7 @@ void SpanType_next(SpanTypeN_iter* it); SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // make a multi-dim cspan, row-major order. SpanTypeN cspan_md_order(char order, ValueType* data, d1, d2, ...); // order='C': row-major, 'F': column-major (FORTRAN). - // transpose a md span (inverse axes). no changes to the underlying array. + // transpose a md span (inverse axes). No changes to the underlying array. void cspan_transpose(const SpanTypeN* self); bool cspan_is_order_F(const SpanTypeN* self); -- cgit v1.2.3 From dd87a488eeeffa41a06757dda2220da21337a35e Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 23 Jul 2023 23:51:02 +0200 Subject: - algo/sort.h: Use plural form of i_key (or i_val) to define default name for sort, like: s_sort_n(data, n). - Updated some examples. --- include/stc/algo/sort.h | 2 +- misc/examples/coroutines/cotasks2.c | 35 ++++++++++------------ misc/examples/coroutines/triples.c | 51 +++++++++++++++++---------------- misc/examples/smartpointers/music_arc.c | 12 ++++---- 4 files changed, 49 insertions(+), 51 deletions(-) diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h index 06d7395f..86c9b9f1 100644 --- a/include/stc/algo/sort.h +++ b/include/stc/algo/sort.h @@ -70,7 +70,7 @@ int main(void) { #ifndef i_tag #define i_tag i_key #endif - #define i_type c_PASTE(i_tag, array) + #define i_type c_PASTE(i_tag, s) typedef i_key i_type; #endif #ifndef i_at diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c index 24a9f23f..4fdf98d9 100644 --- a/misc/examples/coroutines/cotasks2.c +++ b/misc/examples/coroutines/cotasks2.c @@ -42,18 +42,20 @@ int produce_items(struct produce_items* p, cco_runtime* rt) { cco_routine (p) { p->str = cstr_null; + p->next.cco_func = next_value; while (true) { - // await for next CCO_YIELD in next_value() + // await for next CCO_YIELD (or CCO_DONE) in next_value cco_task_await(&p->next, rt, CCO_YIELD); cstr_printf(&p->str, "item %d", p->next.val); print_time(); printf("produced %s\n", cstr_str(&p->str)); cco_yield(); } + cco_cleanup: - cstr_drop(&p->str); - puts("done produce"); + cstr_drop(&p->str); + puts("done produce"); } return 0; } @@ -68,6 +70,8 @@ cco_task_struct (consume_items, int consume_items(struct consume_items* c, cco_runtime* rt) { cco_routine (c) { + c->produce.cco_func = produce_items; + for (c->i = 1; c->i <= c->n; ++c->i) { printf("consume #%d\n", c->i); @@ -75,10 +79,11 @@ int consume_items(struct consume_items* c, cco_runtime* rt) print_time(); printf("consumed %s\n", cstr_str(&c->produce.str)); } + cco_cleanup: - cco_stop(&c->produce); - cco_task_resume(&c->produce, rt); - puts("done consume"); + cco_stop(&c->produce); + cco_task_resume(&c->produce, rt); + puts("done consume"); } return 0; } @@ -86,18 +91,8 @@ int consume_items(struct consume_items* c, cco_runtime* rt) int main(void) { struct consume_items consume = { - .n=5, - .cco_func=consume_items, - .produce={.cco_func=produce_items, .next={.cco_func=next_value}}, + .cco_func = consume_items, + .n = 5, }; - int count = 0; - - cco_task_blocking(&consume) - { - ++count; - //cco_sleep(0.001); - //if (consume.i == 3) - // cco_stop(&consume); - } - printf("count: %d\n", count); -} \ No newline at end of file + cco_task_blocking(&consume); +} diff --git a/misc/examples/coroutines/triples.c b/misc/examples/coroutines/triples.c index fe1ca7c3..9fd771ce 100644 --- a/misc/examples/coroutines/triples.c +++ b/misc/examples/coroutines/triples.c @@ -3,22 +3,14 @@ #include #include -int gcd(int a, int b) { - while (b) { - int t = a % b; - a = b; - b = t; - } - return a; -} - -void triples_vanilla(int n) { - for (int c = 5, i = 0; n; ++c) { +void triples_vanilla(int max_c) { + for (int c = 5, i = 0;; ++c) { for (int a = 1; a < c; ++a) { for (int b = a + 1; b < c; ++b) { - if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c && gcd(a, b) == 1) { + if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) { + if (c > max_c) + goto done; printf("%d: {%d, %d, %d}\n", ++i, a, b, c); - if (--n == 0) goto done; } } } @@ -27,19 +19,21 @@ void triples_vanilla(int n) { } struct triples { - int size, count; + int max_c; int a, b, c; int cco_state; }; int triples_coro(struct triples* t) { cco_routine(t) { - t->count = 0; - for (t->c = 5; t->size; ++t->c) { + for (t->c = 5;; ++t->c) { for (t->a = 1; t->a < t->c; ++t->a) { for (t->b = t->a + 1; t->b < t->c; ++t->b) { - if ((int64_t)t->a*t->a + (int64_t)t->b*t->b == (int64_t)t->c*t->c) { - if (t->count++ == t->size) + if ((int64_t)t->a * t->a + + (int64_t)t->b * t->b == + (int64_t)t->c * t->c) + { + if (t->c > t->max_c) cco_return; cco_yield(); } @@ -52,20 +46,29 @@ int triples_coro(struct triples* t) { return 0; } +int gcd(int a, int b) { + while (b) { + int t = a % b; + a = b; + b = t; + } + return a; +} + int main(void) { puts("Vanilla triples:"); - triples_vanilla(5); + triples_vanilla(20); - puts("\nCoroutine triples:"); - struct triples t = {.size=INT32_MAX}; + puts("\nCoroutine triples with GCD = 1:"); + struct triples t = {.max_c = 100}; int n = 0; - while (triples_coro(&t)) { + cco_call_blocking(triples_coro(&t)) { if (gcd(t.a, t.b) > 1) continue; - if (t.c < 100) - printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c); + if (++n <= 20) + printf("%d: {%d, %d, %d}\n", n, t.a, t.b, t.c); else cco_stop(&t); } diff --git a/misc/examples/smartpointers/music_arc.c b/misc/examples/smartpointers/music_arc.c index 16111b0b..13d368c3 100644 --- a/misc/examples/smartpointers/music_arc.c +++ b/misc/examples/smartpointers/music_arc.c @@ -12,7 +12,7 @@ typedef struct int Song_cmp(const Song* x, const Song* y) { return cstr_cmp(&x->title, &y->title); } -Song Song_make(const char* artist, const char* title) +Song Song_init(const char* artist, const char* title) { return c_LITERAL(Song){cstr_from(artist), cstr_from(title)}; } void Song_drop(Song* s) { @@ -34,9 +34,9 @@ void Song_drop(Song* s) { void example3(void) { SongVec vec1 = c_init(SongVec, { - Song_make("Bob Dylan", "The Times They Are A Changing"), - Song_make("Aretha Franklin", "Bridge Over Troubled Water"), - Song_make("Thalia", "Entre El Mar y Una Estrella") + Song_init("Bob Dylan", "The Times They Are A Changing"), + Song_init("Aretha Franklin", "Bridge Over Troubled Water"), + Song_init("Thalia", "Entre El Mar y Una Estrella") }); SongVec vec2 = {0}; @@ -47,8 +47,8 @@ void example3(void) // Add a few more to vec2. We can use emplace when creating new entries // Emplace calls SongArc_from() on the argument to create the Arc: - SongVec_emplace(&vec2, Song_make("Michael Jackson", "Billie Jean")); - SongVec_emplace(&vec2, Song_make("Rihanna", "Stay")); + SongVec_emplace(&vec2, Song_init("Michael Jackson", "Billie Jean")); + SongVec_emplace(&vec2, Song_init("Rihanna", "Stay")); // We now have two vectors with some shared, some unique entries. c_forlist (i, SongVec, {vec1, vec2}) { -- cgit v1.2.3 From e4c169a66c3d55a4d0d3407f47102e54d289a3fb Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 24 Jul 2023 07:59:17 +0200 Subject: Updated godbolt links to working v4.3 examples. Added missing files. --- README.md | 2 +- docs/coroutine_api.md | 292 ++++++++++++++++++++++++++++++++++++ docs/csmap_api.md | 2 +- docs/pics/Figure_1.png | Bin 0 -> 58425 bytes docs/pics/coroutine.jpg | Bin 0 -> 81539 bytes misc/examples/coroutines/filetask.c | 80 ++++++++++ 6 files changed, 374 insertions(+), 2 deletions(-) create mode 100644 docs/coroutine_api.md create mode 100644 docs/pics/Figure_1.png create mode 100644 docs/pics/coroutine.jpg create mode 100644 misc/examples/coroutines/filetask.c diff --git a/README.md b/README.md index 6351fc07..55c77ca4 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,7 @@ int main(void) ``` This example uses four different container types: -[ [Run this code](https://godbolt.org/z/x5YKeMrEh) ] +[ [Run this code](https://godbolt.org/z/qor16Gf6j) ] ```c #include diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md new file mode 100644 index 00000000..30b85640 --- /dev/null +++ b/docs/coroutine_api.md @@ -0,0 +1,292 @@ +# STC [coroutine](../include/stc/coroutine.h): Coroutines +![Coroutine](pics/coroutine.jpg) + +An implementation of stackless coroutines, which are lightweight threads, providing a blocking +context cheaply using little memory per coroutine. + +Coroutines are used to accomplish a non-preempted form of concurrency known as cooperative multitasking and, therefore, do not incur context switching when yielding to another thread. Within a coroutine, **yield** and **await** is accomplished by utilizing Duff's device within a thread's function and an external variable used in within the switch statement. This allows jumping (resuming) from a yield upon another function call. In order to block threads, these yields may be guarded by a conditional so that successive calls to the same function will yield unless the guard conditional is true. + +Because these coroutines are stackless, local variables within the coroutine where usage crosses `cco_yield` or `cco_await` must be stored in a struct which is passed as pointer to the coroutine. This has the advantages that they become very lightweight and therefore useful on severely memory constrained systems like small microcontrollers where other solutions are impractical or less desirable. + +### Coroutine API + +NB! ***cco_yield\*()*** / ***cco_await\*()*** may not be called from within a `switch` statement in a +`cco_routine` scope; Use `if-else-if` constructs instead. + +| | Function / operator | Description | +|:----------|:-------------------------------------|:----------------------------------------| +|`cco_result` | `CCO_DONE`, `CCO_AWAIT`, `CCO_YIELD` | Default set of return values from coroutines | +| | `cco_cleanup:` | Label for cleanup position in coroutine | +| `bool` | `cco_done(co)` | Is coroutine done? | +| | `cco_routine(co) {}` | The coroutine scope | +| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)| +| | `cco_yield_v(ret);` | Yield/suspend execution (return ret) | +| | `cco_yield_final();` | Yield final suspend, enter cleanup-state | +| | `cco_yield_final(ret);` | Yield a final value | +| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| +| | `cco_call_await(cocall);` | Await for subcoro to finish (returns its ret value) | +| | `cco_call_await(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) | +| | `cco_return;` | Return from coroutine (inside cco_routine) | +| | Task objects: | | +| | `cco_task_struct(Name, ...);` | Define a coroutine task struct | +| | `cco_task_await(task, cco_runtime* rt);`| Await for task to finish | +| | `cco_task_await(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) | +|`cco_result`| `cco_task_resume(task, rt);` | Resume suspended task | +| | Semaphores: | | +| | `cco_sem` | Semaphore type | +| `cco_sem` | `cco_sem_from(long value)` | Create semaphore | +| | `cco_sem_set(sem, long value)` | Set semaphore value | +| | `cco_sem_await(sem)` | Await for the semaphore count > 0 | +| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | +| | Timers: | | +| | `cco_timer` | Timer type | +| | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)| +| | `cco_timer_start(tm, double sec)` | Start timer for secs duration | +| | `cco_timer_restart(tm)` | Restart timer with same duration | +| `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | +| `double` | `cco_timer_elapsed(tm)` | Return seconds elapsed | +| `double` | `cco_timer_remaining(tm)` | Return seconds remaining | +| | From caller side: | | +| `void` | `cco_stop(co)` | Next call of coroutine finalizes | +| `void` | `cco_reset(co)` | Reset state to initial (for reuse) | +| `void` | `cco_call_blocking(cocall) {}` | Run blocking until cocall is finished | +| `void` | `cco_call_blocking(cocall, int* outres) {}`| Run blocking until cocall is finished | +| | `cco_task_blocking(task) {}` | Run blocking until task is finished | +| | `cco_task_blocking(task, rt, STACKSZ) {}`| Run blocking until task is finished | +| | Time functions: | | +| `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | +| | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | + + +## Implementation and examples + +This small implementation of coroutines is inspired by +[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html) and +[Adam Dunkel's photothreads](https://dunkels.com/adam/pt), but provides big improvements regarding +ergonomics, features, and type-safety. Crucially, it also allows coroutines to self-cleanup when +cancelled (not resumed until they are done). + +A coroutine function may have almost any signature, but the implementation adds support for +coroutines which returns an int, indicating CCO_DONE, CCO_AWAIT, or CCO_YIELD. It should also +take a struct pointer as parameter which must contains the member `int cco_state`. The struct should +normally store all *local* variables to be used within the coroutine, along with *input* and *output* data +for the coroutine. + +Note that this implementation is not limited to support a certain set of coroutine types, +like generators. It can even operate like stackfull coroutines, i.e. you can efficiently +yield or await from a (deeply) nested coroutine call using cco_task objects described later. + +The first example is a generator of Pythagorian triples, and stops when diagonal size > max_c. + +[ [Run this code](https://godbolt.org/z/3Efn17cP6) ] +```c +#include +#include +#include +// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ + +struct triples { + int max_c; // input: max c. + int a, b, c; // output + int cco_state; // required member +}; + +int triples(struct triples* i) { + cco_routine(i) { // the coroutine scope! + for (i->c = 5;; ++i->c) { + for (i->a = 1; i->a < i->c; ++i->a) { + for (i->b = i->a + 1; i->b < i->c; ++i->b) { + if ((int64_t)i->a * i->a + + (int64_t)i->b * i->b == + (int64_t)i->c * i->c) + { + if (i->c > i->max_c) + cco_return; // "jump" to cco_cleanup if defined, else exit scope. + cco_yield(); + } + } + } + } + cco_cleanup: + puts("done"); + } + return 0; // CCO_DONE +} + +int main(void) { + struct triples co = {.max_c = 25}; + int n = 0; + + cco_call_blocking(triples(&co)) { + printf("%d: [%d, %d, %d]\n", ++n, co.a, co.b, co.c); + } +} +``` +The next variant skips the triples which are upscaled version of smaller ones by checking +the gcd() function. Note that the gcd1_triples struct contains the triples struct so that +both functions have separate call frames: + +[ [Run this code](https://godbolt.org/z/ndhMq1haj) ] +```c +int gcd(int a, int b) { // greatest common denominator + while (b) { + int t = a % b; + a = b; + b = t; + } + return a; +} + +struct gcd1_triples { + int max_n, max_c, count; // input: max_n, max_c limit #triples to be generated. + struct triples tri; // triples call frame + int cco_state; +}; + +int gcd1_triples(struct gcd1_triples* i) +{ + cco_routine(i) { + cco_reset(&i->tri); + i->tri.max_c = i->max_c; + + while (triples(&i->tri) != CCO_DONE) { + // Skip triples with GCD(a,b) > 1 + if (gcd(i->tri.a, i->tri.b) > 1) + continue; + + // Done when count > max_n + if (++i->count > i->max_n) + cco_return; + else + cco_yield(); + } + cco_cleanup: + cco_stop(&i->tri); // to cleanup state if still active + triples(&i->tri); // do cleanup (or no-op if done) + } + return 0; +} + +int main(void) { + struct gcd1_triples co = {.max_n = 100, .max_c = 100}; + int n = 0; + + cco_call_blocking(gcd1_triples(&co)) { + printf("%d: [%d, %d, %d]\n", ++n, co.tri.a, co.tri.b, co.tri.c); + } +} +``` +When using ***cco_call_blocking()***, the coroutine is continuously resumed after each yield suspension. +However, this means that it first calls ***gcd1_triples()***, which immediately jumps to after the `cco_yield` +-statement and calls ***triples()***, which again jumps and resumes after its `cco_yield`-statement. This +is efficient only when yielding or awaiting from the top- or second-level call like here, but naturally not +when couroutine calls are more deeply nested or recursive. + +The STC coroutine implementation therefore also contains task-objects (`cco_task`), which are base-coroutine +objects/enclosures. These can be executed using ***cco_task_blocking()*** instead of ***cco_call_blocking()***. +Inner coroutine calls are done by ***cco_task_await()***, where you may await for a certain return value, normally CCO_YIELD or just CCO_DONE. It uses a stack of pointers of task-enclosures to call the current +inner-level function directly. The task-objects have the added benefit that coroutines can be managed +by a scheduler, which is useful when dealing with large numbers of coroutines (like in many games and +simulations). + +Note that these two modes may be mixed, and that for short-lived coroutines (only a few suspends), +it is often beneficial to call the sub-coroutine directly rather than via ***cco_task_await()*** +(which pushes the task on top of the runtime stack and yields - then executed on next resume). + +The following example uses task-objects with 3-levels deep coroutine calls. It emulates an async generator +by awaiting a few seconds before producing a number, using a timer. +```c +// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/ +#include +#include +#define i_static +#include +#include + +cco_task_struct (next_value, + int val; + cco_timer tm; +); + +int next_value(struct next_value* co, cco_runtime* rt) +{ + cco_routine (co) { + while (true) { + cco_timer_await(&co->tm, 1 + rand() % 2); // suspend with CCO_AWAIT + co->val = rand(); + cco_yield(); // suspend with CCO_YIELD + } + } + return 0; +} + +void print_time() +{ + time_t now = time(NULL); + char mbstr[64]; + strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now)); + printf("%s ", mbstr); +} + +// PRODUCER +cco_task_struct (produce_items, + struct next_value next; + cstr str; +); + +int produce_items(struct produce_items* p, cco_runtime* rt) +{ + cco_routine (p) { + p->str = cstr_null; + p->next.cco_func = next_value; + while (true) + { + // await for CCO_YIELD (or CCO_DONE) + cco_task_await(&p->next, rt, CCO_YIELD); + cstr_printf(&p->str, "item %d", p->next.val); + print_time(); + printf("produced %s\n", cstr_str(&p->str)); + cco_yield(); + } + cco_cleanup: + cstr_drop(&p->str); + puts("done produce"); + } + return 0; +} + +// CONSUMER +cco_task_struct (consume_items, + int n, i; + struct produce_items produce; +); + +int consume_items(struct consume_items* c, cco_runtime* rt) +{ + cco_routine (c) { + c->produce.cco_func = produce_items; + + for (c->i = 1; c->i <= c->n; ++c->i) + { + printf("consume #%d\n", c->i); + cco_task_await(&c->produce, rt, CCO_YIELD); + print_time(); + printf("consumed %s\n", cstr_str(&c->produce.str)); + } + cco_cleanup: + cco_stop(&c->produce); + cco_task_resume(&c->produce, rt); + puts("done consume"); + } + return 0; +} + +int main(void) +{ + struct consume_items consume = { + .n = 5, + .cco_func = consume_items, + }; + cco_task_blocking(&consume); +} +``` \ No newline at end of file diff --git a/docs/csmap_api.md b/docs/csmap_api.md index afaf49f3..164b0f8a 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -148,7 +148,7 @@ Translate a [C++ example using *insert* and *emplace*](https://en.cppreference.com/w/cpp/container/map/try_emplace) to STC: -[ [Run this code](https://godbolt.org/z/9d1PP77Pa) ] +[ [Run this code](https://godbolt.org/z/b46W5Ezrb) ] ```c #define i_implement #include diff --git a/docs/pics/Figure_1.png b/docs/pics/Figure_1.png new file mode 100644 index 00000000..263303d2 Binary files /dev/null and b/docs/pics/Figure_1.png differ diff --git a/docs/pics/coroutine.jpg b/docs/pics/coroutine.jpg new file mode 100644 index 00000000..e5fceab3 Binary files /dev/null and b/docs/pics/coroutine.jpg differ diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c new file mode 100644 index 00000000..bfce7810 --- /dev/null +++ b/misc/examples/coroutines/filetask.c @@ -0,0 +1,80 @@ +// https://github.com/lewissbaker/cppcoro#taskt + +#include +#include +#define i_static +#include +#include + +cco_task_struct(file_read, + const char* path; + cstr line; + FILE* fp; + cco_timer tm; +); + +int file_read(struct file_read* co, cco_runtime* rt) +{ + cco_routine (co) { + co->fp = fopen(co->path, "r"); + co->line = cstr_null; + + while (true) { + // emulate async io: await 10ms per line + cco_timer_await(&co->tm, 0.003); + + if (!cstr_getline(&co->line, co->fp)) + break; + cco_yield(); + } + + cco_cleanup: + fclose(co->fp); + cstr_drop(&co->line); + puts("done file_read"); + } + return 0; +} + +cco_task_struct(count_line, + cstr path; + struct file_read reader; + int lineCount; +); + +int count_line(struct count_line* co, cco_runtime* rt) +{ + cco_routine (co) { + co->reader.cco_func = file_read; + co->reader.path = cstr_str(&co->path); + while (true) + { + // await for next CCO_YIELD (or CCO_DONE) in file_read() + cco_task_await(&co->reader, rt, CCO_YIELD); + if (rt->result == CCO_DONE) break; + co->lineCount += 1; + cco_yield(); + } + + cco_cleanup: + cstr_drop(&co->path); + puts("done count_line"); + } + return 0; +} + +int main(void) +{ + // Creates a new task + struct count_line countTask = { + .cco_func = count_line, + .path = cstr_from(__FILE__), + }; + + // Execute coroutine as top-level blocking + int loop = 0; + cco_task_blocking(&countTask) { ++loop; } + + printf("line count = %d\n", countTask.lineCount); + printf("exec count = %d\n", loop); +} -- cgit v1.2.3 From 650b053f443f9132dadb6d1ca924c0b36849739f Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 24 Jul 2023 08:41:55 +0200 Subject: Fix for: Merge branch 'master' into dev43 --- misc/examples/algorithms/random.c | 10 +++++----- misc/examples/bitsets/prime.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/misc/examples/algorithms/random.c b/misc/examples/algorithms/random.c index fd904b0f..9522c16d 100644 --- a/misc/examples/algorithms/random.c +++ b/misc/examples/algorithms/random.c @@ -4,7 +4,7 @@ int main(void) { - const int N = 10000000; + const long long N = 10000000; const uint64_t seed = (uint64_t)time(NULL), range = 1000000; crand_t rng = crand_init(seed); @@ -19,7 +19,7 @@ int main(void) } diff = clock() - before; printf("full range\t\t: %f secs, %lld, avg: %f\n", - (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N)); + (double)diff/(double)CLOCKS_PER_SEC, N, (double)(sum/N)); crand_uniform_t dist1 = crand_uniform_init(0, range); rng = crand_init(seed); @@ -29,8 +29,8 @@ int main(void) sum += crand_uniform(&rng, &dist1); // unbiased } diff = clock() - before; - printf("unbiased 0-%" PRIu64 "\t: %f secs, %lld, avg: %f\n", - range, (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N)); + printf("unbiased 0-%lld\t: %f secs, %lld, avg: %f\n", + (long long)range, (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N)); sum = 0; rng = crand_init(seed); @@ -40,6 +40,6 @@ int main(void) } diff = clock() - before; printf("biased 0-%" PRIu64 " \t: %f secs, %lld, avg: %f\n", - range, (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N)); + (long long)range, (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N)); } diff --git a/misc/examples/bitsets/prime.c b/misc/examples/bitsets/prime.c index 8216e332..7e5a2b3f 100644 --- a/misc/examples/bitsets/prime.c +++ b/misc/examples/bitsets/prime.c @@ -35,7 +35,7 @@ int main(void) llong np = cbits_count(&primes); t = clock() - t; - printf("Number of primes: %lld, time: %f\n\n", np, (float)t / (float)CLOCKS_PER_SEC); + printf("Number of primes: %lld, time: %f\n\n", np, (double)t/CLOCKS_PER_SEC); puts("Show all the primes in the range [2, 1000):"); printf("2"); -- cgit v1.2.3 From 4a37879119cd4d8b92c5dc578741052dd399f53f Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 24 Jul 2023 09:12:26 +0200 Subject: Updated docs, fix for issue #64. --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 55c77ca4..c28e5773 100644 --- a/README.md +++ b/README.md @@ -532,17 +532,22 @@ MyVec_push_back(&vec, 1); It is possible to forward declare containers. This is useful when a container is part of a struct, but still not expose or include the full implementation / API of the container. ```c -// Header file +// Dataset.h #include // only include data structures -forward_cstack(cstack_pnt, struct Point); // declare cstack_pnt (and cstack_pnt_value, cstack_pnt_iter); - // struct Point may be an incomplete type. + +// declare cstack_pnt; struct Point may be an incomplete type. +forward_cstack(cstack_pnt, struct Point); typedef struct Dataset { cstack_pnt vertices; cstack_pnt colors; } Dataset; -// Implementation -#define i_is_forward // flag that the container was forward declared. +... +// Dataset.c +#include "Dataset.h" + +struct Point { int x, y, z; }; // Point must be defined here. +#define i_is_forward // flag that the container was forward declared. #define i_key struct Point #define i_tag pnt #include -- cgit v1.2.3 From f1f0c01e798eb3217e62a43de660723173984547 Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 24 Jul 2023 12:54:09 +0200 Subject: Improved an issue with cspan. --- docs/cspan_api.md | 10 ++++++++++ include/stc/cspan.h | 18 +++++++++++------- misc/examples/spans/printspan.c | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 1312ae6d..51d72856 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -29,6 +29,7 @@ by default (define `STC_NDEBUG` or `NDEBUG` to disable). ```c SpanType cspan_init(TYPE SpanType, {v1, v2, ...}); // make a 1-d cspan from values SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from a cvec, cstack, cpque (heap) +SpanType cspan_from_n(ValueType* ptr, intptr_t n); // make a 1-d cspan from a pointer and length SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from a C array intptr_t cspan_size(const SpanTypeN* self); // return number of elements @@ -144,6 +145,7 @@ Slicing cspan without and with reducing the rank: ```c #define i_implement #include +#include #include using_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3 @@ -164,6 +166,14 @@ int main(void) fmt_print(" {}", *i.ref); puts(""); + // create span on-the-fly + int array[] = {3, 65, 4, 3, 7, 87, 45}; + c_forfilter (i, ISpan, (ISpan)cspan_from_array(array), + c_flt_skip(i, 2) && + c_flt_take(i, 3)) + fmt_print(" {}", *i.ref); + puts(""); + // slice without reducing rank: Span3 ss3 = cspan_slice(Span3, &span3, {c_ALL}, {3,4}, {c_ALL}); diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 08045010..1b57d4d4 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -26,7 +26,7 @@ #include #include using_cspan(Span2f, float, 2); -using_cspan(Intspan, int, 1); +using_cspan(Intspan, int); int demo1() { float raw[4*5]; @@ -65,7 +65,11 @@ int demo2() { #define using_cspan(...) c_MACRO_OVERLOAD(using_cspan, __VA_ARGS__) #define using_cspan_2(Self, T) \ - using_cspan_3(Self, T, 1) + using_cspan_3(Self, T, 1); \ + STC_INLINE Self Self##_from_n(Self##_raw* raw, const intptr_t n) { \ + return (Self){.data=raw, .shape={(int32_t)n}, .stride={.d={1}}}; \ + } \ + struct stc_nostruct #define using_cspan_3(Self, T, RANK) \ typedef T Self##_value; typedef T Self##_raw; \ @@ -77,9 +81,6 @@ int demo2() { \ typedef struct { Self##_value *ref; int32_t pos[RANK]; const Self *_s; } Self##_iter; \ \ - STC_INLINE Self Self##_from_n(Self##_raw* raw, const intptr_t n) { \ - return (Self){.data=raw, .shape={(int32_t)n}}; \ - } \ STC_INLINE Self Self##_slice_(Self##_value* d, const int32_t shape[], const int32_t stri[], \ const int rank, const int32_t a[][2]) { \ Self s; int outrank; \ @@ -104,7 +105,7 @@ int demo2() { } \ struct stc_nostruct -#define using_cspan2(Self, T) using_cspan_3(Self, T, 1); using_cspan_3(Self##2, T, 2) +#define using_cspan2(Self, T) using_cspan_2(Self, T); using_cspan_3(Self##2, T, 2) #define using_cspan3(Self, T) using_cspan2(Self, T); using_cspan_3(Self##3, T, 3) #define using_cspan4(Self, T) using_cspan3(Self, T); using_cspan_3(Self##4, T, 4) #define using_cspan_tuple(N) typedef struct { int32_t d[N]; } cspan_tuple##N @@ -124,8 +125,11 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define cspan_from(container) \ {.data=(container)->data, .shape={(int32_t)(container)->_len}, .stride={.d={1}}} +#define cspan_from_n(ptr, n) \ + {.data=(ptr), .shape={n}, .stride={.d={1}}} + #define cspan_from_array(array) \ - {.data=(array), .shape={c_arraylen(array)}, .stride={.d={1}}} + cspan_from_n(array, c_arraylen(array)) #define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) #define cspan_rank(self) c_arraylen((self)->shape) diff --git a/misc/examples/spans/printspan.c b/misc/examples/spans/printspan.c index cd3c5f4f..eb9d80e3 100644 --- a/misc/examples/spans/printspan.c +++ b/misc/examples/spans/printspan.c @@ -11,7 +11,7 @@ #include #include -using_cspan(intspan, int, 1); +using_cspan(intspan, int); void printMe(intspan container) { printf("%d:", (int)cspan_size(&container)); -- cgit v1.2.3 From 78ba677b59a8cecd69f733fca1a37ad01b38320f Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 24 Jul 2023 22:57:44 +0200 Subject: Updated and fixed benchmarks and performance graphs. --- docs/pics/Figure_1.png | Bin 58425 -> 60722 bytes include/stc/cstack.h | 2 +- include/stc/cvec.h | 2 +- misc/benchmarks/plotbench/cdeq_benchmark.cpp | 15 ++++++--------- misc/benchmarks/plotbench/clist_benchmark.cpp | 8 +++----- misc/benchmarks/plotbench/cmap_benchmark.cpp | 8 +++++--- misc/benchmarks/plotbench/cpque_benchmark.cpp | 3 ++- misc/benchmarks/plotbench/csmap_benchmark.cpp | 8 +++++--- misc/benchmarks/plotbench/cvec_benchmark.cpp | 15 ++++++--------- misc/benchmarks/plotbench/plot.py | 7 +++---- 10 files changed, 32 insertions(+), 36 deletions(-) diff --git a/docs/pics/Figure_1.png b/docs/pics/Figure_1.png index 263303d2..46a1478f 100644 Binary files a/docs/pics/Figure_1.png and b/docs/pics/Figure_1.png differ diff --git a/include/stc/cstack.h b/include/stc/cstack.h index f8640ed1..8fb176e1 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -103,7 +103,7 @@ STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t n) { STC_INLINE _cx_value* _cx_MEMB(_append_uninit)(_cx_Self *self, intptr_t n) { intptr_t len = self->_len; - if (!_cx_MEMB(_reserve)(self, len + n)) return NULL; + if (!_cx_MEMB(_reserve)(self, len*3/2 + n)) return NULL; self->_len += n; return self->data + len; } diff --git a/include/stc/cvec.h b/include/stc/cvec.h index d08e382f..774f0582 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -316,7 +316,7 @@ _cx_MEMB(_resize)(_cx_Self* self, const intptr_t len, i_key null) { STC_DEF _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value) { if (self->_len == self->_cap) - if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + 4)) + if (!_cx_MEMB(_reserve)(self, self->_len*2 + 4)) return NULL; _cx_value *v = self->data + self->_len++; *v = value; diff --git a/misc/benchmarks/plotbench/cdeq_benchmark.cpp b/misc/benchmarks/plotbench/cdeq_benchmark.cpp index 54d7305b..d11b4103 100644 --- a/misc/benchmarks/plotbench/cdeq_benchmark.cpp +++ b/misc/benchmarks/plotbench/cdeq_benchmark.cpp @@ -9,10 +9,10 @@ #endif enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; -const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; +const char* operations[] = {"insert", "erase", "access", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 60000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 60000000, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } @@ -44,14 +44,12 @@ Sample test_std_deque() { c_forrange (N) con.push_back(crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; - // Iteration - not inherent find - skipping - //container::iterator it; - //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it; + c_forrange (R) c_forrange (i, N) sum += con[i]; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); sum = 0; - c_forrange (R) c_forrange (i, N) sum += con[i]; + c_forrange (R) for (const auto i: con) sum += i; s.test[ITER].t2 = clock(); s.test[ITER].sum = sum; s.test[DESTRUCT].t1 = clock(); @@ -89,13 +87,12 @@ Sample test_stc_deque() { c_forrange (N) cdeq_x_push_back(&con, crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; - //cdeq_x_iter it, end = cdeq_x_end(&con); - //c_forrange (S) if ((it = cdeq_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref; + c_forrange (R) c_forrange (i, N) sum += *cdeq_x_at(&con, i); s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); sum = 0; - c_forrange (R) c_forrange (i, N) sum += con.data[i]; + c_forrange (R) c_foreach (i, cdeq_x, con) sum += *i.ref; s.test[ITER].t2 = clock(); s.test[ITER].sum = sum; s.test[DESTRUCT].t1 = clock(); diff --git a/misc/benchmarks/plotbench/clist_benchmark.cpp b/misc/benchmarks/plotbench/clist_benchmark.cpp index 01bfbf83..8fdfddba 100644 --- a/misc/benchmarks/plotbench/clist_benchmark.cpp +++ b/misc/benchmarks/plotbench/clist_benchmark.cpp @@ -9,10 +9,10 @@ #endif enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; -const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; +const char* operations[] = {"insert", "erase", "access", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 10000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 10000000, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } @@ -45,7 +45,6 @@ Sample test_std_forward_list() { size_t sum = 0; container::iterator it; // Iteration - not inherent find - skipping - //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); @@ -86,8 +85,7 @@ Sample test_stc_forward_list() { c_forrange (N) clist_x_push_front(&con, crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; - //clist_x_iter it, end = clist_x_end(&con); - //c_forrange (S) if ((it = clist_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref; + //clist iteration - skipping s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); diff --git a/misc/benchmarks/plotbench/cmap_benchmark.cpp b/misc/benchmarks/plotbench/cmap_benchmark.cpp index 6b2edbd7..c7957bb7 100644 --- a/misc/benchmarks/plotbench/cmap_benchmark.cpp +++ b/misc/benchmarks/plotbench/cmap_benchmark.cpp @@ -8,7 +8,7 @@ #endif enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; -const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; +const char* operations[] = {"insert", "erase", "access", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; enum {SAMPLES = 2, N = 2000000, R = 4}; @@ -47,12 +47,14 @@ Sample test_std_unordered_map() { s.test[FIND].t1 = clock(); size_t sum = 0; container::iterator it; - c_forrange (N) if ((it = con.find(crand() & mask1)) != con.end()) sum += it->second; + c_forrange (N) + if ((it = con.find(crand() & mask1)) != con.end()) + sum += it->second; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); sum = 0; - c_forrange (R) for (auto i: con) sum += i.second; + c_forrange (R) for (const auto& i: con) sum += i.second; s.test[ITER].t2 = clock(); s.test[ITER].sum = sum; s.test[DESTRUCT].t1 = clock(); diff --git a/misc/benchmarks/plotbench/cpque_benchmark.cpp b/misc/benchmarks/plotbench/cpque_benchmark.cpp index 6c62ae3e..aafc9eb0 100644 --- a/misc/benchmarks/plotbench/cpque_benchmark.cpp +++ b/misc/benchmarks/plotbench/cpque_benchmark.cpp @@ -37,7 +37,8 @@ void stc_test() { int N = 10000000; - c_auto (cpque_f, pq) + cpque_f pq = {0}; + c_defer(cpque_f_drop(&pq)) { csrand(seed); clock_t start = clock(); diff --git a/misc/benchmarks/plotbench/csmap_benchmark.cpp b/misc/benchmarks/plotbench/csmap_benchmark.cpp index 60f2db49..480163ed 100644 --- a/misc/benchmarks/plotbench/csmap_benchmark.cpp +++ b/misc/benchmarks/plotbench/csmap_benchmark.cpp @@ -8,7 +8,7 @@ #endif enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; -const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; +const char* operations[] = {"insert", "erase", "access", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; enum {SAMPLES = 2, N = 1000000, R = 4}; @@ -47,12 +47,14 @@ Sample test_std_map() { s.test[FIND].t1 = clock(); size_t sum = 0; container::iterator it; - c_forrange (N) if ((it = con.find(crand() & mask1)) != con.end()) sum += it->second; + c_forrange (N) + if ((it = con.find(crand() & mask1)) != con.end()) + sum += it->second; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); sum = 0; - c_forrange (R) for (auto i: con) sum += i.second; + c_forrange (R) for (const auto& i: con) sum += i.second; s.test[ITER].t2 = clock(); s.test[ITER].sum = sum; s.test[DESTRUCT].t1 = clock(); diff --git a/misc/benchmarks/plotbench/cvec_benchmark.cpp b/misc/benchmarks/plotbench/cvec_benchmark.cpp index 45b9cf93..fb10653a 100644 --- a/misc/benchmarks/plotbench/cvec_benchmark.cpp +++ b/misc/benchmarks/plotbench/cvec_benchmark.cpp @@ -9,10 +9,10 @@ #endif enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; -const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; +const char* operations[] = {"insert", "erase", "access", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 40000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 60000000, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } @@ -42,14 +42,12 @@ Sample test_std_vector() { c_forrange (N) con.push_back(crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; - //container::iterator it; - // Iteration - not inherent find - skipping - //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it; + c_forrange (R) c_forrange (i, N) sum += con[i]; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); sum = 0; - c_forrange (R) c_forrange (i, N) sum += con[i]; + c_forrange (R) for (const auto i: con) sum += i; s.test[ITER].t2 = clock(); s.test[ITER].sum = sum; s.test[DESTRUCT].t1 = clock(); @@ -85,13 +83,12 @@ Sample test_stc_vector() { c_forrange (N) cvec_x_push(&con, crand() & mask2); s.test[FIND].t1 = clock(); size_t sum = 0; - //cvec_x_iter it, end = cvec_x_end(&con); - //c_forrange (S) if ((it = cvec_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref; + c_forrange (R) c_forrange (i, N) sum += con.data[i]; s.test[FIND].t2 = clock(); s.test[FIND].sum = sum; s.test[ITER].t1 = clock(); sum = 0; - c_forrange (R) c_forrange (i, N) sum += con.data[i]; + c_forrange (R) c_foreach (i, cvec_x, con) sum += *i.ref; s.test[ITER].t2 = clock(); s.test[ITER].sum = sum; s.test[DESTRUCT].t1 = clock(); diff --git a/misc/benchmarks/plotbench/plot.py b/misc/benchmarks/plotbench/plot.py index 8e684ccc..4a02c6b2 100644 --- a/misc/benchmarks/plotbench/plot.py +++ b/misc/benchmarks/plotbench/plot.py @@ -13,12 +13,11 @@ if n > 0: df = df[df.Compiler == comp[n]] g = sns.catplot(data=df, x='Method', y='Seconds', hue='Library', col='C', kind='bar', orient='v', - errorbar=('ci', 68), legend=False, col_wrap=2, sharex=False, aspect=1.4, height=3.1) + errorbar=('ci', 68), legend=False, col_wrap=2, sharex=False, aspect=1.4, height=3.0) g.set_xlabels('') -g.add_legend(bbox_to_anchor=(0.75, 0.2), borderaxespad=0.) - -g.fig.subplots_adjust(top=0.90, left=0.06, bottom=0.07) +g.add_legend(bbox_to_anchor=(0.75, 0.2), borderaxespad=0) +g.fig.subplots_adjust(top=0.90, left=0.08, right=0.98, bottom=0.04, hspace=0.4) g.fig.suptitle('Benchmark STC vs c++ std containers: %s' % comp[n], fontsize=15, y=0.98) plt.show() -- cgit v1.2.3 From 5b54b0ca26540dd116880f316c6fa0291a7c96c7 Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 24 Jul 2023 23:44:53 +0200 Subject: Made it a pre-release 4.3 --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c28e5773..9b6698e5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ STC - Smart Template Containers =============================== -### [Version 4.3 Released](#version-history) +### [Version 4.3 Pre-release](#version-history) - See details for breaking changes. --- Description @@ -107,8 +107,8 @@ Benchmark notes: - The barchart shows average test times over three compilers: **Mingw64 13.1.0, Win-Clang 16.0.5, VC-19-36**. CPU: **Ryzen 7 5700X**. - Containers uses value types `uint64_t` and pairs of `uint64_t` for the maps. - Black bars indicates performance variation between various platforms/compilers. -- Iterations are repeated 4 times over n elements. -- **find()**: not executed for *forward_list*, *deque*, and *vector* because these c++ containers does not have native *find()*. +- Iterations and access are repeated 4 times over n elements. +- access: no entryfor *forward_list*, *deque*, and *vector* because these c++ containers does not have native *find()*. - **deque**: *insert*: n/3 push_front(), n/3 push_back()+pop_front(), n/3 push_back(). - **map and unordered map**: *insert*: n/2 random numbers, n/2 sequential numbers. *erase*: n/2 keys in the map, n/2 random keys. @@ -537,6 +537,7 @@ but still not expose or include the full implementation / API of the container. // declare cstack_pnt; struct Point may be an incomplete type. forward_cstack(cstack_pnt, struct Point); + typedef struct Dataset { cstack_pnt vertices; cstack_pnt colors; -- cgit v1.2.3 From d7fba27af452de2d709767e615fa2e90d6b3a391 Mon Sep 17 00:00:00 2001 From: tylov Date: Wed, 26 Jul 2023 21:23:15 +0200 Subject: Added cmap_emplace_key() / csmap_emplace_key() More docs. --- README.md | 29 +++++----- docs/algorithm_api.md | 4 +- docs/cmap_api.md | 8 ++- docs/csmap_api.md | 1 + include/stc/algo/filter.h | 2 +- include/stc/cmap.h | 87 +++++++++++++++------------- include/stc/csmap.h | 30 ++++++---- include/stc/forward.h | 1 + misc/examples/smartpointers/arc_containers.c | 1 - misc/tests/cspan_test.c | 4 +- 10 files changed, 95 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 9b6698e5..d66a7f1c 100644 --- a/README.md +++ b/README.md @@ -619,23 +619,24 @@ STC is generally very memory efficient. Memory usage for the different container # Version History ## Version 4.3 -- Some breaking changes. -- **coroutines**: much improved with some new API and added features. -- **cspan**: Rewritten to add support for **column-major** order (fortran) multidim spans and transposed views. -- Removed default comparison for **clist**, **cvec** and **cdeq** (like cstack and cqueue). - - Define `i_cmp_native` to enable built-in i_key types comparisons (<, ==). - - Use of `i_keyclass` still expects comparison functions defined. - - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined. -- **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. +- Some breaking changes: + - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. + - Changes in `coroutine.h`: much improved with some new API and added features. + - Renamed stc/calgo.h => `` + - Removed deprecated stc/crandom.h. Use `` with the new API. + - Removed default comparison for **clist**, **cvec** and **cdeq**: + - Define `i_cmp_native` to enable comparison for built-in i_key types (<, ==). + - Use of `i_keyclass` still expects comparison functions to be defined. + - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined. + - Renamed input enum flags for ***cregex***-functions. +- **cspan**: Changed representation of strides to add **column-major** order (fortran) multidimensional spans and transposed views. - All new faster and smaller **cqueue** and **cdeq** implementations, using a circular buffer. -- Renamed i_extern => `i_import`. - - Define `i_import` before `#include ` will also define utf8 case conversions. +- Renamed i_extern => `i_import` (i_extern deprecated). + - Define `i_import` before `#include ` will also define full utf8 case conversions. - Define `i_import` before `#include ` will also define cstr + utf8 tables. -- Renamed c_make() => ***c_init()*** macro for initializing containers with element lists. -- Renamed input enum flags for ***cregex***-functions. -- Removed deprecated . Use `` with the new API. +- Renamed c_make() => ***c_init()*** macro for initializing containers with element lists. c_make deprecated. - Removed deprecated uppercase flow-control macro names. -- Improved default string hash function. +- Other smaller additions, bug fixes and improved documentation. ## Version 4.2 - New home! And online single headers for https://godbolt.org diff --git a/docs/algorithm_api.md b/docs/algorithm_api.md index 490771b5..40ff32d6 100644 --- a/docs/algorithm_api.md +++ b/docs/algorithm_api.md @@ -130,7 +130,7 @@ Iterate a container or a crange with chained `&&` filtering. [ [Run this example](https://godbolt.org/z/n9aYrYPv8) ] ```c -#include +#include #include bool isPrime(long long i) { @@ -309,8 +309,6 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are | `continue` | Exit a defer-block without resource leak | ```c -#include // or -... // `c_defer` executes the expression(s) when leaving scope. // Note: does not require inclusion of "raii.h". cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 17f27662..4e6da57d 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -71,7 +71,8 @@ cmap_X_result cmap_X_insert_or_assign(cmap_X* self, i_key key, i_val map cmap_X_result cmap_X_push(cmap_X* self, cmap_X_value entry); // similar to insert cmap_X_result cmap_X_emplace(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map -cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update +cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update mapped +cmap_X_result cmap_X_emplace_key(cmap_X* self, i_keyraw rkey); // see example 1. int cmap_X_erase(cmap_X* self, i_keyraw rkey); // return 0 or 1 cmap_X_iter cmap_X_erase_at(cmap_X* self, cmap_X_iter it); // return iter after it @@ -138,6 +139,11 @@ int main(void) cmap_str_emplace(&umap, "BLACK", "#000000"); cmap_str_emplace(&umap, "WHITE", "#FFFFFF"); + // Insert only if "CYAN" is not in the map: create mapped value when needed only. + cmap_str_result res = cmap_str_emplace_key(&umap, "CYAN"); + if (res.inserted) + res.ref->second = cstr_from("#00FFFF"); // must assign second if key was inserted. + // Output values by key printf("The HEX of color RED is:[%s]\n", cstr_str(cmap_str_at(&umap, "RED"))); printf("The HEX of color BLACK is:[%s]\n", cstr_str(cmap_str_at(&umap, "BLACK"))); diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 164b0f8a..d739283b 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -72,6 +72,7 @@ csmap_X_result csmap_X_push(csmap_X* self, csmap_X_value entry); csmap_X_result csmap_X_emplace(csmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map csmap_X_result csmap_X_emplace_or_assign(csmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update rmapped +csmap_X_result csmap_X_emplace_key(csmap_X* self, i_keyraw rkey); // if key not in map, mapped is left unassigned int csmap_X_erase(csmap_X* self, i_keyraw rkey); csmap_X_iter csmap_X_erase_at(csmap_X* self, csmap_X_iter it); // returns iter after it diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index 1a62c3e1..320cd50d 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -24,7 +24,7 @@ #include #define i_val int #include -#include +#include int main(void) { diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 513a8b93..2dd8cbe6 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -55,7 +55,6 @@ int main(void) { #include #include struct chash_slot { uint8_t hashx; }; -typedef struct { intptr_t idx; uint8_t hashx, found; } chash_bucket; #endif // CMAP_H_INCLUDED #ifndef _i_prefix @@ -94,7 +93,7 @@ STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self map); STC_API void _cx_MEMB(_drop)(_cx_Self* self); STC_API void _cx_MEMB(_clear)(_cx_Self* self); STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t capacity); -STC_API chash_bucket _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr); +STC_API _cx_result _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr); STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey); STC_API void _cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* val); STC_API float _cx_MEMB(_max_load_factor)(const _cx_Self* self); @@ -106,9 +105,9 @@ STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* map) { return !map->siz STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* map) { return (intptr_t)map->size; } STC_INLINE intptr_t _cx_MEMB(_bucket_count)(_cx_Self* map) { return map->bucket_count; } STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey) - { return self->size && _cx_MEMB(_bucket_)(self, &rkey).found; } + { return self->size && !_cx_MEMB(_bucket_)(self, &rkey).inserted; } -#ifndef _i_isset +#ifdef _i_ismap STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped); #if !defined i_no_emplace STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped); @@ -116,14 +115,15 @@ STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rke STC_INLINE const _cx_mapped* _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) { - chash_bucket b = _cx_MEMB(_bucket_)(self, &rkey); - c_assert(b.found); - return &self->data[b.idx].second; + _cx_result b = _cx_MEMB(_bucket_)(self, &rkey); + c_assert(!b.inserted); + return &b.ref->second; } + STC_INLINE _cx_mapped* _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey) { return (_cx_mapped*)_cx_MEMB(_at)(self, rkey); } -#endif // !_i_isset +#endif // _i_ismap #if !defined i_no_clone STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { @@ -151,6 +151,16 @@ _cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe } return _res; } + +#ifdef _i_ismap + STC_INLINE _cx_result + _cx_MEMB(_emplace_key)(_cx_Self* self, _cx_keyraw rkey) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey); + if (_res.inserted) + _res.ref->first = i_keyfrom(rkey); + return _res; + } +#endif // _i_ismap #endif // !i_no_emplace STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) { @@ -215,19 +225,19 @@ STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) { STC_INLINE _cx_iter _cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey) { - chash_bucket b; - if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found) - return c_LITERAL(_cx_iter){self->data + b.idx, + _cx_result b; + if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted) + return c_LITERAL(_cx_iter){b.ref, self->data + self->bucket_count, - self->slot + b.idx}; + self->slot + (b.ref - self->data)}; return _cx_MEMB(_end)(self); } STC_INLINE const _cx_value* _cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey) { - chash_bucket b; - if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found) - return self->data + b.idx; + _cx_result b; + if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted) + return b.ref; return NULL; } @@ -237,10 +247,10 @@ _cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey) STC_INLINE int _cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) { - chash_bucket b = {0}; - if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found) - _cx_MEMB(_erase_entry)(self, self->data + b.idx); - return b.found; + _cx_result b; + if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted) + { _cx_MEMB(_erase_entry)(self, b.ref); return 1; } + return 0; } STC_INLINE _cx_iter @@ -313,7 +323,7 @@ STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) { c_memset(self->slot, 0, c_sizeof(chash_slot)*self->bucket_count); } -#ifndef _i_isset +#ifdef _i_ismap STC_DEF _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) { _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); @@ -340,42 +350,41 @@ STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) { return _res; } #endif // !i_no_emplace -#endif // !_i_isset +#endif // _i_ismap -STC_DEF chash_bucket +STC_DEF _cx_result _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); intptr_t _cap = self->bucket_count; - chash_bucket b = {fastrange_2(_hash, _cap), (uint8_t)(_hash | 0x80)}; + intptr_t _idx = fastrange_2(_hash, _cap); + _cx_result b = {NULL, true, (uint8_t)(_hash | 0x80)}; const chash_slot* s = self->slot; - while (s[b.idx].hashx) { - if (s[b.idx].hashx == b.hashx) { - const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + b.idx)); + while (s[_idx].hashx) { + if (s[_idx].hashx == b.hashx) { + const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + _idx)); if (i_eq((&_raw), rkeyptr)) { - b.found = true; + b.inserted = false; break; } } - if (++b.idx == _cap) b.idx = 0; + if (++_idx == _cap) _idx = 0; } + b.ref = self->data + _idx; return b; } STC_DEF _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { - _cx_result res = {NULL}; if (self->size >= (intptr_t)((float)self->bucket_count * (i_max_load_factor))) if (!_cx_MEMB(_reserve)(self, (intptr_t)(self->size*3/2 + 2))) - return res; + return c_LITERAL(_cx_result){NULL}; - chash_bucket b = _cx_MEMB(_bucket_)(self, &rkey); - res.ref = &self->data[b.idx]; - if (!b.found) { - self->slot[b.idx].hashx = b.hashx; - res.inserted = true; + _cx_result b = _cx_MEMB(_bucket_)(self, &rkey); + if (b.inserted) { + self->slot[b.ref - self->data].hashx = b.hashx; ++self->size; } - return res; + return b; } #if !defined i_no_clone @@ -417,9 +426,9 @@ _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) { const chash_slot* s = self->slot; for (intptr_t i = 0; i < _oldbucks; ++i, ++d) if ((s++)->hashx) { _cx_keyraw r = i_keyto(_i_keyref(d)); - chash_bucket b = _cx_MEMB(_bucket_)(&m, &r); - m.slot[b.idx].hashx = b.hashx; - m.data[b.idx] = *d; // move + _cx_result b = _cx_MEMB(_bucket_)(&m, &r); + m.slot[b.ref - m.data].hashx = b.hashx; + *b.ref = *d; // move } c_swap(_cx_Self, self, &m); } diff --git a/include/stc/csmap.h b/include/stc/csmap.h index f4d33a4d..d2e1d1fc 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -170,19 +170,29 @@ _cx_MEMB(_shrink_to_fit)(_cx_Self *self) { } #endif // !i_no_clone -#ifndef _i_isset +STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey); + +#ifdef _i_ismap STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped); #if !defined i_no_emplace STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped); - #endif + STC_INLINE _cx_result + _cx_MEMB(_emplace_key)(_cx_Self* self, _cx_keyraw rkey) { + _cx_result res = _cx_MEMB(_insert_entry_)(self, rkey); + if (res.inserted) + res.ref->first = i_keyfrom(rkey); + return res; + } + #endif STC_INLINE const _cx_mapped* _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; } + STC_INLINE _cx_mapped* _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey) { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; } -#endif // !_i_isset +#endif // _i_ismap STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) { @@ -209,8 +219,6 @@ _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { return true; } -static _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey); - STC_INLINE _cx_result _cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); @@ -326,7 +334,7 @@ _cx_MEMB(_new_node_)(_cx_Self* self, int level) { return tn; } -#ifndef _i_isset +#ifdef _i_ismap STC_DEF _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) { _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); @@ -353,7 +361,7 @@ _cx_MEMB(_new_node_)(_cx_Self* self, int level) { return _res; } #endif // !i_no_emplace -#endif // !_i_isset +#endif // !_i_ismap STC_DEF _cx_value* _cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out) { @@ -407,7 +415,7 @@ _cx_MEMB(_split_)(_cx_node *d, int32_t tn) { return tn; } -static int32_t +STC_DEF int32_t _cx_MEMB(_insert_entry_i_)(_cx_Self* self, int32_t tn, const _cx_keyraw* rkey, _cx_result* _res) { int32_t up[64], tx = tn; _cx_node* d = self->nodes; @@ -439,7 +447,7 @@ _cx_MEMB(_insert_entry_i_)(_cx_Self* self, int32_t tn, const _cx_keyraw* rkey, _ return up[0]; } -static _cx_result +STC_DEF _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { _cx_result res = {NULL}; int32_t tn = _cx_MEMB(_insert_entry_i_)(self, self->root, &rkey, &res); @@ -448,7 +456,7 @@ _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { return res; } -static int32_t +STC_DEF int32_t _cx_MEMB(_erase_r_)(_cx_Self *self, int32_t tn, const _cx_keyraw* rkey, int *erased) { _cx_node *d = self->nodes; if (tn == 0) @@ -533,7 +541,7 @@ _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) { } #if !defined i_no_clone -static int32_t +STC_DEF int32_t _cx_MEMB(_clone_r_)(_cx_Self* self, _cx_node* src, int32_t sn) { if (sn == 0) return 0; diff --git a/include/stc/forward.h b/include/stc/forward.h index 484a8b63..085205cf 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -120,6 +120,7 @@ typedef struct chash_slot chash_slot; typedef struct { \ SELF##_value *ref; \ bool inserted; \ + uint8_t hashx; \ } SELF##_result; \ \ typedef struct { \ diff --git a/misc/examples/smartpointers/arc_containers.c b/misc/examples/smartpointers/arc_containers.c index 2fb04c56..6209005d 100644 --- a/misc/examples/smartpointers/arc_containers.c +++ b/misc/examples/smartpointers/arc_containers.c @@ -2,7 +2,6 @@ // and demonstrate sharing and cloning of maps. #define i_implement #include -#include #define i_type Map #define i_key_str // strings #define i_val int diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index d7ca9b64..ce267b14 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -1,6 +1,5 @@ #include #include -#include #include "ctest.h" using_cspan3(intspan, int); @@ -48,7 +47,8 @@ CTEST(cspan, slice) { #include CTEST(cspan, slice2) { - c_auto (cstack_int, stack) + cstack_int stack = {0}; + c_defer (cstack_int_drop(&stack)) { c_forrange (i, 10*20*30) cstack_int_push(&stack, i); -- cgit v1.2.3 From c5e7742523c09520f1186458a574ef816f089821 Mon Sep 17 00:00:00 2001 From: tylov Date: Thu, 27 Jul 2023 12:50:11 +0200 Subject: Added docs for "pull" functions. --- docs/cdeq_api.md | 2 ++ docs/cqueue_api.md | 1 + docs/cstack_api.md | 3 ++- docs/cvec_api.md | 3 ++- include/stc/cdeq.h | 1 + 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index 38de7f66..c544f213 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -56,12 +56,14 @@ cdeq_X_value* cdeq_X_back(const cdeq_X* self); cdeq_X_value* cdeq_X_push_front(cdeq_X* self, i_key value); cdeq_X_value* cdeq_X_emplace_front(cdeq_X* self, i_keyraw raw); void cdeq_X_pop_front(cdeq_X* self); +cdeq_X_value cdeq_X_pull_front(cdeq_X* self); // move out front element cdeq_X_value* cdeq_X_push_back(cdeq_X* self, i_key value); cdeq_X_value* cdeq_X_push(cdeq_X* self, i_key value); // alias for push_back() cdeq_X_value* cdeq_X_emplace_back(cdeq_X* self, i_keyraw raw); cdeq_X_value* cdeq_X_emplace(cdeq_X* self, i_keyraw raw); // alias for emplace_back() void cdeq_X_pop_back(cdeq_X* self); +cdeq_X_value cdeq_X_pull_back(cdeq_X* self); // move out last element cdeq_X_iter cdeq_X_insert_n(cdeq_X* self, intptr_t idx, const i_key[] arr, intptr_t n); // move values cdeq_X_iter cdeq_X_insert_at(cdeq_X* self, cdeq_X_iter it, i_key value); // move value diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md index 1834baf9..ba4411b7 100644 --- a/docs/cqueue_api.md +++ b/docs/cqueue_api.md @@ -45,6 +45,7 @@ cqueue_X_value* cqueue_X_back(const cqueue_X* self); cqueue_X_value* cqueue_X_push(cqueue_X* self, i_key value); cqueue_X_value* cqueue_X_emplace(cqueue_X* self, i_keyraw raw); void cqueue_X_pop(cqueue_X* self); +cqueue_X_value cqueue_X_pull(cqueue_X* self); // move out last element cqueue_X_iter cqueue_X_begin(const cqueue_X* self); cqueue_X_iter cqueue_X_end(const cqueue_X* self); diff --git a/docs/cstack_api.md b/docs/cstack_api.md index fb629392..da0bc954 100644 --- a/docs/cstack_api.md +++ b/docs/cstack_api.md @@ -48,7 +48,8 @@ i_key* cstack_X_at_mut(cstack_X* self, intptr_t idx); i_key* cstack_X_push(cstack_X* self, i_key value); i_key* cstack_X_emplace(cstack_X* self, i_keyraw raw); -void cstack_X_pop(cstack_X* self); +void cstack_X_pop(cstack_X* self); // destroy last element +cstack_X_value cstack_X_pull(cstack_X* self); // move out last element cstack_X_iter cstack_X_begin(const cstack_X* self); cstack_X_iter cstack_X_end(const cstack_X* self); diff --git a/docs/cvec_api.md b/docs/cvec_api.md index 9cba74b5..3f827df6 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -68,8 +68,9 @@ cvec_X_value* cvec_X_emplace(cvec_X* self, i_keyraw raw); cvec_X_value* cvec_X_push_back(cvec_X* self, i_key value); // alias for push cvec_X_value* cvec_X_emplace_back(cvec_X* self, i_keyraw raw); // alias for emplace -void cvec_X_pop(cvec_X* self); +void cvec_X_pop(cvec_X* self); // destroy last element void cvec_X_pop_back(cvec_X* self); // alias for pop +cvec_X_value cvec_X_pull(cvec_X* self); // move out last element cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_key arr[], intptr_t n); // move values cvec_X_iter cvec_X_insert_at(cvec_X* self, cvec_X_iter it, i_key value); // move value diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 9892f6f1..cde2928c 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -34,6 +34,7 @@ #define _pull _pull_front #include "priv/cqueue_hdr.h" #undef _pop +#undef _pull STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value); STC_API _cx_iter _cx_MEMB(_insert_n)(_cx_Self* self, intptr_t idx, const _cx_value* arr, intptr_t n); -- cgit v1.2.3 From a64d171f0eb76c8f208ffc7d8501baa8222634d3 Mon Sep 17 00:00:00 2001 From: tylov Date: Thu, 27 Jul 2023 15:24:46 +0200 Subject: An improvement in cvec/cdeq insert_uninit() impl. --- include/stc/cdeq.h | 2 +- include/stc/coroutine.h | 3 ++- include/stc/cvec.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index cde2928c..b0575fe0 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -156,7 +156,7 @@ _cx_MEMB(_insert_uninit)(_cx_Self* self, const intptr_t idx, const intptr_t n) { const intptr_t len = _cx_MEMB(_size)(self); _cx_iter it = {._s=self}; if (len + n > self->capmask) - if (!_cx_MEMB(_reserve)(self, len + n)) + if (!_cx_MEMB(_reserve)(self, len*5/4 + n)) return it; for (intptr_t i = len - 1, j = i + n; i >= idx; --i, --j) *_cx_MEMB(_at_mut)(self, j) = *_cx_MEMB(_at)(self, i); diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h index 42905744..9f55dddf 100644 --- a/include/stc/coroutine.h +++ b/include/stc/coroutine.h @@ -169,7 +169,8 @@ typedef struct cco_runtime { #define cco_task_blocking_1(task) cco_task_blocking_3(task, _rt, 16) #define cco_task_blocking_3(task, rt, STACKDEPTH) \ for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ - (((rt.result = cco_task_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) + (((rt.result = cco_task_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & \ + ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) /* * Semaphore diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 774f0582..e2b8fe97 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -326,7 +326,7 @@ _cx_MEMB(_push)(_cx_Self* self, i_key value) { STC_DEF _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, const intptr_t idx, const intptr_t n) { if (self->_len + n > self->_cap) - if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + n)) + if (!_cx_MEMB(_reserve)(self, self->_len*5/4 + n)) return _cx_MEMB(_end)(self); _cx_value* pos = self->data + idx; -- cgit v1.2.3 From 078f20f2e378543f078e86f8ad256887378ce92b Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 28 Jul 2023 11:20:25 +0200 Subject: Improved crand docs and commented out the irrelevant 32-bit variants in the benchmark. --- docs/crandom_api.md | 28 ++++++++++++--------------- misc/benchmarks/various/prng_bench.cpp | 31 ++++++++++++++---------------- misc/examples/smartpointers/arcvec_erase.c | 3 ++- 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/docs/crandom_api.md b/docs/crandom_api.md index 88924784..c6491243 100644 --- a/docs/crandom_api.md +++ b/docs/crandom_api.md @@ -8,27 +8,23 @@ See [random](https://en.cppreference.com/w/cpp/header/random) for similar c++ fu ## Description -**crand64** is a novel, very fast PRNG, suited for parallel usage. It features a -Weyl-sequence as part of its state. It is based on *sfc64*, but has a different output function -and state size. +**crand64** is a very fast PRNG, suited for parallel usage. It is based on *sfc64*, but has a +different output function and state size. It features a Weyl-sequence as part of its state. -**sfc64** is the fastest among *pcg*, *xoshiro`**`*, and *lehmer*. It is equally fast or faster than -*sfc64* on most platforms. *wyrand* is faster on platforms with fast 128-bit multiplication, and has -2^64 period (https://github.com/lemire/SwiftWyhash/issues/10). *wyrand* is not suited for massive -parallel usage due to its limited minimal period. +**crand64** is faster or equally fast as *wyrand*, *xoshiro\*\**, *sfc64*, and *romu_trio* +with both **clang 16.0** and **gcc 13.1** from the [prng_bench.c](../misc/benchmarks/various/prng_bench.cpp) +on windows 11, Ryzen 7 5700X. (clang does not optimize *xoshiro\*\** and *sfc64* as well as gcc does). -**crand64** does not require multiplication or 128-bit integer operations. It has 320 bit state, -where 64-bits are constant per prng instance created. - -There is no *jump function*, but each odd number Weyl-increment (state[4]) starts a new +**crand64** has no jump *function*, but each odd number Weyl-increment (state[4]) starts a new unique 2^64 *minimum* length period, i.e. virtually unlimitied number of unique threads. +In contrast, *wyrand* and *sfc64* have only a (total) minimum period of 2^64 (*romu_trio* has +no guarantees), and may therefore not be suited for massive parallel usage (for purists). -**crand64** passes *PractRand* (tested up to 8TB output), Vigna's Hamming weight test, and simple -correlation tests, i.e. *n* interleaved streams with only one-bit differences in initial state. -Also 32-bit and 16-bit versions passes PractRand up to their size limits. +**crand64** does not require multiplication or 128-bit integer operations. It has 320 bit state, +where 64-bits are constant per instance. -For more, see the PRNG shootout by Vigna: http://prng.di.unimi.it and a debate between the authors of -xoshiro and pcg (Vigna/O'Neill) PRNGs: https://www.pcg-random.org/posts/on-vignas-pcg-critique.html +**crand64** passes *PractRand* (tested up to 8TB output), Vigna's Hamming weight test, and simple +correlation tests. The 16- and 32-bit variants also passes PractRand up to their size limits. ## Header file diff --git a/misc/benchmarks/various/prng_bench.cpp b/misc/benchmarks/various/prng_bench.cpp index 234e3805..cd43ff36 100644 --- a/misc/benchmarks/various/prng_bench.cpp +++ b/misc/benchmarks/various/prng_bench.cpp @@ -66,7 +66,7 @@ uint32_t pcg32(uint32_t s[2]) { } -/* xoshiro128+ */ +/* xo(ro)shiro */ uint64_t xoroshiro128plus(uint64_t s[2]) { const uint64_t s0 = s[0]; @@ -80,9 +80,6 @@ uint64_t xoroshiro128plus(uint64_t s[2]) { return result; } - -/* xoshiro256** */ - static inline uint64_t xoshiro256starstar(uint64_t s[4]) { const uint64_t result = rotl64(s[1] * 5, 7) * 9; const uint64_t t = s[1] << 17; @@ -95,7 +92,7 @@ static inline uint64_t xoshiro256starstar(uint64_t s[4]) { return result; } -// wyrand - 2020-12-07 +/* wyrand - 2020-12-07 */ static inline void _wymum(uint64_t *A, uint64_t *B){ #if defined(__SIZEOF_INT128__) __uint128_t r = *A; r *= *B; @@ -136,44 +133,44 @@ int main(void) for (size_t ti = 0; ti < 2; ti++) { init_state(rng.state, 12345123); cout << endl << "ROUND " << ti+1 << " ---------" << endl; - +/* beg = clock(); for (size_t i = 0; i < N; i++) - recipient[i] = romu_trio(rng.state); + recipient[i] = sfc32((uint32_t *)rng.state); end = clock(); - cout << "romu_trio:\t" + cout << "sfc32:\t\t" << (float(end - beg) / CLOCKS_PER_SEC) << "s: " << recipient[312] << endl; beg = clock(); for (size_t i = 0; i < N; i++) - recipient[i] = wyrand64(rng.state); + recipient[i] = stc32((uint32_t *)rng.state); end = clock(); - cout << "wyrand64:\t" + cout << "stc32:\t\t" << (float(end - beg) / CLOCKS_PER_SEC) << "s: " << recipient[312] << endl; beg = clock(); for (size_t i = 0; i < N; i++) - recipient[i] = sfc32((uint32_t *)rng.state); + recipient[i] = pcg32((uint32_t *)rng.state); end = clock(); - cout << "sfc32:\t\t" + cout << "pcg32:\t\t" << (float(end - beg) / CLOCKS_PER_SEC) << "s: " << recipient[312] << endl; - +*/ beg = clock(); for (size_t i = 0; i < N; i++) - recipient[i] = stc32((uint32_t *)rng.state); + recipient[i] = romu_trio(rng.state); end = clock(); - cout << "stc32:\t\t" + cout << "romu_trio:\t" << (float(end - beg) / CLOCKS_PER_SEC) << "s: " << recipient[312] << endl; beg = clock(); for (size_t i = 0; i < N; i++) - recipient[i] = pcg32((uint32_t *)rng.state); + recipient[i] = wyrand64(rng.state); end = clock(); - cout << "pcg32:\t\t" + cout << "wyrand64:\t" << (float(end - beg) / CLOCKS_PER_SEC) << "s: " << recipient[312] << endl; diff --git a/misc/examples/smartpointers/arcvec_erase.c b/misc/examples/smartpointers/arcvec_erase.c index ba54c1c7..9d757533 100644 --- a/misc/examples/smartpointers/arcvec_erase.c +++ b/misc/examples/smartpointers/arcvec_erase.c @@ -19,7 +19,8 @@ int main(void) // clone the second 2012 and push it back. // note: cloning make sure that vec.data[2] has ref count 2. - Vec_push(&vec, Arc_clone(vec.data[2])); + Vec_push(&vec, Arc_clone(vec.data[2])); // => share vec.data[2] + Vec_emplace(&vec, *vec.data[2].get); // => deep-copy vec.data[2] printf("vec before erase :"); c_foreach (i, Vec, vec) -- cgit v1.2.3 From b7efd45f0b59511be7202ce0641283e8a8ff6028 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 28 Jul 2023 11:48:03 +0200 Subject: Updated output label for crand64. --- misc/benchmarks/various/prng_bench.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/benchmarks/various/prng_bench.cpp b/misc/benchmarks/various/prng_bench.cpp index cd43ff36..45c14d18 100644 --- a/misc/benchmarks/various/prng_bench.cpp +++ b/misc/benchmarks/various/prng_bench.cpp @@ -186,7 +186,7 @@ int main(void) for (size_t i = 0; i < N; i++) recipient[i] = crand_u64(&rng); end = clock(); - cout << "stc64:\t\t" + cout << "crand64:\t" << (float(end - beg) / CLOCKS_PER_SEC) << "s: " << recipient[312] << endl; -- cgit v1.2.3 From e6003c0ecfd7e76803bac7d98feca814997e8a86 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 30 Jul 2023 22:46:33 +0200 Subject: Added cco_generator(Name, ...) macro to simplify defining the iterator struct. Updated example generator.c --- include/stc/coroutine.h | 14 +++++++++++++- misc/examples/coroutines/generator.c | 19 +++++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h index 9f55dddf..7917878a 100644 --- a/include/stc/coroutine.h +++ b/include/stc/coroutine.h @@ -132,7 +132,19 @@ typedef enum { (void)((co)->cco_state = 0) /* - * Tasks (optional) + * Generators + */ + +#define cco_generator(Name, ...) \ + typedef Name Name##_value; \ + typedef struct { \ + Name##_value* ref; \ + int cco_state; \ + __VA_ARGS__ \ + } Name##_iter + +/* + * Tasks */ struct cco_runtime; diff --git a/misc/examples/coroutines/generator.c b/misc/examples/coroutines/generator.c index f9e59fea..c092b92d 100644 --- a/misc/examples/coroutines/generator.c +++ b/misc/examples/coroutines/generator.c @@ -6,19 +6,17 @@ typedef struct { int size; int a, b, c; -} Triple, Triple_value; +} Triple; -typedef struct { - Triple_value* ref; +cco_generator(Triple, int count; - int cco_state; -} Triple_iter; +); int Triple_next(Triple_iter* it) { - Triple_value* g = it->ref; + Triple* g = it->ref; // note: before cco_routine cco_routine(it) { - for (g->c = 5; g->size; ++g->c) { + for (g->c = 5;; ++g->c) { for (g->a = 1; g->a < g->c; ++g->a) { for (g->b = g->a; g->b < g->c; ++g->b) { if (g->a*g->a + g->b*g->b == g->c*g->c) { @@ -31,12 +29,13 @@ int Triple_next(Triple_iter* it) { } cco_cleanup: it->ref = NULL; + puts("done"); } return 0; } Triple_iter Triple_begin(Triple* g) { - Triple_iter it = {.ref=g}; + Triple_iter it = {.ref=g}; Triple_next(&it); return it; } @@ -44,8 +43,8 @@ Triple_iter Triple_begin(Triple* g) { int main(void) { - puts("Pythagorean triples with c < 100:"); - Triple triple = {.size=30}; // max number of triples + puts("Pythagorean triples; stops at 100 triples or c >= 100:"); + Triple triple = {.size=100}; c_foreach (i, Triple, triple) { if (i.ref->c < 100) printf("%u: (%d, %d, %d)\n", i.count, i.ref->a, i.ref->b, i.ref->c); -- cgit v1.2.3 From cd9d0f984e678691855787a2fa855ccd5876425f Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 31 Jul 2023 08:37:59 +0200 Subject: Renamed cco_generator() => cco_iter_struct(). More in line with cco_task_struct() macro. --- include/stc/coroutine.h | 2 +- misc/examples/coroutines/generator.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h index 7917878a..146f3efb 100644 --- a/include/stc/coroutine.h +++ b/include/stc/coroutine.h @@ -135,7 +135,7 @@ typedef enum { * Generators */ -#define cco_generator(Name, ...) \ +#define cco_iter_struct(Name, ...) \ typedef Name Name##_value; \ typedef struct { \ Name##_value* ref; \ diff --git a/misc/examples/coroutines/generator.c b/misc/examples/coroutines/generator.c index c092b92d..3f51ce9c 100644 --- a/misc/examples/coroutines/generator.c +++ b/misc/examples/coroutines/generator.c @@ -8,7 +8,7 @@ typedef struct { int a, b, c; } Triple; -cco_generator(Triple, +cco_iter_struct(Triple, int count; ); -- cgit v1.2.3 From fc0942205fb06591a5784b2878187a4475c6af7b Mon Sep 17 00:00:00 2001 From: tylov Date: Tue, 1 Aug 2023 15:45:37 +0200 Subject: Fixed bug in cco_call_await() test. --- include/stc/coroutine.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h index 146f3efb..4a7fd6aa 100644 --- a/include/stc/coroutine.h +++ b/include/stc/coroutine.h @@ -94,10 +94,10 @@ typedef enum { /* cco_call_await(): assumes coroutine returns a cco_result value (int) */ #define cco_call_await(...) c_MACRO_OVERLOAD(cco_call_await, __VA_ARGS__) #define cco_call_await_1(corocall) cco_call_await_2(corocall, CCO_DONE) -#define cco_call_await_2(corocall, resultbits) \ +#define cco_call_await_2(corocall, awaitbits) \ do { \ *_state = __LINE__; \ - case __LINE__: { int _r = corocall; if (!(_r & ~(resultbits))) {return _r; goto _resume;} } \ + case __LINE__: { int _r = corocall; if (_r & ~(awaitbits)) {return _r; goto _resume;} } \ } while (0) /* cco_call_blocking(): assumes coroutine returns a cco_result value (int) */ @@ -170,10 +170,10 @@ typedef struct cco_runtime { #define cco_task_await(...) c_MACRO_OVERLOAD(cco_task_await, __VA_ARGS__) #define cco_task_await_2(task, rt) cco_task_await_3(task, rt, CCO_DONE) -#define cco_task_await_3(task, rt, resultbits) \ +#define cco_task_await_3(task, rt, awaitbits) \ do { \ cco_runtime* _rt = rt; \ - (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = (resultbits); \ + (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = (awaitbits); \ cco_yield_v(CCO_AWAIT); \ } while (0) -- cgit v1.2.3 From 6354a597892e84baa6c3a99b98f2c7acaf33a99d Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 1 Aug 2023 16:31:40 +0200 Subject: Improve changelog for v4.3 --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d66a7f1c..c333f5cd 100644 --- a/README.md +++ b/README.md @@ -619,17 +619,19 @@ STC is generally very memory efficient. Memory usage for the different container # Version History ## Version 4.3 -- Some breaking changes: +- Breaking changes: - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. - - Changes in `coroutine.h`: much improved with some new API and added features. - - Renamed stc/calgo.h => `` - - Removed deprecated stc/crandom.h. Use `` with the new API. + - Renamed => `` + - Moved => `` + - Much improved with some new API and added features. + - Removed deprecated . Use `` with the new API. + - Reverted names _unif and _norm back to `_uniform` and `_normal`. - Removed default comparison for **clist**, **cvec** and **cdeq**: - Define `i_cmp_native` to enable comparison for built-in i_key types (<, ==). - Use of `i_keyclass` still expects comparison functions to be defined. - - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined. + - Use of `i_keyboxed` compares stored pointers instead of pointed to values if comparison not defined. - Renamed input enum flags for ***cregex***-functions. -- **cspan**: Changed representation of strides to add **column-major** order (fortran) multidimensional spans and transposed views. +- **cspan**: Added **column-major** order (fortran) multidimensional spans and transposed views (changed representation of strides). - All new faster and smaller **cqueue** and **cdeq** implementations, using a circular buffer. - Renamed i_extern => `i_import` (i_extern deprecated). - Define `i_import` before `#include ` will also define full utf8 case conversions. -- cgit v1.2.3 From 2ae41a5b709abdb549c4128b43e25ee8a704fcc4 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 1 Aug 2023 16:47:38 +0200 Subject: Last minute API change for coroutines before V4.3 release: - Renamed cco_xxxx_await() => cco_await_xxxx() (call, task, sem, timer) - Renamed cco_xxxx_blocking() => cco_blocking_xxxx() (call, task) - Renamed cco_task_resume() => cco_resume_task() --- docs/coroutine_api.md | 47 +++++++++++++------------- include/stc/coroutine.h | 46 ++++++++++++------------- misc/examples/coroutines/cointerleave.c | 2 +- misc/examples/coroutines/coread.c | 2 +- misc/examples/coroutines/coroutines.c | 8 ++--- misc/examples/coroutines/cotasks1.c | 4 +-- misc/examples/coroutines/cotasks2.c | 10 +++--- misc/examples/coroutines/dining_philosophers.c | 8 ++--- misc/examples/coroutines/filetask.c | 6 ++-- misc/examples/coroutines/triples.c | 2 +- 10 files changed, 68 insertions(+), 67 deletions(-) diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md index 30b85640..6dc12123 100644 --- a/docs/coroutine_api.md +++ b/docs/coroutine_api.md @@ -24,23 +24,24 @@ NB! ***cco_yield\*()*** / ***cco_await\*()*** may not be called from within a `s | | `cco_yield_final();` | Yield final suspend, enter cleanup-state | | | `cco_yield_final(ret);` | Yield a final value | | | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| -| | `cco_call_await(cocall);` | Await for subcoro to finish (returns its ret value) | -| | `cco_call_await(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) | +| | `cco_await_call(cocall);` | Await for subcoro to finish (returns its ret value) | +| | `cco_await_call(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) | | | `cco_return;` | Return from coroutine (inside cco_routine) | | | Task objects: | | | | `cco_task_struct(Name, ...);` | Define a coroutine task struct | -| | `cco_task_await(task, cco_runtime* rt);`| Await for task to finish | -| | `cco_task_await(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) | -|`cco_result`| `cco_task_resume(task, rt);` | Resume suspended task | +| | `cco_await_task(task, cco_runtime* rt);`| Await for task to finish | +| | `cco_await_task(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) | +|`cco_result`| `cco_resume_task(task, rt);` | Resume suspended task | | | Semaphores: | | | | `cco_sem` | Semaphore type | +| | `cco_await_sem(sem)` | Await for the semaphore count > 0 | | `cco_sem` | `cco_sem_from(long value)` | Create semaphore | | | `cco_sem_set(sem, long value)` | Set semaphore value | -| | `cco_sem_await(sem)` | Await for the semaphore count > 0 | + | | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | | | Timers: | | | | `cco_timer` | Timer type | -| | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)| +| | `cco_await_timer(tm, double sec)` | Await secs for timer to expire (usec prec.)| | | `cco_timer_start(tm, double sec)` | Start timer for secs duration | | | `cco_timer_restart(tm)` | Restart timer with same duration | | `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | @@ -49,10 +50,10 @@ NB! ***cco_yield\*()*** / ***cco_await\*()*** may not be called from within a `s | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_call_blocking(cocall) {}` | Run blocking until cocall is finished | -| `void` | `cco_call_blocking(cocall, int* outres) {}`| Run blocking until cocall is finished | -| | `cco_task_blocking(task) {}` | Run blocking until task is finished | -| | `cco_task_blocking(task, rt, STACKSZ) {}`| Run blocking until task is finished | +| `void` | `cco_blocking_call(cocall) {}` | Run blocking until cocall is finished | +| `void` | `cco_blocking_call(cocall, int* outres) {}`| Run blocking until cocall is finished | +| | `cco_blocking_task(task) {}` | Run blocking until task is finished | +| | `cco_blocking_task(task, rt, STACKSZ) {}`| Run blocking until task is finished | | | Time functions: | | | `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | | | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | @@ -117,7 +118,7 @@ int main(void) { struct triples co = {.max_c = 25}; int n = 0; - cco_call_blocking(triples(&co)) { + cco_blocking_call(triples(&co)) { printf("%d: [%d, %d, %d]\n", ++n, co.a, co.b, co.c); } } @@ -171,26 +172,26 @@ int main(void) { struct gcd1_triples co = {.max_n = 100, .max_c = 100}; int n = 0; - cco_call_blocking(gcd1_triples(&co)) { + cco_blocking_call(gcd1_triples(&co)) { printf("%d: [%d, %d, %d]\n", ++n, co.tri.a, co.tri.b, co.tri.c); } } ``` -When using ***cco_call_blocking()***, the coroutine is continuously resumed after each yield suspension. +When using ***cco_blocking_call()***, the coroutine is continuously resumed after each yield suspension. However, this means that it first calls ***gcd1_triples()***, which immediately jumps to after the `cco_yield` -statement and calls ***triples()***, which again jumps and resumes after its `cco_yield`-statement. This is efficient only when yielding or awaiting from the top- or second-level call like here, but naturally not when couroutine calls are more deeply nested or recursive. The STC coroutine implementation therefore also contains task-objects (`cco_task`), which are base-coroutine -objects/enclosures. These can be executed using ***cco_task_blocking()*** instead of ***cco_call_blocking()***. -Inner coroutine calls are done by ***cco_task_await()***, where you may await for a certain return value, normally CCO_YIELD or just CCO_DONE. It uses a stack of pointers of task-enclosures to call the current +objects/enclosures. These can be executed using ***cco_blocking_task()*** instead of ***cco_blocking_call()***. +Inner coroutine calls are done by ***cco_await_task()***, where you may await for a certain return value, normally CCO_YIELD or just CCO_DONE. It uses a stack of pointers of task-enclosures to call the current inner-level function directly. The task-objects have the added benefit that coroutines can be managed by a scheduler, which is useful when dealing with large numbers of coroutines (like in many games and simulations). Note that these two modes may be mixed, and that for short-lived coroutines (only a few suspends), -it is often beneficial to call the sub-coroutine directly rather than via ***cco_task_await()*** +it is often beneficial to call the sub-coroutine directly rather than via ***cco_await_task()*** (which pushes the task on top of the runtime stack and yields - then executed on next resume). The following example uses task-objects with 3-levels deep coroutine calls. It emulates an async generator @@ -212,7 +213,7 @@ int next_value(struct next_value* co, cco_runtime* rt) { cco_routine (co) { while (true) { - cco_timer_await(&co->tm, 1 + rand() % 2); // suspend with CCO_AWAIT + cco_await_timer(&co->tm, 1 + rand() % 2); // suspend with CCO_AWAIT co->val = rand(); cco_yield(); // suspend with CCO_YIELD } @@ -242,7 +243,7 @@ int produce_items(struct produce_items* p, cco_runtime* rt) while (true) { // await for CCO_YIELD (or CCO_DONE) - cco_task_await(&p->next, rt, CCO_YIELD); + cco_await_task(&p->next, rt, CCO_YIELD); cstr_printf(&p->str, "item %d", p->next.val); print_time(); printf("produced %s\n", cstr_str(&p->str)); @@ -269,13 +270,13 @@ int consume_items(struct consume_items* c, cco_runtime* rt) for (c->i = 1; c->i <= c->n; ++c->i) { printf("consume #%d\n", c->i); - cco_task_await(&c->produce, rt, CCO_YIELD); + cco_await_task(&c->produce, rt, CCO_YIELD); print_time(); printf("consumed %s\n", cstr_str(&c->produce.str)); } cco_cleanup: cco_stop(&c->produce); - cco_task_resume(&c->produce, rt); + cco_resume_task(&c->produce, rt); puts("done consume"); } return 0; @@ -287,6 +288,6 @@ int main(void) .n = 5, .cco_func = consume_items, }; - cco_task_blocking(&consume); + cco_blocking_task(&consume); } -``` \ No newline at end of file +``` diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h index 4a7fd6aa..01a32fc2 100644 --- a/include/stc/coroutine.h +++ b/include/stc/coroutine.h @@ -91,19 +91,19 @@ typedef enum { case __LINE__: if (!(promise)) {return ret; goto _resume;} \ } while (0) -/* cco_call_await(): assumes coroutine returns a cco_result value (int) */ -#define cco_call_await(...) c_MACRO_OVERLOAD(cco_call_await, __VA_ARGS__) -#define cco_call_await_1(corocall) cco_call_await_2(corocall, CCO_DONE) -#define cco_call_await_2(corocall, awaitbits) \ +/* cco_await_call(): assumes coroutine returns a cco_result value (int) */ +#define cco_await_call(...) c_MACRO_OVERLOAD(cco_await_call, __VA_ARGS__) +#define cco_await_call_1(corocall) cco_await_call_2(corocall, CCO_DONE) +#define cco_await_call_2(corocall, awaitbits) \ do { \ *_state = __LINE__; \ case __LINE__: { int _r = corocall; if (_r & ~(awaitbits)) {return _r; goto _resume;} } \ } while (0) -/* cco_call_blocking(): assumes coroutine returns a cco_result value (int) */ -#define cco_call_blocking(...) c_MACRO_OVERLOAD(cco_call_blocking, __VA_ARGS__) -#define cco_call_blocking_1(corocall) while ((corocall) != CCO_DONE) -#define cco_call_blocking_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) +/* cco_blocking_call(): assumes coroutine returns a cco_result value (int) */ +#define cco_blocking_call(...) c_MACRO_OVERLOAD(cco_blocking_call, __VA_ARGS__) +#define cco_blocking_call_1(corocall) while ((corocall) != CCO_DONE) +#define cco_blocking_call_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) #define cco_cleanup \ *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP @@ -165,23 +165,23 @@ typedef struct cco_runtime { #define cco_cast_task(task) \ ((cco_task *)(task) + 0*sizeof((task)->cco_func(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) -#define cco_task_resume(task, rt) \ +#define cco_resume_task(task, rt) \ (task)->cco_func(task, rt) -#define cco_task_await(...) c_MACRO_OVERLOAD(cco_task_await, __VA_ARGS__) -#define cco_task_await_2(task, rt) cco_task_await_3(task, rt, CCO_DONE) -#define cco_task_await_3(task, rt, awaitbits) \ +#define cco_await_task(...) c_MACRO_OVERLOAD(cco_await_task, __VA_ARGS__) +#define cco_await_task_2(task, rt) cco_await_task_3(task, rt, CCO_DONE) +#define cco_await_task_3(task, rt, awaitbits) \ do { \ cco_runtime* _rt = rt; \ (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = (awaitbits); \ cco_yield_v(CCO_AWAIT); \ } while (0) -#define cco_task_blocking(...) c_MACRO_OVERLOAD(cco_task_blocking, __VA_ARGS__) -#define cco_task_blocking_1(task) cco_task_blocking_3(task, _rt, 16) -#define cco_task_blocking_3(task, rt, STACKDEPTH) \ +#define cco_blocking_task(...) c_MACRO_OVERLOAD(cco_blocking_task, __VA_ARGS__) +#define cco_blocking_task_1(task) cco_blocking_task_3(task, _rt, 16) +#define cco_blocking_task_3(task, rt, STACKDEPTH) \ for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ - (((rt.result = cco_task_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & \ + (((rt.result = cco_resume_task(rt.stack[rt.top], (cco_runtime*)&rt)) & \ ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) /* @@ -190,9 +190,9 @@ typedef struct cco_runtime { typedef struct { intptr_t count; } cco_sem; -#define cco_sem_await(sem) cco_sem_await_and_return(sem, CCO_AWAIT) -#define cco_sem_await_v(sem) cco_sem_await_and_return(sem, ) -#define cco_sem_await_and_return(sem, ret) \ +#define cco_await_sem(sem) cco_await_sem_and_return(sem, CCO_AWAIT) +#define cco_await_sem_v(sem) cco_await_sem_and_return(sem, ) +#define cco_await_sem_and_return(sem, ret) \ do { \ cco_await_and_return((sem)->count > 0, ret); \ --(sem)->count; \ @@ -248,10 +248,10 @@ typedef struct { intptr_t count; } cco_sem; typedef struct { double interval, start; } cco_timer; -#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT) -#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__) -#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, ) -#define cco_timer_await_v_3(tm, sec, ret) \ +#define cco_await_timer(tm, sec) cco_await_timer_v_3(tm, sec, CCO_AWAIT) +#define cco_await_timer_v(...) c_MACRO_OVERLOAD(cco_await_timer_v, __VA_ARGS__) +#define cco_await_timer_v_2(tm, sec) cco_await_timer_v_3(tm, sec, ) +#define cco_await_timer_v_3(tm, sec, ret) \ do { \ cco_timer_start(tm, sec); \ cco_await_and_return(cco_timer_expired(tm), ret); \ diff --git a/misc/examples/coroutines/cointerleave.c b/misc/examples/coroutines/cointerleave.c index f3710ba3..80494176 100644 --- a/misc/examples/coroutines/cointerleave.c +++ b/misc/examples/coroutines/cointerleave.c @@ -49,7 +49,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - cco_call_blocking(interleaved(&g)) { + cco_blocking_call(interleaved(&g)) { printf("%d ", g.value); } puts(""); diff --git a/misc/examples/coroutines/coread.c b/misc/examples/coroutines/coread.c index ebaaf19d..359ca85d 100644 --- a/misc/examples/coroutines/coread.c +++ b/misc/examples/coroutines/coread.c @@ -33,7 +33,7 @@ int main(void) { struct file_read g = {__FILE__}; int n = 0; - cco_call_blocking(file_read(&g)) + cco_blocking_call(file_read(&g)) { printf("%3d %s\n", ++n, cstr_str(&g.line)); //if (n == 10) cco_stop(&g); diff --git a/misc/examples/coroutines/coroutines.c b/misc/examples/coroutines/coroutines.c index 489c3ed6..e642a823 100644 --- a/misc/examples/coroutines/coroutines.c +++ b/misc/examples/coroutines/coroutines.c @@ -84,13 +84,13 @@ struct combined { int combined(struct combined* g) { cco_routine(g) { - cco_call_await(prime(&g->prm)); - cco_call_await(fibonacci(&g->fib)); + cco_await_call(prime(&g->prm)); + cco_await_call(fibonacci(&g->fib)); // Reuse the g->prm context and extend the count: g->prm.count = 8, g->prm.result += 2; cco_reset(&g->prm); - cco_call_await(prime(&g->prm)); + cco_await_call(prime(&g->prm)); cco_cleanup: puts("final combined"); @@ -103,7 +103,7 @@ int main(void) struct combined c = {.prm={.count=8}, .fib={14}}; int res; - cco_call_blocking(combined(&c), &res) { + cco_blocking_call(combined(&c), &res) { if (res == CCO_YIELD) printf("Prime(%d)=%lld, Fib(%d)=%lld\n", c.prm.idx, c.prm.result, diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c index e4afbe2b..230bd62b 100644 --- a/misc/examples/coroutines/cotasks1.c +++ b/misc/examples/coroutines/cotasks1.c @@ -16,7 +16,7 @@ int next_value(struct next_value* co) { cco_routine (co) { while (true) { - cco_timer_await(&co->tm, 1 + rand() % 2); + cco_await_timer(&co->tm, 1 + rand() % 2); co->val = rand(); cco_yield(); } @@ -88,7 +88,7 @@ int main(void) struct consume_items consume = {.n=5}; int count = 0; - cco_call_blocking(consume_items(&consume, &produce)) + cco_blocking_call(consume_items(&consume, &produce)) { ++count; //cco_sleep(0.001); diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c index 4fdf98d9..d77a28bc 100644 --- a/misc/examples/coroutines/cotasks2.c +++ b/misc/examples/coroutines/cotasks2.c @@ -15,7 +15,7 @@ int next_value(struct next_value* co, cco_runtime* rt) { cco_routine (co) { while (true) { - cco_timer_await(&co->tm, 1 + rand() % 2); + cco_await_timer(&co->tm, 1 + rand() % 2); co->val = rand(); cco_yield(); } @@ -46,7 +46,7 @@ int produce_items(struct produce_items* p, cco_runtime* rt) while (true) { // await for next CCO_YIELD (or CCO_DONE) in next_value - cco_task_await(&p->next, rt, CCO_YIELD); + cco_await_task(&p->next, rt, CCO_YIELD); cstr_printf(&p->str, "item %d", p->next.val); print_time(); printf("produced %s\n", cstr_str(&p->str)); @@ -75,14 +75,14 @@ int consume_items(struct consume_items* c, cco_runtime* rt) for (c->i = 1; c->i <= c->n; ++c->i) { printf("consume #%d\n", c->i); - cco_task_await(&c->produce, rt, CCO_YIELD); + cco_await_task(&c->produce, rt, CCO_YIELD); print_time(); printf("consumed %s\n", cstr_str(&c->produce.str)); } cco_cleanup: cco_stop(&c->produce); - cco_task_resume(&c->produce, rt); + cco_resume_task(&c->produce, rt); puts("done consume"); } return 0; @@ -94,5 +94,5 @@ int main(void) .cco_func = consume_items, .n = 5, }; - cco_task_blocking(&consume); + cco_blocking_task(&consume); } diff --git a/misc/examples/coroutines/dining_philosophers.c b/misc/examples/coroutines/dining_philosophers.c index abe09204..f7edf815 100644 --- a/misc/examples/coroutines/dining_philosophers.c +++ b/misc/examples/coroutines/dining_philosophers.c @@ -34,15 +34,15 @@ int philosopher(struct Philosopher* p) while (1) { duration = 1.0 + crandf()*2.0; printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10); - cco_timer_await(&p->tm, duration); + cco_await_timer(&p->tm, duration); printf("Philosopher %d is hungry...\n", p->id); - cco_sem_await(p->left_fork); - cco_sem_await(p->right_fork); + cco_await_sem(p->left_fork); + cco_await_sem(p->right_fork); duration = 0.5 + crandf(); printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10); - cco_timer_await(&p->tm, duration); + cco_await_timer(&p->tm, duration); cco_sem_release(p->left_fork); cco_sem_release(p->right_fork); diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c index bfce7810..28292801 100644 --- a/misc/examples/coroutines/filetask.c +++ b/misc/examples/coroutines/filetask.c @@ -21,7 +21,7 @@ int file_read(struct file_read* co, cco_runtime* rt) while (true) { // emulate async io: await 10ms per line - cco_timer_await(&co->tm, 0.003); + cco_await_timer(&co->tm, 0.003); if (!cstr_getline(&co->line, co->fp)) break; @@ -50,7 +50,7 @@ int count_line(struct count_line* co, cco_runtime* rt) while (true) { // await for next CCO_YIELD (or CCO_DONE) in file_read() - cco_task_await(&co->reader, rt, CCO_YIELD); + cco_await_task(&co->reader, rt, CCO_YIELD); if (rt->result == CCO_DONE) break; co->lineCount += 1; cco_yield(); @@ -73,7 +73,7 @@ int main(void) // Execute coroutine as top-level blocking int loop = 0; - cco_task_blocking(&countTask) { ++loop; } + cco_blocking_task(&countTask) { ++loop; } printf("line count = %d\n", countTask.lineCount); printf("exec count = %d\n", loop); diff --git a/misc/examples/coroutines/triples.c b/misc/examples/coroutines/triples.c index 9fd771ce..22914c2b 100644 --- a/misc/examples/coroutines/triples.c +++ b/misc/examples/coroutines/triples.c @@ -64,7 +64,7 @@ int main(void) struct triples t = {.max_c = 100}; int n = 0; - cco_call_blocking(triples_coro(&t)) { + cco_blocking_call(triples_coro(&t)) { if (gcd(t.a, t.b) > 1) continue; if (++n <= 20) -- cgit v1.2.3 From 94391527ef50cbee073a4b427f6fe839c010ecb1 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 1 Aug 2023 16:47:38 +0200 Subject: Last minute API change for coroutines before V4.3 release: - Renamed cco_xxxx_await() => cco_await_xxxx() (call, task, sem, timer) - Renamed cco_xxxx_blocking() => cco_blocking_xxxx() (call, task) - Renamed cco_task_resume() => cco_resume_task() - Simplified cco_blocking_call() --- docs/coroutine_api.md | 46 +++++++++++++------------- include/stc/coroutine.h | 44 ++++++++++++------------ misc/examples/coroutines/cointerleave.c | 2 +- misc/examples/coroutines/coread.c | 2 +- misc/examples/coroutines/coroutines.c | 8 ++--- misc/examples/coroutines/cotasks1.c | 4 +-- misc/examples/coroutines/cotasks2.c | 10 +++--- misc/examples/coroutines/dining_philosophers.c | 14 ++++---- misc/examples/coroutines/filetask.c | 6 ++-- misc/examples/coroutines/triples.c | 2 +- 10 files changed, 68 insertions(+), 70 deletions(-) diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md index 30b85640..b356dcf0 100644 --- a/docs/coroutine_api.md +++ b/docs/coroutine_api.md @@ -24,23 +24,24 @@ NB! ***cco_yield\*()*** / ***cco_await\*()*** may not be called from within a `s | | `cco_yield_final();` | Yield final suspend, enter cleanup-state | | | `cco_yield_final(ret);` | Yield a final value | | | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| -| | `cco_call_await(cocall);` | Await for subcoro to finish (returns its ret value) | -| | `cco_call_await(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) | +| | `cco_await_call(cocall);` | Await for subcoro to finish (returns its ret value) | +| | `cco_await_call(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) | | | `cco_return;` | Return from coroutine (inside cco_routine) | | | Task objects: | | | | `cco_task_struct(Name, ...);` | Define a coroutine task struct | -| | `cco_task_await(task, cco_runtime* rt);`| Await for task to finish | -| | `cco_task_await(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) | -|`cco_result`| `cco_task_resume(task, rt);` | Resume suspended task | +| | `cco_await_task(task, cco_runtime* rt);`| Await for task to finish | +| | `cco_await_task(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) | +|`cco_result`| `cco_resume_task(task, rt);` | Resume suspended task | | | Semaphores: | | | | `cco_sem` | Semaphore type | +| | `cco_await_sem(sem)` | Await for the semaphore count > 0 | | `cco_sem` | `cco_sem_from(long value)` | Create semaphore | | | `cco_sem_set(sem, long value)` | Set semaphore value | -| | `cco_sem_await(sem)` | Await for the semaphore count > 0 | + | | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | | | Timers: | | | | `cco_timer` | Timer type | -| | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)| +| | `cco_await_timer(tm, double sec)` | Await secs for timer to expire (usec prec.)| | | `cco_timer_start(tm, double sec)` | Start timer for secs duration | | | `cco_timer_restart(tm)` | Restart timer with same duration | | `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | @@ -49,10 +50,9 @@ NB! ***cco_yield\*()*** / ***cco_await\*()*** may not be called from within a `s | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_call_blocking(cocall) {}` | Run blocking until cocall is finished | -| `void` | `cco_call_blocking(cocall, int* outres) {}`| Run blocking until cocall is finished | -| | `cco_task_blocking(task) {}` | Run blocking until task is finished | -| | `cco_task_blocking(task, rt, STACKSZ) {}`| Run blocking until task is finished | +| `void` | `cco_blocking_call(cocall) {}` | Run blocking until cocall is finished | +| | `cco_blocking_task(task) {}` | Run blocking until task is finished | +| | `cco_blocking_task(task, rt, STACKSZ) {}`| Run blocking until task is finished | | | Time functions: | | | `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | | | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | @@ -117,7 +117,7 @@ int main(void) { struct triples co = {.max_c = 25}; int n = 0; - cco_call_blocking(triples(&co)) { + cco_blocking_call(triples(&co)) { printf("%d: [%d, %d, %d]\n", ++n, co.a, co.b, co.c); } } @@ -171,26 +171,26 @@ int main(void) { struct gcd1_triples co = {.max_n = 100, .max_c = 100}; int n = 0; - cco_call_blocking(gcd1_triples(&co)) { + cco_blocking_call(gcd1_triples(&co)) { printf("%d: [%d, %d, %d]\n", ++n, co.tri.a, co.tri.b, co.tri.c); } } ``` -When using ***cco_call_blocking()***, the coroutine is continuously resumed after each yield suspension. +When using ***cco_blocking_call()***, the coroutine is continuously resumed after each yield suspension. However, this means that it first calls ***gcd1_triples()***, which immediately jumps to after the `cco_yield` -statement and calls ***triples()***, which again jumps and resumes after its `cco_yield`-statement. This is efficient only when yielding or awaiting from the top- or second-level call like here, but naturally not when couroutine calls are more deeply nested or recursive. The STC coroutine implementation therefore also contains task-objects (`cco_task`), which are base-coroutine -objects/enclosures. These can be executed using ***cco_task_blocking()*** instead of ***cco_call_blocking()***. -Inner coroutine calls are done by ***cco_task_await()***, where you may await for a certain return value, normally CCO_YIELD or just CCO_DONE. It uses a stack of pointers of task-enclosures to call the current +objects/enclosures. These can be executed using ***cco_blocking_task()*** instead of ***cco_blocking_call()***. +Inner coroutine calls are done by ***cco_await_task()***, where you may await for a certain return value, normally CCO_YIELD or just CCO_DONE. It uses a stack of pointers of task-enclosures to call the current inner-level function directly. The task-objects have the added benefit that coroutines can be managed by a scheduler, which is useful when dealing with large numbers of coroutines (like in many games and simulations). Note that these two modes may be mixed, and that for short-lived coroutines (only a few suspends), -it is often beneficial to call the sub-coroutine directly rather than via ***cco_task_await()*** +it is often beneficial to call the sub-coroutine directly rather than via ***cco_await_task()*** (which pushes the task on top of the runtime stack and yields - then executed on next resume). The following example uses task-objects with 3-levels deep coroutine calls. It emulates an async generator @@ -212,7 +212,7 @@ int next_value(struct next_value* co, cco_runtime* rt) { cco_routine (co) { while (true) { - cco_timer_await(&co->tm, 1 + rand() % 2); // suspend with CCO_AWAIT + cco_await_timer(&co->tm, 1 + rand() % 2); // suspend with CCO_AWAIT co->val = rand(); cco_yield(); // suspend with CCO_YIELD } @@ -242,7 +242,7 @@ int produce_items(struct produce_items* p, cco_runtime* rt) while (true) { // await for CCO_YIELD (or CCO_DONE) - cco_task_await(&p->next, rt, CCO_YIELD); + cco_await_task(&p->next, rt, CCO_YIELD); cstr_printf(&p->str, "item %d", p->next.val); print_time(); printf("produced %s\n", cstr_str(&p->str)); @@ -269,13 +269,13 @@ int consume_items(struct consume_items* c, cco_runtime* rt) for (c->i = 1; c->i <= c->n; ++c->i) { printf("consume #%d\n", c->i); - cco_task_await(&c->produce, rt, CCO_YIELD); + cco_await_task(&c->produce, rt, CCO_YIELD); print_time(); printf("consumed %s\n", cstr_str(&c->produce.str)); } cco_cleanup: cco_stop(&c->produce); - cco_task_resume(&c->produce, rt); + cco_resume_task(&c->produce, rt); puts("done consume"); } return 0; @@ -287,6 +287,6 @@ int main(void) .n = 5, .cco_func = consume_items, }; - cco_task_blocking(&consume); + cco_blocking_task(&consume); } -``` \ No newline at end of file +``` diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h index 4a7fd6aa..0e592bae 100644 --- a/include/stc/coroutine.h +++ b/include/stc/coroutine.h @@ -91,19 +91,17 @@ typedef enum { case __LINE__: if (!(promise)) {return ret; goto _resume;} \ } while (0) -/* cco_call_await(): assumes coroutine returns a cco_result value (int) */ -#define cco_call_await(...) c_MACRO_OVERLOAD(cco_call_await, __VA_ARGS__) -#define cco_call_await_1(corocall) cco_call_await_2(corocall, CCO_DONE) -#define cco_call_await_2(corocall, awaitbits) \ +/* cco_await_call(): assumes coroutine returns a cco_result value (int) */ +#define cco_await_call(...) c_MACRO_OVERLOAD(cco_await_call, __VA_ARGS__) +#define cco_await_call_1(corocall) cco_await_call_2(corocall, CCO_DONE) +#define cco_await_call_2(corocall, awaitbits) \ do { \ *_state = __LINE__; \ case __LINE__: { int _r = corocall; if (_r & ~(awaitbits)) {return _r; goto _resume;} } \ } while (0) -/* cco_call_blocking(): assumes coroutine returns a cco_result value (int) */ -#define cco_call_blocking(...) c_MACRO_OVERLOAD(cco_call_blocking, __VA_ARGS__) -#define cco_call_blocking_1(corocall) while ((corocall) != CCO_DONE) -#define cco_call_blocking_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) +/* cco_blocking_call(): assumes coroutine returns a cco_result value (int) */ +#define cco_blocking_call(corocall) while ((corocall) != CCO_DONE) #define cco_cleanup \ *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP @@ -165,23 +163,23 @@ typedef struct cco_runtime { #define cco_cast_task(task) \ ((cco_task *)(task) + 0*sizeof((task)->cco_func(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) -#define cco_task_resume(task, rt) \ +#define cco_resume_task(task, rt) \ (task)->cco_func(task, rt) -#define cco_task_await(...) c_MACRO_OVERLOAD(cco_task_await, __VA_ARGS__) -#define cco_task_await_2(task, rt) cco_task_await_3(task, rt, CCO_DONE) -#define cco_task_await_3(task, rt, awaitbits) \ +#define cco_await_task(...) c_MACRO_OVERLOAD(cco_await_task, __VA_ARGS__) +#define cco_await_task_2(task, rt) cco_await_task_3(task, rt, CCO_DONE) +#define cco_await_task_3(task, rt, awaitbits) \ do { \ cco_runtime* _rt = rt; \ (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = (awaitbits); \ cco_yield_v(CCO_AWAIT); \ } while (0) -#define cco_task_blocking(...) c_MACRO_OVERLOAD(cco_task_blocking, __VA_ARGS__) -#define cco_task_blocking_1(task) cco_task_blocking_3(task, _rt, 16) -#define cco_task_blocking_3(task, rt, STACKDEPTH) \ +#define cco_blocking_task(...) c_MACRO_OVERLOAD(cco_blocking_task, __VA_ARGS__) +#define cco_blocking_task_1(task) cco_blocking_task_3(task, _rt, 16) +#define cco_blocking_task_3(task, rt, STACKDEPTH) \ for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ - (((rt.result = cco_task_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & \ + (((rt.result = cco_resume_task(rt.stack[rt.top], (cco_runtime*)&rt)) & \ ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) /* @@ -190,9 +188,9 @@ typedef struct cco_runtime { typedef struct { intptr_t count; } cco_sem; -#define cco_sem_await(sem) cco_sem_await_and_return(sem, CCO_AWAIT) -#define cco_sem_await_v(sem) cco_sem_await_and_return(sem, ) -#define cco_sem_await_and_return(sem, ret) \ +#define cco_await_sem(sem) cco_await_sem_and_return(sem, CCO_AWAIT) +#define cco_await_sem_v(sem) cco_await_sem_and_return(sem, ) +#define cco_await_sem_and_return(sem, ret) \ do { \ cco_await_and_return((sem)->count > 0, ret); \ --(sem)->count; \ @@ -248,10 +246,10 @@ typedef struct { intptr_t count; } cco_sem; typedef struct { double interval, start; } cco_timer; -#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT) -#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__) -#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, ) -#define cco_timer_await_v_3(tm, sec, ret) \ +#define cco_await_timer(tm, sec) cco_await_timer_v_3(tm, sec, CCO_AWAIT) +#define cco_await_timer_v(...) c_MACRO_OVERLOAD(cco_await_timer_v, __VA_ARGS__) +#define cco_await_timer_v_2(tm, sec) cco_await_timer_v_3(tm, sec, ) +#define cco_await_timer_v_3(tm, sec, ret) \ do { \ cco_timer_start(tm, sec); \ cco_await_and_return(cco_timer_expired(tm), ret); \ diff --git a/misc/examples/coroutines/cointerleave.c b/misc/examples/coroutines/cointerleave.c index f3710ba3..80494176 100644 --- a/misc/examples/coroutines/cointerleave.c +++ b/misc/examples/coroutines/cointerleave.c @@ -49,7 +49,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - cco_call_blocking(interleaved(&g)) { + cco_blocking_call(interleaved(&g)) { printf("%d ", g.value); } puts(""); diff --git a/misc/examples/coroutines/coread.c b/misc/examples/coroutines/coread.c index ebaaf19d..359ca85d 100644 --- a/misc/examples/coroutines/coread.c +++ b/misc/examples/coroutines/coread.c @@ -33,7 +33,7 @@ int main(void) { struct file_read g = {__FILE__}; int n = 0; - cco_call_blocking(file_read(&g)) + cco_blocking_call(file_read(&g)) { printf("%3d %s\n", ++n, cstr_str(&g.line)); //if (n == 10) cco_stop(&g); diff --git a/misc/examples/coroutines/coroutines.c b/misc/examples/coroutines/coroutines.c index 489c3ed6..faeb71f6 100644 --- a/misc/examples/coroutines/coroutines.c +++ b/misc/examples/coroutines/coroutines.c @@ -84,13 +84,13 @@ struct combined { int combined(struct combined* g) { cco_routine(g) { - cco_call_await(prime(&g->prm)); - cco_call_await(fibonacci(&g->fib)); + cco_await_call(prime(&g->prm)); + cco_await_call(fibonacci(&g->fib)); // Reuse the g->prm context and extend the count: g->prm.count = 8, g->prm.result += 2; cco_reset(&g->prm); - cco_call_await(prime(&g->prm)); + cco_await_call(prime(&g->prm)); cco_cleanup: puts("final combined"); @@ -103,7 +103,7 @@ int main(void) struct combined c = {.prm={.count=8}, .fib={14}}; int res; - cco_call_blocking(combined(&c), &res) { + cco_blocking_call(res = combined(&c)) { if (res == CCO_YIELD) printf("Prime(%d)=%lld, Fib(%d)=%lld\n", c.prm.idx, c.prm.result, diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c index e4afbe2b..230bd62b 100644 --- a/misc/examples/coroutines/cotasks1.c +++ b/misc/examples/coroutines/cotasks1.c @@ -16,7 +16,7 @@ int next_value(struct next_value* co) { cco_routine (co) { while (true) { - cco_timer_await(&co->tm, 1 + rand() % 2); + cco_await_timer(&co->tm, 1 + rand() % 2); co->val = rand(); cco_yield(); } @@ -88,7 +88,7 @@ int main(void) struct consume_items consume = {.n=5}; int count = 0; - cco_call_blocking(consume_items(&consume, &produce)) + cco_blocking_call(consume_items(&consume, &produce)) { ++count; //cco_sleep(0.001); diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c index 4fdf98d9..d77a28bc 100644 --- a/misc/examples/coroutines/cotasks2.c +++ b/misc/examples/coroutines/cotasks2.c @@ -15,7 +15,7 @@ int next_value(struct next_value* co, cco_runtime* rt) { cco_routine (co) { while (true) { - cco_timer_await(&co->tm, 1 + rand() % 2); + cco_await_timer(&co->tm, 1 + rand() % 2); co->val = rand(); cco_yield(); } @@ -46,7 +46,7 @@ int produce_items(struct produce_items* p, cco_runtime* rt) while (true) { // await for next CCO_YIELD (or CCO_DONE) in next_value - cco_task_await(&p->next, rt, CCO_YIELD); + cco_await_task(&p->next, rt, CCO_YIELD); cstr_printf(&p->str, "item %d", p->next.val); print_time(); printf("produced %s\n", cstr_str(&p->str)); @@ -75,14 +75,14 @@ int consume_items(struct consume_items* c, cco_runtime* rt) for (c->i = 1; c->i <= c->n; ++c->i) { printf("consume #%d\n", c->i); - cco_task_await(&c->produce, rt, CCO_YIELD); + cco_await_task(&c->produce, rt, CCO_YIELD); print_time(); printf("consumed %s\n", cstr_str(&c->produce.str)); } cco_cleanup: cco_stop(&c->produce); - cco_task_resume(&c->produce, rt); + cco_resume_task(&c->produce, rt); puts("done consume"); } return 0; @@ -94,5 +94,5 @@ int main(void) .cco_func = consume_items, .n = 5, }; - cco_task_blocking(&consume); + cco_blocking_task(&consume); } diff --git a/misc/examples/coroutines/dining_philosophers.c b/misc/examples/coroutines/dining_philosophers.c index abe09204..e917c303 100644 --- a/misc/examples/coroutines/dining_philosophers.c +++ b/misc/examples/coroutines/dining_philosophers.c @@ -34,15 +34,15 @@ int philosopher(struct Philosopher* p) while (1) { duration = 1.0 + crandf()*2.0; printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10); - cco_timer_await(&p->tm, duration); + cco_await_timer(&p->tm, duration); printf("Philosopher %d is hungry...\n", p->id); - cco_sem_await(p->left_fork); - cco_sem_await(p->right_fork); - + cco_await_sem(p->left_fork); + cco_await_sem(p->right_fork); + duration = 0.5 + crandf(); printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10); - cco_timer_await(&p->tm, duration); + cco_await_timer(&p->tm, duration); cco_sem_release(p->left_fork); cco_sem_release(p->right_fork); @@ -94,10 +94,10 @@ int main(void) cco_timer tm = cco_timer_from(15.0); // seconds csrand((uint64_t)time(NULL)); - while (!cco_done(&dine)) { + cco_blocking_call(dining(&dine)) + { if (cco_timer_expired(&tm)) cco_stop(&dine); - dining(&dine); // resume cco_sleep(0.001); ++n; } diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c index bfce7810..28292801 100644 --- a/misc/examples/coroutines/filetask.c +++ b/misc/examples/coroutines/filetask.c @@ -21,7 +21,7 @@ int file_read(struct file_read* co, cco_runtime* rt) while (true) { // emulate async io: await 10ms per line - cco_timer_await(&co->tm, 0.003); + cco_await_timer(&co->tm, 0.003); if (!cstr_getline(&co->line, co->fp)) break; @@ -50,7 +50,7 @@ int count_line(struct count_line* co, cco_runtime* rt) while (true) { // await for next CCO_YIELD (or CCO_DONE) in file_read() - cco_task_await(&co->reader, rt, CCO_YIELD); + cco_await_task(&co->reader, rt, CCO_YIELD); if (rt->result == CCO_DONE) break; co->lineCount += 1; cco_yield(); @@ -73,7 +73,7 @@ int main(void) // Execute coroutine as top-level blocking int loop = 0; - cco_task_blocking(&countTask) { ++loop; } + cco_blocking_task(&countTask) { ++loop; } printf("line count = %d\n", countTask.lineCount); printf("exec count = %d\n", loop); diff --git a/misc/examples/coroutines/triples.c b/misc/examples/coroutines/triples.c index 9fd771ce..22914c2b 100644 --- a/misc/examples/coroutines/triples.c +++ b/misc/examples/coroutines/triples.c @@ -64,7 +64,7 @@ int main(void) struct triples t = {.max_c = 100}; int n = 0; - cco_call_blocking(triples_coro(&t)) { + cco_blocking_call(triples_coro(&t)) { if (gcd(t.a, t.b) > 1) continue; if (++n <= 20) -- cgit v1.2.3 From 7df124507b82bfb168a440392060bc0e03ce5c7e Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 1 Aug 2023 18:12:01 +0200 Subject: Fixed conversion warnings. --- misc/examples/algorithms/random.c | 35 ++++++++++++++++------------------- misc/examples/mixed/demos.c | 6 +++--- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/misc/examples/algorithms/random.c b/misc/examples/algorithms/random.c index 9522c16d..e457d329 100644 --- a/misc/examples/algorithms/random.c +++ b/misc/examples/algorithms/random.c @@ -4,42 +4,39 @@ int main(void) { - const long long N = 10000000; - const uint64_t seed = (uint64_t)time(NULL), range = 1000000; + const long long N = 10000000, range = 1000000; + const uint64_t seed = (uint64_t)time(NULL); crand_t rng = crand_init(seed); - - long long sum; - clock_t diff, before; + clock_t t; printf("Compare speed of full and unbiased ranged random numbers...\n"); - sum = 0; - before = clock(); + long long sum = 0; + t = clock(); c_forrange (N) { - sum += (uint32_t)crand_u64(&rng); + sum += (int32_t)crand_u64(&rng); } - diff = clock() - before; + t = clock() - t; printf("full range\t\t: %f secs, %lld, avg: %f\n", - (double)diff/(double)CLOCKS_PER_SEC, N, (double)(sum/N)); + (double)t/CLOCKS_PER_SEC, N, (double)(sum/N)); crand_uniform_t dist1 = crand_uniform_init(0, range); rng = crand_init(seed); sum = 0; - before = clock(); + t = clock(); c_forrange (N) { sum += crand_uniform(&rng, &dist1); // unbiased } - diff = clock() - before; + t = clock() - t; printf("unbiased 0-%lld\t: %f secs, %lld, avg: %f\n", - (long long)range, (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N)); + range, (double)t/CLOCKS_PER_SEC, N, (double)(sum/N)); sum = 0; rng = crand_init(seed); - before = clock(); + t = clock(); c_forrange (N) { - sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased + sum += (int32_t)crand_u64(&rng) % (range + 1); // biased } - diff = clock() - before; - printf("biased 0-%" PRIu64 " \t: %f secs, %lld, avg: %f\n", - (long long)range, (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N)); - + t = clock() - t; + printf("biased 0-%lld \t: %f secs, %lld, avg: %f\n", + range, (double)t/CLOCKS_PER_SEC, N, (double)(sum/N)); } diff --git a/misc/examples/mixed/demos.c b/misc/examples/mixed/demos.c index 1a604d9f..7f5091fd 100644 --- a/misc/examples/mixed/demos.c +++ b/misc/examples/mixed/demos.c @@ -28,7 +28,7 @@ void stringdemo1(void) cstr_drop(&cs); } -#define i_key int64_t +#define i_key long long #define i_tag ix #include @@ -39,14 +39,14 @@ void vectordemo1(void) for (int i = 10; i <= 100; i += 10) cvec_ix_push(&bignums, i * i); - printf("erase - %d: %" PRIu64 "\n", 3, bignums.data[3]); + printf("erase - %d: %lld\n", 3, bignums.data[3]); cvec_ix_erase_n(&bignums, 3, 1); // erase index 3 cvec_ix_pop(&bignums); // erase the last cvec_ix_erase_n(&bignums, 0, 1); // erase the first for (int i = 0; i < cvec_ix_size(&bignums); ++i) { - printf("%d: %" PRIu64 "\n", i, bignums.data[i]); + printf("%d: %lld\n", i, bignums.data[i]); } cvec_ix_drop(&bignums); -- cgit v1.2.3 From da14db1a3b3570d52f22c7ae4027d1a53b6ac862 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 1 Aug 2023 20:50:29 +0200 Subject: Added some checks that a proper i_cmp/(i_hash) is defined when i_keyraw conversion type is specified for maps. Advanced usage. --- include/stc/cmap.h | 2 ++ include/stc/cpque.h | 2 ++ include/stc/priv/template.h | 20 +++++++++++++------- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 2dd8cbe6..cd7430ba 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -69,6 +69,7 @@ struct chash_slot { uint8_t hashx; }; #define _i_SET_ONLY c_true #define _i_keyref(vp) (vp) #endif +#define _i_ishash #include "priv/template.h" #ifndef i_is_forward _cx_DEFTYPES(_c_chash_types, _cx_Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); @@ -463,6 +464,7 @@ _cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* _val) { #undef i_max_load_factor #undef _i_isset #undef _i_ismap +#undef _i_ishash #undef _i_keyref #undef _i_MAP_ONLY #undef _i_SET_ONLY diff --git a/include/stc/cpque.h b/include/stc/cpque.h index ca51eeff..520514ef 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -29,6 +29,7 @@ #endif #define _i_prefix cpque_ +#define _i_ispque #include "priv/template.h" #ifndef i_is_forward _cx_DEFTYPES(_c_cpque_types, _cx_Self, i_key); @@ -160,3 +161,4 @@ _cx_MEMB(_push)(_cx_Self* self, _cx_value value) { #endif #define CPQUE_H_INCLUDED #include "priv/template2.h" +#undef _i_ispque \ No newline at end of file diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index ccdce718..0f4ac893 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -171,6 +171,15 @@ #endif #endif +#ifndef i_no_cmp + #if defined i_cmp || defined i_less || defined i_cmp_native + #define _i_has_cmp + #endif + #if defined i_eq || defined i_cmp_native + #define _i_has_eq + #endif +#endif + #if !defined i_key #error "No i_key or i_val defined" #elif defined i_keyraw ^ defined i_keyto @@ -179,6 +188,10 @@ #error "Both i_keyclone/i_valclone and i_keydrop/i_valdrop must be defined, if any" #elif defined i_from || defined i_drop #error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead" +#elif defined i_keyraw && defined _i_ishash && !(defined i_hash && (defined _i_has_cmp || defined i_eq)) + #error "For cmap/cset, both i_hash and i_eq (or i_less or i_cmp) must be defined when i_keyraw is defined." +#elif defined i_keyraw && (defined _i_ismap || defined _i_isset || defined _i_ispque) && !defined _i_has_cmp + #error "For csmap/csset/cpque, i_cmp or i_less must be defined when i_keyraw is defined." #endif #ifndef i_tag @@ -203,13 +216,6 @@ #endif #ifndef i_no_cmp - #if defined i_cmp || defined i_less || defined i_cmp_native - #define _i_has_cmp - #endif - #if defined i_eq || defined i_cmp_native - #define _i_has_eq - #endif - // i_eq, i_less, i_cmp #if !defined i_eq && (defined i_cmp || defined i_less) #define i_eq(x, y) !(i_cmp(x, y)) -- cgit v1.2.3 From d65debf1846fad56e59852e4003e24f99bfd1517 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 2 Aug 2023 16:31:45 +0200 Subject: Renamed (most internal "class" type) crawstr => ccharptr --- docs/algorithm_api.md | 11 ++++++----- include/stc/ccommon.h | 12 ++++++------ include/stc/priv/template.h | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/algorithm_api.md b/docs/algorithm_api.md index 40ff32d6..127aa120 100644 --- a/docs/algorithm_api.md +++ b/docs/algorithm_api.md @@ -275,12 +275,13 @@ int* ip = c_const_cast(int*, cs); // issues a warning! ### Predefined template parameter functions -**crawstr** - Non-owned `const char*` "class" element type: `#define i_keyclass crawstr` +**ccharptr** - Non-owning `const char*` "class" element type: `#define i_keyclass ccharptr` ```c -typedef const char* crawstr; -int crawstr_cmp(const crawstr* x, const crawstr* y); -bool crawstr_eq(const crawstr* x, const crawstr* y); -uint64_t crawstr_hash(const crawstr* x); +typedef const char* ccharptr; +int ccharptr_cmp(const ccharptr* x, const ccharptr* y); +uint64_t ccharptr_hash(const ccharptr* x); +ccharptr ccharptr_clone(ccharptr sp); +void ccharptr_drop(ccharptr* x); ``` Default implementations ```c diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 77f754fa..2528b94f 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -124,12 +124,12 @@ typedef long long _llong; #define c_litstrlen(literal) (c_sizeof("" literal) - 1) #define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a]) -// Non-owning c-string -typedef const char* crawstr; -#define crawstr_clone(s) (s) -#define crawstr_drop(p) ((void)p) -#define crawstr_cmp(xp, yp) strcmp(*(xp), *(yp)) -#define crawstr_hash(p) cstrhash(*(p)) +// Non-owning c-string "class" +typedef const char* ccharptr; +#define ccharptr_cmp(xp, yp) strcmp(*(xp), *(yp)) +#define ccharptr_hash(p) cstrhash(*(p)) +#define ccharptr_clone(s) (s) +#define ccharptr_drop(p) ((void)p) #define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) #define c_sv_1(lit) c_sv_2(lit, c_litstrlen(lit)) diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 0f4ac893..49b4d8da 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -111,7 +111,7 @@ #if defined i_key_str #define i_keyclass cstr - #define i_rawclass crawstr + #define i_rawclass ccharptr #ifndef i_tag #define i_tag str #endif -- cgit v1.2.3 From 3f50495eb4f465531000c33072005ab218fdfb11 Mon Sep 17 00:00:00 2001 From: tylov Date: Sat, 5 Aug 2023 12:57:14 +0200 Subject: Docs improvements in README.md --- README.md | 81 ++++++++++++++++++++++++++++++------- misc/examples/coroutines/filetask.c | 2 +- 2 files changed, 67 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index c333f5cd..3ff00e52 100644 --- a/README.md +++ b/README.md @@ -521,39 +521,90 @@ Define `i_type` instead of `i_tag`: #define i_key int #include -myvec vec = MyVec_init(); -MyVec_push_back(&vec, 1); +MyVec vec = {0}; +MyVec_push(&vec, 42); ... ``` --- ## Forward declarations -It is possible to forward declare containers. This is useful when a container is part of a struct, -but still not expose or include the full implementation / API of the container. +There are two ways to pre-declare templated containers in header files: + +1. Include the templated container type instance as a header file. This also exposes all container +functions, which can be used by client code. It requires that the element type is complete. +2. Or, pre-declare the container type only. In this case, the container can be a "private" member of a +user struct (the container functions will not be available to the user). + +### 1. Include as a header file + +Create a dedicated header for the container type instance: +```c +#ifndef PointVec_H_ +#define PointVec_H_ +// Do not to include user defined headers here if they use templated containers themselves + +#define i_type PointVec +#define i_val struct Point // NB! Element type must be complete at this point! +#define i_header // Do not implement, only expose API +#include + +#endif +``` +Usage from e.g. other headers is trivial: +```c +#ifndef Dataset_H_ +#define Dataset_H_ +#include "Point.h" // include element type separately +#include "PointVec.h" + +typedef struct Dataset { + PointVec vertices; + PointVec colors; +} Dataset; +... +#endif +``` + +Implement PointVec in a c-file: +```c +#include "Point.h" +#define i_implement // define immediately before PointVec.h +#include "PointVec.h" +... +``` + +### 2. Forward declare only ```c // Dataset.h -#include // only include data structures +#ifndef Dataset_H_ +#define Dataset_H_ +#include // include various container data structure templates -// declare cstack_pnt; struct Point may be an incomplete type. -forward_cstack(cstack_pnt, struct Point); +// declare PointVec. Note: struct Point may be an incomplete/undeclared type. +forward_cvec(PointVec, struct Point); typedef struct Dataset { - cstack_pnt vertices; - cstack_pnt colors; + PointVec vertices; + PointVec colors; } Dataset; +void Dataset_drop(Dataset* self); ... +#endif +``` +Define and use the "private" container in the c-file: +```c // Dataset.c #include "Dataset.h" +#include "Point.h" // Point must be defined here. -struct Point { int x, y, z; }; // Point must be defined here. -#define i_is_forward // flag that the container was forward declared. -#define i_key struct Point -#define i_tag pnt -#include +#define i_is_forward // flag that the container was forward declared. +#define i_type PointVec +#define i_val struct Point +#include // Implements PointVec with static linking by default +... ``` - --- ## Per container-instance customization Sometimes it is useful to extend a container type to store extra data, e.g. a comparison diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c index 28292801..0607442d 100644 --- a/misc/examples/coroutines/filetask.c +++ b/misc/examples/coroutines/filetask.c @@ -21,7 +21,7 @@ int file_read(struct file_read* co, cco_runtime* rt) while (true) { // emulate async io: await 10ms per line - cco_await_timer(&co->tm, 0.003); + cco_await_timer(&co->tm, 0.010); if (!cstr_getline(&co->line, co->fp)) break; -- cgit v1.2.3 From f514c5128d62ad53623af4d45bd856b9564bce4f Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 6 Aug 2023 23:23:36 +0200 Subject: Improved Installation section in README.md --- README.md | 56 ++++++++++++++++++------------------------------------ include/stc/cstr.h | 2 +- src/libstc.c | 2 ++ 3 files changed, 21 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 3ff00e52..69c51417 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ List of contents - **Uniform, easy-to-learn API** - Just include the headers and you are good. The API and functionality resembles c++ STL and is fully listed in the docs. Intuitive method/type names and uniform usage across the various containers. - **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed for comparison and calculation is asking for trouble. STC only uses signed numbers in the API for this reason. - **Small footprint** - Small source code and generated executables. The executable from the example below using *four different* container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux. -- **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section. +- **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the [installation section](#installation). - **No callback functions** - All passed template argument functions/macros are directly called from the implementation, no slow callbacks which requires storage. - **Compiles with C++ and C99** - C code can be compiled with C++ (container element types must be POD). - **Forward declaration** - Templated containers may be [forward declared](#forward-declarations) without including the full API/implementation. @@ -333,49 +333,29 @@ After erasing the elements found: --- ## Installation -*NEEDS REWRITE!* -Because it is headers-only, headers can simply be included in your program. By default, functions are static -(some inlined). You may add the *include* folder to the **CPATH** environment variable to -let GCC, Clang, and TinyC locate the headers. +STC is primarily a "headers-only" library, so most headers can simply be included in your program. By default, +all "templated" functions are static (many inlined). If you add the STC *include* folder to the **CPATH** +environment variable, GCC, Clang, and TinyC will locate the headers automatically. -If containers are used across several translation units with common instantiated container types, it is -recommended to build as a "library" with external linking to minimize executable size. To enable this, -specify `-DSTC_HEADER` as compiler option in your build environment. Next, place all the instantiations -of the containers used inside a single C-source file as in the example below, and `#define STC_IMPLEMENT` at top. -You may also cherry-pick shared linking mode on individual containers by `#define i_header` and -`#define i_implement`, or force static symbols by `#define i_static` before container includes. - -As a special case, there may be non-templated functions in templated containers that should be implemented only -once and if needed. Currently, define `i_import` before including **cregex** or **utf8** to implement them. - -It is possible to generate single headers by executing the python script `src/singleheader.py header-file > single`. - -Conveniently, `src\libstc.c` implements non-templated functions as shared symbols for **cstr**, **csview**, -**cbits** and **crand**. When building in shared mode (-DSTC_HEADER), you may include this file in your project, -or define your own, e.g.: +The templated container functions are defined with static linking by default, which is normally optimal +for both performance and compiled binary size. However, some common container type instances, e.g. `cvec_int` +may be used in several translation units. When they are used in more than 3-4, consider creating a separate +header file for them [as described here](#1-include-as-a-header-file). Now it will use shared +linking, so *one* c-file must implement the templated container, e.g.: ```c -// stc_libs.c -#define STC_IMPLEMENT // implement all the following as shared objects #define i_implement -#include -#include "Point.h" - -#define i_key int -#define i_val int -#define i_tag ii -#include // cmap_ii: int => int +#include "cvec_int.h" +``` +The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by +`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so +linking specifications and implementation are only needed for a few lesser used functions. -#define i_key int64_t -#define i_tag ix -#include // cset_ix +Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**, +**csview**, **cregex**, **utf8**, and **crand**. -#define i_key int -#include // cvec_int +As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent +**utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc. -#define i_key Point -#define i_tag pnt -#include // clist_pnt -``` --- ## Specifying template parameters diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 2648e267..f12d29b6 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -179,7 +179,7 @@ extern void cstr_lowercase(cstr* self); extern void cstr_uppercase(cstr* self); extern bool cstr_valid_utf8(const cstr* self); -// other utf8 +// utf8 functions not depending on src/utf8code.c: STC_INLINE intptr_t cstr_u8_size(const cstr* self) { return utf8_size(cstr_str(self)); } diff --git a/src/libstc.c b/src/libstc.c index 7b49540a..462c97c4 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -2,6 +2,8 @@ #include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement #include "../include/stc/csview.h" +#define i_implement +#include "../include/stc/crand.h" #if __STDC_VERSION__ >= 201112L # define i_implement # include "../include/c11/fmt.h" -- cgit v1.2.3 From 9e13d34c82abfeeadcc8697331f9fd3e5e7f2bca Mon Sep 17 00:00:00 2001 From: tylov Date: Tue, 8 Aug 2023 00:31:15 +0200 Subject: Optimized cdeq insert (in the middle) functions. --- include/stc/cdeq.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index b0575fe0..4730721c 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -158,12 +158,14 @@ _cx_MEMB(_insert_uninit)(_cx_Self* self, const intptr_t idx, const intptr_t n) { if (len + n > self->capmask) if (!_cx_MEMB(_reserve)(self, len*5/4 + n)) return it; - for (intptr_t i = len - 1, j = i + n; i >= idx; --i, --j) - *_cx_MEMB(_at_mut)(self, j) = *_cx_MEMB(_at)(self, i); - - self->end = (self->end + n) & self->capmask; it.pos = _cdeq_topos(self, idx); it.ref = self->data + it.pos; + self->end = (self->end + n) & self->capmask; + + if (it.pos < self->end) // common case because of reserve policy + c_memmove(it.ref + n, it.ref, (len - idx)*c_sizeof *it.ref); + else for (intptr_t i = len - 1, j = i + n; i >= idx; --i, --j) + *_cx_MEMB(_at_mut)(self, j) = *_cx_MEMB(_at)(self, i); return it; } -- cgit v1.2.3 From c27c266b6c4ae0e5e535b18c3790ee97416412b9 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 8 Aug 2023 12:28:15 +0200 Subject: Reverted cco_cleanup => cco_final. (cco_cleanup deprecated). Updated generator.c example. Misc internal refactoring. --- docs/coroutine_api.md | 12 +++++------ include/stc/cmap.h | 16 +++++++-------- include/stc/coroutine.h | 5 +++-- include/stc/forward.h | 6 ++---- include/stc/priv/cqueue_hdr.h | 4 ++-- misc/examples/coroutines/coread.c | 2 +- misc/examples/coroutines/coroutines.c | 6 +++--- misc/examples/coroutines/cotasks1.c | 4 ++-- misc/examples/coroutines/cotasks2.c | 4 ++-- misc/examples/coroutines/dining_philosophers.c | 4 ++-- misc/examples/coroutines/filetask.c | 4 ++-- misc/examples/coroutines/generator.c | 28 ++++++++++++++++++-------- misc/examples/coroutines/triples.c | 2 +- 13 files changed, 54 insertions(+), 43 deletions(-) diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md index b356dcf0..6bd558f2 100644 --- a/docs/coroutine_api.md +++ b/docs/coroutine_api.md @@ -16,7 +16,7 @@ NB! ***cco_yield\*()*** / ***cco_await\*()*** may not be called from within a `s | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| |`cco_result` | `CCO_DONE`, `CCO_AWAIT`, `CCO_YIELD` | Default set of return values from coroutines | -| | `cco_cleanup:` | Label for cleanup position in coroutine | +| | `cco_final:` | Label for cleanup position in coroutine | | `bool` | `cco_done(co)` | Is coroutine done? | | | `cco_routine(co) {}` | The coroutine scope | | | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)| @@ -101,13 +101,13 @@ int triples(struct triples* i) { (int64_t)i->c * i->c) { if (i->c > i->max_c) - cco_return; // "jump" to cco_cleanup if defined, else exit scope. + cco_return; // "jump" to cco_final if defined, else exit scope. cco_yield(); } } } } - cco_cleanup: + cco_final: puts("done"); } return 0; // CCO_DONE @@ -160,7 +160,7 @@ int gcd1_triples(struct gcd1_triples* i) else cco_yield(); } - cco_cleanup: + cco_final: cco_stop(&i->tri); // to cleanup state if still active triples(&i->tri); // do cleanup (or no-op if done) } @@ -248,7 +248,7 @@ int produce_items(struct produce_items* p, cco_runtime* rt) printf("produced %s\n", cstr_str(&p->str)); cco_yield(); } - cco_cleanup: + cco_final: cstr_drop(&p->str); puts("done produce"); } @@ -273,7 +273,7 @@ int consume_items(struct consume_items* c, cco_runtime* rt) print_time(); printf("consumed %s\n", cstr_str(&c->produce.str)); } - cco_cleanup: + cco_final: cco_stop(&c->produce); cco_resume_task(&c->produce, rt); puts("done consume"); diff --git a/include/stc/cmap.h b/include/stc/cmap.h index cd7430ba..e0134964 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -306,7 +306,7 @@ STC_INLINE void _cx_MEMB(_wipe_)(_cx_Self* self) { if (self->size == 0) return; _cx_value* d = self->data, *_end = d + self->bucket_count; - chash_slot* s = self->slot; + struct chash_slot* s = self->slot; for (; d != _end; ++d) if ((s++)->hashx) _cx_MEMB(_value_drop)(d); @@ -321,7 +321,7 @@ STC_DEF void _cx_MEMB(_drop)(_cx_Self* self) { STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) { _cx_MEMB(_wipe_)(self); self->size = 0; - c_memset(self->slot, 0, c_sizeof(chash_slot)*self->bucket_count); + c_memset(self->slot, 0, c_sizeof(struct chash_slot)*self->bucket_count); } #ifdef _i_ismap @@ -359,7 +359,7 @@ _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr) { intptr_t _cap = self->bucket_count; intptr_t _idx = fastrange_2(_hash, _cap); _cx_result b = {NULL, true, (uint8_t)(_hash | 0x80)}; - const chash_slot* s = self->slot; + const struct chash_slot* s = self->slot; while (s[_idx].hashx) { if (s[_idx].hashx == b.hashx) { const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + _idx)); @@ -394,8 +394,8 @@ _cx_MEMB(_clone)(_cx_Self m) { if (m.data) { _cx_value *d = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count), *_dst = d, *_end = m.data + m.bucket_count; - const intptr_t _mem = c_sizeof(chash_slot)*(m.bucket_count + 1); - chash_slot *s = (chash_slot *)c_memcpy(i_malloc(_mem), m.slot, _mem); + const intptr_t _mem = c_sizeof(struct chash_slot)*(m.bucket_count + 1); + struct chash_slot *s = (struct chash_slot *)c_memcpy(i_malloc(_mem), m.slot, _mem); if (!(d && s)) { i_free(d), i_free(s), d = 0, s = 0, m.bucket_count = 0; } else @@ -417,14 +417,14 @@ _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) { _newbucks = cnextpow2(_newbucks); _cx_Self m = { (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), - (chash_slot *)i_calloc(_newbucks + 1, sizeof(chash_slot)), + (struct chash_slot *)i_calloc(_newbucks + 1, sizeof(struct chash_slot)), self->size, _newbucks }; bool ok = m.data && m.slot; if (ok) { // Rehash: m.slot[_newbucks].hashx = 0xff; const _cx_value* d = self->data; - const chash_slot* s = self->slot; + const struct chash_slot* s = self->slot; for (intptr_t i = 0; i < _oldbucks; ++i, ++d) if ((s++)->hashx) { _cx_keyraw r = i_keyto(_i_keyref(d)); _cx_result b = _cx_MEMB(_bucket_)(&m, &r); @@ -441,7 +441,7 @@ _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) { STC_DEF void _cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* _val) { _cx_value* d = self->data; - chash_slot* s = self->slot; + struct chash_slot* s = self->slot; intptr_t i = _val - d, j = i, k; const intptr_t _cap = self->bucket_count; _cx_MEMB(_value_drop)(_val); diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h index 0e592bae..cecd4002 100644 --- a/include/stc/coroutine.h +++ b/include/stc/coroutine.h @@ -38,7 +38,7 @@ int iterpair(struct iterpair* I) { for (I->y = 0; I->y < I->max_y; I->y++) cco_yield(); - cco_cleanup: // required if there is cleanup code + cco_final: // required if there is cleanup code puts("final"); } return 0; // CCO_DONE @@ -103,7 +103,8 @@ typedef enum { /* cco_blocking_call(): assumes coroutine returns a cco_result value (int) */ #define cco_blocking_call(corocall) while ((corocall) != CCO_DONE) -#define cco_cleanup \ +#define cco_cleanup cco_final // [deprecated] +#define cco_final \ *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP #define cco_return \ diff --git a/include/stc/forward.h b/include/stc/forward.h index 085205cf..572a319f 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -107,8 +107,6 @@ typedef union { SELF##_node *last; \ } SELF -typedef struct chash_slot chash_slot; - #define _c_chash_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \ typedef KEY SELF##_key; \ typedef VAL SELF##_mapped; \ @@ -125,12 +123,12 @@ typedef struct chash_slot chash_slot; \ typedef struct { \ SELF##_value *ref, *_end; \ - chash_slot* sref; \ + struct chash_slot* sref; \ } SELF##_iter; \ \ typedef struct SELF { \ SELF##_value* data; \ - chash_slot* slot; \ + struct chash_slot* slot; \ intptr_t size, bucket_count; \ } SELF diff --git a/include/stc/priv/cqueue_hdr.h b/include/stc/priv/cqueue_hdr.h index 90539f36..1cad8684 100644 --- a/include/stc/priv/cqueue_hdr.h +++ b/include/stc/priv/cqueue_hdr.h @@ -96,8 +96,8 @@ STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { return c_LITERAL(_cx_iter){ - _cx_MEMB(_empty)(self) ? NULL : self->data + self->start, - self->start, self + .ref=_cx_MEMB(_empty)(self) ? NULL : self->data + self->start, + .pos=self->start, ._s=self }; } diff --git a/misc/examples/coroutines/coread.c b/misc/examples/coroutines/coread.c index 359ca85d..6d3acdd7 100644 --- a/misc/examples/coroutines/coread.c +++ b/misc/examples/coroutines/coread.c @@ -21,7 +21,7 @@ int file_read(struct file_read* g) cco_await(!cstr_getline(&g->line, g->fp)); - cco_cleanup: + cco_final: printf("finish\n"); cstr_drop(&g->line); if (g->fp) fclose(g->fp); diff --git a/misc/examples/coroutines/coroutines.c b/misc/examples/coroutines/coroutines.c index faeb71f6..802a976a 100644 --- a/misc/examples/coroutines/coroutines.c +++ b/misc/examples/coroutines/coroutines.c @@ -34,7 +34,7 @@ int prime(struct prime* g) { cco_yield(); } } - cco_cleanup: + cco_final: printf("final prm\n"); } return 0; @@ -68,7 +68,7 @@ int fibonacci(struct fibonacci* g) { } cco_yield(); } - cco_cleanup: + cco_final: printf("final fib\n"); } return 0; @@ -92,7 +92,7 @@ int combined(struct combined* g) { cco_reset(&g->prm); cco_await_call(prime(&g->prm)); - cco_cleanup: + cco_final: puts("final combined"); } return 0; diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c index 230bd62b..7df4eb34 100644 --- a/misc/examples/coroutines/cotasks1.c +++ b/misc/examples/coroutines/cotasks1.c @@ -52,7 +52,7 @@ int produce_items(struct produce_items* p) printf("produced %s\n", cstr_str(&p->str)); cco_yield(); } - cco_cleanup: + cco_final: cstr_drop(&p->str); puts("done produce"); } @@ -76,7 +76,7 @@ int consume_items(struct consume_items* c, struct produce_items* p) print_time(); printf("consumed %s\n", cstr_str(&p->str)); } - cco_cleanup: + cco_final: puts("done consume"); } return 0; diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c index d77a28bc..f6257a7e 100644 --- a/misc/examples/coroutines/cotasks2.c +++ b/misc/examples/coroutines/cotasks2.c @@ -53,7 +53,7 @@ int produce_items(struct produce_items* p, cco_runtime* rt) cco_yield(); } - cco_cleanup: + cco_final: cstr_drop(&p->str); puts("done produce"); } @@ -80,7 +80,7 @@ int consume_items(struct consume_items* c, cco_runtime* rt) printf("consumed %s\n", cstr_str(&c->produce.str)); } - cco_cleanup: + cco_final: cco_stop(&c->produce); cco_resume_task(&c->produce, rt); puts("done consume"); diff --git a/misc/examples/coroutines/dining_philosophers.c b/misc/examples/coroutines/dining_philosophers.c index e917c303..d353b3b9 100644 --- a/misc/examples/coroutines/dining_philosophers.c +++ b/misc/examples/coroutines/dining_philosophers.c @@ -48,7 +48,7 @@ int philosopher(struct Philosopher* p) cco_sem_release(p->right_fork); } - cco_cleanup: + cco_final: printf("Philosopher %d finished\n", p->id); } return 0; @@ -76,7 +76,7 @@ int dining(struct Dining* d) cco_yield(); // suspend, return control back to main } - cco_cleanup: + cco_final: for (int i = 0; i < num_philosophers; ++i) { cco_stop(&d->ph[i]); philosopher(&d->ph[i]); diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c index 0607442d..74388359 100644 --- a/misc/examples/coroutines/filetask.c +++ b/misc/examples/coroutines/filetask.c @@ -28,7 +28,7 @@ int file_read(struct file_read* co, cco_runtime* rt) cco_yield(); } - cco_cleanup: + cco_final: fclose(co->fp); cstr_drop(&co->line); puts("done file_read"); @@ -56,7 +56,7 @@ int count_line(struct count_line* co, cco_runtime* rt) cco_yield(); } - cco_cleanup: + cco_final: cstr_drop(&co->path); puts("done count_line"); } diff --git a/misc/examples/coroutines/generator.c b/misc/examples/coroutines/generator.c index 3f51ce9c..96498498 100644 --- a/misc/examples/coroutines/generator.c +++ b/misc/examples/coroutines/generator.c @@ -2,12 +2,15 @@ #include #include +#include typedef struct { - int size; + int max_triples; int a, b, c; } Triple; +// Create an iterable generator over Triple with count items. +// Requires coroutine Triple_next() and function Triple_begin() to be defined. cco_iter_struct(Triple, int count; ); @@ -20,16 +23,15 @@ int Triple_next(Triple_iter* it) { for (g->a = 1; g->a < g->c; ++g->a) { for (g->b = g->a; g->b < g->c; ++g->b) { if (g->a*g->a + g->b*g->b == g->c*g->c) { - if (it->count++ == g->size) + if (it->count++ == g->max_triples) cco_return; cco_yield(); } } } } - cco_cleanup: - it->ref = NULL; - puts("done"); + cco_final: + it->ref = NULL; // stop the iterator } return 0; } @@ -43,12 +45,22 @@ Triple_iter Triple_begin(Triple* g) { int main(void) { - puts("Pythagorean triples; stops at 100 triples or c >= 100:"); - Triple triple = {.size=100}; + puts("Pythagorean triples.\nGet max 200 triples with c < 50:"); + Triple triple = {.max_triples=200}; + c_foreach (i, Triple, triple) { - if (i.ref->c < 100) + if (i.ref->c < 50) printf("%u: (%d, %d, %d)\n", i.count, i.ref->a, i.ref->b, i.ref->c); else cco_stop(&i); } + + puts("\nGet the 10 first triples with odd a's and a <= 20:"); + c_forfilter (i, Triple, triple, + i.ref->a <= 20 && + (i.ref->a & 1) && + c_flt_take(i, 10) + ){ + printf("%d: (%d, %d, %d)\n", c_flt_getcount(i), i.ref->a, i.ref->b, i.ref->c); + } } diff --git a/misc/examples/coroutines/triples.c b/misc/examples/coroutines/triples.c index 22914c2b..d6ce2791 100644 --- a/misc/examples/coroutines/triples.c +++ b/misc/examples/coroutines/triples.c @@ -40,7 +40,7 @@ int triples_coro(struct triples* t) { } } } - cco_cleanup: + cco_final: puts("done"); } return 0; -- cgit v1.2.3 From 97898812b4c0185db74fc5c94c7556ecef3fb1e3 Mon Sep 17 00:00:00 2001 From: tylov Date: Wed, 9 Aug 2023 09:35:36 +0200 Subject: Bench scripts update --- misc/benchmarks/plotbench/run_all.bat | 4 +--- misc/benchmarks/plotbench/run_clang.sh | 10 +++++----- misc/benchmarks/plotbench/run_vc.bat | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/misc/benchmarks/plotbench/run_all.bat b/misc/benchmarks/plotbench/run_all.bat index 23a62eed..de380531 100644 --- a/misc/benchmarks/plotbench/run_all.bat +++ b/misc/benchmarks/plotbench/run_all.bat @@ -1,7 +1,5 @@ -set out=plot_win.csv +@set out=plot_win.csv echo Compiler,Library,C,Method,Seconds,Ratio> %out% -echo gcc sh run_gcc.sh >> %out% -echo clang sh run_clang.sh >> %out% call run_vc.bat >> %out% diff --git a/misc/benchmarks/plotbench/run_clang.sh b/misc/benchmarks/plotbench/run_clang.sh index fc3e90ec..4f649cbc 100644 --- a/misc/benchmarks/plotbench/run_clang.sh +++ b/misc/benchmarks/plotbench/run_clang.sh @@ -1,10 +1,10 @@ exe='' if [ "$OS" = "Windows_NT" ] ; then exe=".exe" ; fi -clang++ -DNDEBUG -I../../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp -clang++ -DNDEBUG -I../../include -O3 -o clist_benchmark$exe clist_benchmark.cpp -clang++ -DNDEBUG -I../../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp -clang++ -DNDEBUG -I../../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp -clang++ -DNDEBUG -I../../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp +clang -DNDEBUG -I../../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp -lstdc++ +clang -DNDEBUG -I../../include -O3 -o clist_benchmark$exe clist_benchmark.cpp -lstdc++ +clang -DNDEBUG -I../../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp -lstdc++ +clang -DNDEBUG -I../../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp -lstdc++ +clang -DNDEBUG -I../../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp -lstdc++ c='Win-Clang-16.0.5' ./cdeq_benchmark$exe $c diff --git a/misc/benchmarks/plotbench/run_vc.bat b/misc/benchmarks/plotbench/run_vc.bat index a162fb64..c00d059b 100644 --- a/misc/benchmarks/plotbench/run_vc.bat +++ b/misc/benchmarks/plotbench/run_vc.bat @@ -1,6 +1,6 @@ @echo off -if "%VSINSTALLDIR%"=="" call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" >nul +if "%VSINSTALLDIR%"=="" call "C:\Program Files (x86)\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" >nul cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cdeq_benchmark.cpp >nul cl.exe -nologo -EHsc -std:c++latest -I../include -O2 clist_benchmark.cpp >nul cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cmap_benchmark.cpp >nul -- cgit v1.2.3 From be5651c9fc3d3ecd2d9d24e6e4763260ef86de41 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 10 Aug 2023 21:17:48 +0200 Subject: Update template.h - also renamed i_cmp_native => i_use_cmp --- README.md | 4 +- docs/carc_api.md | 2 +- docs/cbox_api.md | 2 +- docs/cdeq_api.md | 2 +- docs/clist_api.md | 2 +- docs/cvec_api.md | 4 +- include/stc/carc.h | 64 ++++++++++++--------------- include/stc/cbox.h | 65 ++++++++++++---------------- include/stc/ccommon.h | 2 +- include/stc/priv/template.h | 29 ++++++------- include/stc/priv/template2.h | 2 +- misc/examples/linkedlists/intrusive.c | 2 +- misc/examples/linkedlists/list.c | 2 +- misc/examples/linkedlists/new_list.c | 2 +- misc/examples/mixed/astar.c | 1 - misc/examples/mixed/complex.c | 1 - misc/examples/mixed/demos.c | 3 +- misc/examples/smartpointers/arc_containers.c | 4 +- misc/examples/smartpointers/arc_demo.c | 3 +- misc/examples/smartpointers/arcvec_erase.c | 3 +- misc/examples/smartpointers/box.c | 1 + misc/examples/smartpointers/box2.c | 1 - misc/examples/smartpointers/music_arc.c | 4 +- misc/examples/smartpointers/new_sptr.c | 3 +- misc/examples/smartpointers/person_arc.c | 3 +- misc/examples/sortedmaps/csmap_insert.c | 1 - misc/examples/sortedmaps/multimap.c | 1 + misc/examples/vectors/lower_bound.c | 2 +- 28 files changed, 99 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 69c51417..48ccdd6f 100644 --- a/README.md +++ b/README.md @@ -251,7 +251,7 @@ struct Point { float x, y; }; #include // cvec_pnt: vector of struct Point #define i_key int -#define i_cmp_native // enable sort/search. Use native `<` and `==` operators +#define i_use_cmp // enable sort/search. Use native `<` and `==` operators #include // clist_int: singly linked list #define i_key int @@ -658,7 +658,7 @@ STC is generally very memory efficient. Memory usage for the different container - Removed deprecated . Use `` with the new API. - Reverted names _unif and _norm back to `_uniform` and `_normal`. - Removed default comparison for **clist**, **cvec** and **cdeq**: - - Define `i_cmp_native` to enable comparison for built-in i_key types (<, ==). + - Define `i_use_cmp` to enable comparison for built-in i_key types (<, ==). - Use of `i_keyclass` still expects comparison functions to be defined. - Use of `i_keyboxed` compares stored pointers instead of pointed to values if comparison not defined. - Renamed input enum flags for ***cregex***-functions. diff --git a/docs/carc_api.md b/docs/carc_api.md index fb79019a..3e394378 100644 --- a/docs/carc_api.md +++ b/docs/carc_api.md @@ -25,7 +25,7 @@ See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory #define i_cmp // three-way compareison. REQUIRED IF i_key is a non-integral type // Note that containers of carcs will "inherit" i_cmp // when using carc in containers with i_valboxed MyArc - ie. the i_type. -#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type. #define i_keydrop // destroy element func - defaults to empty destruct #define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. diff --git a/docs/cbox_api.md b/docs/cbox_api.md index 0e6fca64..c683d9ef 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -19,7 +19,7 @@ See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory #define i_cmp // three-way compareison. REQUIRED IF i_key is a non-integral type // Note that containers of carcs will "inherit" i_cmp // when using carc in containers with i_valboxed MyArc - ie. the i_type. -#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type. #define i_keydrop // destroy element func - defaults to empty destruct #define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index c544f213..3ce58e78 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -13,7 +13,7 @@ See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque #define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. #define i_type // cdeq container type name #define i_cmp // three-way compare of two i_keyraw*. -#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type. #define i_keydrop // destroy value func - defaults to empty destruct #define i_keyclone // REQUIRED IF i_keydrop is defined diff --git a/docs/clist_api.md b/docs/clist_api.md index d8d614c2..a24d813b 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -25,7 +25,7 @@ See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list) #define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. #define i_type // clist container type name #define i_cmp // three-way compare two i_keyraw* -#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type. #define i_keydrop // destroy value func - defaults to empty destruct #define i_keyclone // REQUIRED IF i_keydrop defined diff --git a/docs/cvec_api.md b/docs/cvec_api.md index 3f827df6..8997ed51 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -15,7 +15,7 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect #define i_type // container type name #define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. #define i_cmp // three-way compare two i_keyraw* -#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type. #define i_keydrop // destroy value func - defaults to empty destruct #define i_keyclone // REQUIRED IF i_keydrop defined @@ -224,4 +224,4 @@ int main(void) { c_drop(UVec, &vec, &vec2); // cleanup } -``` \ No newline at end of file +``` diff --git a/include/stc/carc.h b/include/stc/carc.h index 9ba2ddd1..e1dfe14e 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -176,50 +176,40 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { *self = ptr; } -#if defined _i_has_cmp +#if defined i_use_cmp STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); - } -#else - STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) - { return c_default_cmp(&rx, &ry); } - - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - return c_default_cmp(&self->get, &other->get); - } -#endif -#if defined _i_has_eq || defined _i_has_cmp STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } - - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); - } -#else - STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return rx == ry; } - - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - return self->get == other->get; - } -#endif -#if defined i_hash + #ifndef i_no_hash STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } - - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } -#else - STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) - { return c_default_hash(&rx); } - - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { return c_default_hash(&self->get); } + #endif // i_no_hash + + #if defined i_ptr_cmp + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } + #else + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_cmp((&rx), (&ry)); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_eq((&rx), (&ry)); + } + #ifndef i_no_hash + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } + #endif // i_no_hash + #endif // i_ptr_cmp #endif #undef _i_atomic_inc diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 25d41b92..b799c24c 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -159,50 +159,41 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) { moved->get = NULL; } -#if defined _i_has_cmp +#if defined i_use_cmp STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); - } -#else - STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) - { return c_default_cmp(&rx, &ry); } - - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - return c_default_cmp(&self->get, &other->get); - } -#endif -#if defined _i_has_eq || defined _i_has_cmp STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } - - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); - } -#else - STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return rx == ry; } - - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - return self->get == other->get; - } -#endif -#if defined i_hash + #ifndef i_no_hash STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } - - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } -#else - STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) - { return c_default_hash(&rx); } - - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { return c_default_hash(&self->get); } + #endif // i_no_hash + + #if defined i_ptr_cmp + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } + #else + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_cmp((&rx), (&ry)); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_eq((&rx), (&ry)); + } + #ifndef i_no_hash + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } + #endif // i_no_hash + #endif // i_ptr_cmp #endif + #include "priv/template2.h" #undef _i_cbox diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 2528b94f..b37ad1da 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -117,7 +117,7 @@ typedef long long _llong; #define c_no_clone (1<<2) #define c_no_emplace (1<<3) #define c_no_cmp (1<<4) -#define c_native_cmp (1<<5) +#define c_use_cmp (1<<5) #define c_no_hash (1<<6) /* Function macros and others */ diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 49b4d8da..fae9093e 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -102,8 +102,8 @@ #if c_option(c_no_emplace) #define i_no_emplace #endif -#if c_option(c_native_cmp) - #define i_cmp_native +#if c_option(c_use_cmp) || defined _i_ismap || defined _i_isset || defined _i_ispque + #define i_use_cmp #endif #if c_option(c_no_clone) || defined _i_carc #define i_no_clone @@ -127,7 +127,7 @@ #elif defined i_keyboxed #define i_keyclass i_keyboxed #define i_rawclass c_PASTE(i_keyboxed, _raw) - #ifndef i_no_cmp + #if !defined i_no_cmp && defined i_use_cmp #define i_eq c_PASTE(i_keyboxed, _raw_eq) #endif #endif @@ -138,7 +138,7 @@ #define i_rawclass i_key #endif -#ifdef i_keyclass +#if defined i_keyclass #define i_key i_keyclass #ifndef i_keyclone #define i_keyclone c_PASTE(i_key, _clone) @@ -154,8 +154,8 @@ #endif #endif -#ifdef i_rawclass - #if !(defined i_cmp || defined i_no_cmp) +#if defined i_rawclass && defined i_use_cmp + #if !(defined i_cmp || defined i_less || defined i_no_cmp) #define i_cmp c_PASTE(i_keyraw, _cmp) #endif #if !(defined i_hash || defined i_no_hash || defined i_no_cmp) @@ -171,26 +171,29 @@ #endif #endif -#ifndef i_no_cmp - #if defined i_cmp || defined i_less || defined i_cmp_native +#if !defined i_no_cmp + #if defined i_cmp || defined i_less || defined i_use_cmp #define _i_has_cmp #endif - #if defined i_eq || defined i_cmp_native + #if defined i_eq || defined i_use_cmp #define _i_has_eq #endif #endif +#if !(defined i_hash || defined i_no_hash || defined i_no_cmp) + #define i_hash c_default_hash +#endif #if !defined i_key #error "No i_key or i_val defined" #elif defined i_keyraw ^ defined i_keyto #error "Both i_keyraw/i_valraw and i_keyto/i_valto must be defined, if any" #elif !defined i_no_clone && (defined i_keyclone ^ defined i_keydrop) - #error "Both i_keyclone/i_valclone and i_keydrop/i_valdrop must be defined, if any" + #error "Both i_keyclone/i_valclone and i_keydrop/i_valdrop must be defined, if any (unless i_no_clone defined)." #elif defined i_from || defined i_drop #error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead" #elif defined i_keyraw && defined _i_ishash && !(defined i_hash && (defined _i_has_cmp || defined i_eq)) #error "For cmap/cset, both i_hash and i_eq (or i_less or i_cmp) must be defined when i_keyraw is defined." -#elif defined i_keyraw && (defined _i_ismap || defined _i_isset || defined _i_ispque) && !defined _i_has_cmp +#elif defined i_keyraw && defined i_use_cmp && !defined _i_has_cmp #error "For csmap/csset/cpque, i_cmp or i_less must be defined when i_keyraw is defined." #endif @@ -234,10 +237,6 @@ #endif #endif -#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_cmp_native) - #define i_hash c_default_hash -#endif - #if defined _i_ismap // ---- process cmap/csmap value i_val, ... ---- #ifdef i_val_str diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 351defde..1e0d4a2e 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -67,7 +67,7 @@ #undef i_realloc #undef i_free -#undef i_cmp_native +#undef i_use_cmp #undef i_no_cmp #undef i_no_hash #undef i_no_clone diff --git a/misc/examples/linkedlists/intrusive.c b/misc/examples/linkedlists/intrusive.c index c7402d09..edb072c7 100644 --- a/misc/examples/linkedlists/intrusive.c +++ b/misc/examples/linkedlists/intrusive.c @@ -4,7 +4,7 @@ #define i_type List #define i_key int -#define i_cmp_native +#define i_use_cmp #include void printList(List list) { diff --git a/misc/examples/linkedlists/list.c b/misc/examples/linkedlists/list.c index 518cc09b..e83dc6b2 100644 --- a/misc/examples/linkedlists/list.c +++ b/misc/examples/linkedlists/list.c @@ -5,7 +5,7 @@ #define i_type DList #define i_key double -#define i_cmp_native +#define i_use_cmp #include int main(void) { diff --git a/misc/examples/linkedlists/new_list.c b/misc/examples/linkedlists/new_list.c index 2112bf1f..7518929a 100644 --- a/misc/examples/linkedlists/new_list.c +++ b/misc/examples/linkedlists/new_list.c @@ -27,7 +27,7 @@ int point_cmp(const Point* a, const Point* b) { #include #define i_key float -#define i_cmp_native // use < and == operators for comparison +#define i_use_cmp // use < and == operators for comparison #include void MyStruct_drop(MyStruct* s); diff --git a/misc/examples/mixed/astar.c b/misc/examples/mixed/astar.c index 590b7952..d15a9ed7 100644 --- a/misc/examples/mixed/astar.c +++ b/misc/examples/mixed/astar.c @@ -61,7 +61,6 @@ point_key_cmp(const point* a, const point* b) #include #define i_key point -#define i_opt c_no_cmp #include #define i_key point diff --git a/misc/examples/mixed/complex.c b/misc/examples/mixed/complex.c index 4eb1574b..9fcbc417 100644 --- a/misc/examples/mixed/complex.c +++ b/misc/examples/mixed/complex.c @@ -14,7 +14,6 @@ #define i_type StackList #define i_keyclass FloatStack // "class" picks up _clone, _drop, _cmp -#define i_opt c_no_cmp // exclude FloatStack_cmp(): not defined #include #define i_type ListMap diff --git a/misc/examples/mixed/demos.c b/misc/examples/mixed/demos.c index 7f5091fd..43c9a7ae 100644 --- a/misc/examples/mixed/demos.c +++ b/misc/examples/mixed/demos.c @@ -53,6 +53,7 @@ void vectordemo1(void) } #define i_key_str +#define i_use_cmp #include void vectordemo2(void) @@ -74,7 +75,7 @@ void vectordemo2(void) #define i_key int #define i_tag ix -#define i_cmp_native +#define i_use_cmp #include void listdemo1(void) diff --git a/misc/examples/smartpointers/arc_containers.c b/misc/examples/smartpointers/arc_containers.c index 6209005d..c2bff56f 100644 --- a/misc/examples/smartpointers/arc_containers.c +++ b/misc/examples/smartpointers/arc_containers.c @@ -12,11 +12,11 @@ #define i_key Map #define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) // no need for atomic ref. count in single thread: -#define i_opt c_no_atomic +#define i_opt c_no_atomic|c_no_cmp #include #define i_type Stack -#define i_keyboxed Arc // define i_keyboxed for carc/cbox value (not i_key) +#define i_keyboxed Arc // use i_keyboxed for carc/cbox key #include #define i_type List diff --git a/misc/examples/smartpointers/arc_demo.c b/misc/examples/smartpointers/arc_demo.c index 929a48a1..a66d84b0 100644 --- a/misc/examples/smartpointers/arc_demo.c +++ b/misc/examples/smartpointers/arc_demo.c @@ -11,13 +11,14 @@ void int_drop(int* x) { #define i_type Arc // set type name to be defined (instead of 'carc_int') #define i_key int #define i_keydrop int_drop // optional, just to display the elements destroyed -#define i_cmp_native // use int comparison (x < y, x == y). +#define i_use_cmp // use int comparison (x < y, x == y). #include // Arc #define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements #include // csset_Arc (like: std::set>) #define i_keyboxed Arc // note: as above. +#define i_use_cmp #include // cvec_Arc (like: std::vector>) int main(void) diff --git a/misc/examples/smartpointers/arcvec_erase.c b/misc/examples/smartpointers/arcvec_erase.c index 9d757533..0526b6a0 100644 --- a/misc/examples/smartpointers/arcvec_erase.c +++ b/misc/examples/smartpointers/arcvec_erase.c @@ -5,11 +5,12 @@ void show_drop(int* x) { printf("drop: %d\n", *x); } #define i_type Arc #define i_key int #define i_keydrop show_drop -#define i_cmp_native // enable sort/search for int type +#define i_use_cmp // enable sort/search for int type #include // Shared pointer to int #define i_type Vec #define i_keyboxed Arc +#define i_use_cmp #include // Vec: cvec diff --git a/misc/examples/smartpointers/box.c b/misc/examples/smartpointers/box.c index 94d126c0..5c8018d4 100644 --- a/misc/examples/smartpointers/box.c +++ b/misc/examples/smartpointers/box.c @@ -30,6 +30,7 @@ void Person_drop(Person* p) { #define i_type PBox #define i_keyclass Person // "class" binds _cmp, _clone, _drop functions. +#define i_use_cmp #include #define i_type Persons diff --git a/misc/examples/smartpointers/box2.c b/misc/examples/smartpointers/box2.c index eaab1c47..9b782c74 100644 --- a/misc/examples/smartpointers/box2.c +++ b/misc/examples/smartpointers/box2.c @@ -22,7 +22,6 @@ typedef struct { // Box in box: #define i_type BoxBoxPoint #define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc! -#define i_no_cmp #include // BoxBoxPoint Point origin(void) { diff --git a/misc/examples/smartpointers/music_arc.c b/misc/examples/smartpointers/music_arc.c index 13d368c3..e9ebbbfe 100644 --- a/misc/examples/smartpointers/music_arc.c +++ b/misc/examples/smartpointers/music_arc.c @@ -23,7 +23,7 @@ void Song_drop(Song* s) { // Define the shared pointer: #define i_type SongArc #define i_keyclass Song -#define i_no_hash // no hash fn for Song, fallback hash pointer to Song. +#define i_opt c_use_cmp|c_no_hash #include // ... and a vector of them @@ -64,4 +64,4 @@ void example3(void) int main(void) { example3(); -} +} \ No newline at end of file diff --git a/misc/examples/smartpointers/new_sptr.c b/misc/examples/smartpointers/new_sptr.c index 3c6fa16c..50e28ae2 100644 --- a/misc/examples/smartpointers/new_sptr.c +++ b/misc/examples/smartpointers/new_sptr.c @@ -10,12 +10,13 @@ uint64_t Person_hash(const Person* p); #define i_type PersonArc #define i_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined. +#define i_use_cmp #include #define i_type IPtr #define i_key int #define i_keydrop(x) printf("drop: %d\n", *x) -#define i_cmp_native +#define i_use_cmp #include #define i_type IPStack diff --git a/misc/examples/smartpointers/person_arc.c b/misc/examples/smartpointers/person_arc.c index 38c883a7..11040cd2 100644 --- a/misc/examples/smartpointers/person_arc.c +++ b/misc/examples/smartpointers/person_arc.c @@ -31,11 +31,12 @@ void Person_drop(Person* p) { #define i_type PSPtr #define i_keyclass Person // ensure Person_drop -#define i_cmp Person_cmp // specify object cmp, instead of ptr cmp for arc. +#define i_use_cmp #include #define i_type Persons #define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop... +#define i_use_cmp #include diff --git a/misc/examples/sortedmaps/csmap_insert.c b/misc/examples/sortedmaps/csmap_insert.c index c9f02891..04b8ddc6 100644 --- a/misc/examples/sortedmaps/csmap_insert.c +++ b/misc/examples/sortedmaps/csmap_insert.c @@ -13,7 +13,6 @@ #include #define i_key csmap_ii_raw -#define i_opt c_no_cmp #define i_tag ii #include diff --git a/misc/examples/sortedmaps/multimap.c b/misc/examples/sortedmaps/multimap.c index 1068a5dc..a4490f91 100644 --- a/misc/examples/sortedmaps/multimap.c +++ b/misc/examples/sortedmaps/multimap.c @@ -41,6 +41,7 @@ void OlympicLoc_drop(OlympicLoc* self); // Create a clist, can be sorted by year. #define i_keyclass OlympicLoc // binds _cmp, _clone and _drop. +#define i_use_cmp #define i_tag OL #include diff --git a/misc/examples/vectors/lower_bound.c b/misc/examples/vectors/lower_bound.c index bea828f2..09cf2008 100644 --- a/misc/examples/vectors/lower_bound.c +++ b/misc/examples/vectors/lower_bound.c @@ -1,7 +1,7 @@ #include #define i_key int -#define i_cmp_native +#define i_use_cmp #include #define i_key int -- cgit v1.2.3 From 4ba846d378481cb74f68456a3ad4d7cd77d92522 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 11 Aug 2023 08:52:50 +0200 Subject: Updated carc, cbox and template.h - simplifications: removed i_no_cmp/c_no_cmp, --- README.md | 9 +++++-- include/stc/carc.h | 49 ++++++++++++++++----------------- include/stc/cbox.h | 50 +++++++++++++++++----------------- include/stc/priv/template.h | 64 ++++++++++++++++++-------------------------- include/stc/priv/template2.h | 1 - 5 files changed, 83 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 48ccdd6f..fbdbd9fc 100644 --- a/README.md +++ b/README.md @@ -194,8 +194,13 @@ int main(void) Floats_drop(&nums); } ``` -For user-defined struct elements, `i_cmp` compare function should be defined because the default `<` and `==` -only works for integral types. *Alternatively, `#define i_opt c_no_cmp` to disable sorting and searching*. Similarily, if an element destructor `i_keydrop` is defined, `i_keyclone` function is required. +Comparison/lookup functions are enabled by default for associative containers and priority queue (cmap, cset, csmap, csset, cpque). To enable it for the remaining containers, define `i_cmp` or `i_less` (and optionally `i_eq`) on the element type. If the element is an integral type, simply define `i_use_cmp` to use `<` and `==` operators for comparisons. + +Note that for `#define i_keyclass Type`, defining `i_use_cmp` means that *Type_cmp()* function is expected to exist (along with *Type_clone()* and *Type_drop()*). + +To summarize, `i_use_cmp` is only needed to enable comparison (sort/search) functions when defining cstack, cvec, cqueue, cdeq, carc, cbox. With built-in types, it enables the comparison operators, whereas for keyclass types, it binds comparison to its Type_cmp() function. + +If an element destructor `i_keydrop` is defined, `i_keyclone` function is required. *Alternatively `#define i_opt c_no_clone` to disable container cloning.* Let's make a vector of vectors, which can be cloned. All of its element vectors will be destroyed when destroying the Vec2D. diff --git a/include/stc/carc.h b/include/stc/carc.h index e1dfe14e..e987f453 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -180,37 +180,38 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_cmp((&rx), (&ry)); + } + STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } + + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_eq((&rx), (&ry)); + } + #ifndef i_no_hash STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } + + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } #endif // i_no_hash - #if defined i_ptr_cmp - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - return c_default_cmp(&self->get, &other->get); - } - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - return self->get == other->get; - } - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { return c_default_hash(&self->get); } - #else - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); - } - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); - } - #ifndef i_no_hash - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } - #endif // i_no_hash - #endif // i_ptr_cmp -#endif +#else + + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } +#endif // i_use_cmp #undef _i_atomic_inc #undef _i_atomic_dec_and_test diff --git a/include/stc/cbox.h b/include/stc/cbox.h index b799c24c..37daa69e 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -44,7 +44,6 @@ void Person_drop(Person* p) { #define i_type PBox #define i_valclass Person // bind Person clone+drop fn's -#define i_no_cmp // no cmp/hash is defined #include int main(void) { @@ -163,37 +162,38 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) { STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_cmp((&rx), (&ry)); + } + STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } + + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_eq((&rx), (&ry)); + } + #ifndef i_no_hash STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } + + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } #endif // i_no_hash - #if defined i_ptr_cmp - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - return c_default_cmp(&self->get, &other->get); - } - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - return self->get == other->get; - } - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { return c_default_hash(&self->get); } - #else - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); - } - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); - } - #ifndef i_no_hash - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } - #endif // i_no_hash - #endif // i_ptr_cmp -#endif +#else + + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } +#endif // i_use_cmp #include "priv/template2.h" #undef _i_cbox diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index fae9093e..3b8a5b39 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -93,9 +93,6 @@ #if c_option(c_is_forward) #define i_is_forward #endif -#if c_option(c_no_cmp) - #define i_no_cmp -#endif #if c_option(c_no_hash) #define i_no_hash #endif @@ -127,7 +124,7 @@ #elif defined i_keyboxed #define i_keyclass i_keyboxed #define i_rawclass c_PASTE(i_keyboxed, _raw) - #if !defined i_no_cmp && defined i_use_cmp + #if defined i_use_cmp #define i_eq c_PASTE(i_keyboxed, _raw_eq) #endif #endif @@ -152,34 +149,27 @@ #ifndef i_keydrop #define i_keydrop c_PASTE(i_key, _drop) #endif + #if !defined i_keyraw && (defined i_cmp || defined i_less || defined i_eq || defined i_hash) + #define i_use_cmp + #endif #endif #if defined i_rawclass && defined i_use_cmp - #if !(defined i_cmp || defined i_less || defined i_no_cmp) + #if !(defined i_cmp || defined i_less) #define i_cmp c_PASTE(i_keyraw, _cmp) #endif - #if !(defined i_hash || defined i_no_hash || defined i_no_cmp) + #if !(defined i_hash || defined i_no_hash) #define i_hash c_PASTE(i_keyraw, _hash) #endif #endif -#if !defined i_keyraw && !defined i_no_clone - #if !defined i_keyfrom && defined i_keyclone - #define i_keyfrom i_keyclone - #elif !defined i_keyclone && defined i_keyfrom - #define i_keyclone i_keyfrom - #endif +#if defined i_cmp || defined i_less || defined i_use_cmp + #define _i_has_cmp #endif - -#if !defined i_no_cmp - #if defined i_cmp || defined i_less || defined i_use_cmp - #define _i_has_cmp - #endif - #if defined i_eq || defined i_use_cmp - #define _i_has_eq - #endif +#if defined i_eq || defined i_use_cmp + #define _i_has_eq #endif -#if !(defined i_hash || defined i_no_hash || defined i_no_cmp) +#if !(defined i_hash || defined i_no_hash) #define i_hash c_default_hash #endif @@ -218,23 +208,21 @@ #define i_keydrop c_default_drop #endif -#ifndef i_no_cmp - // i_eq, i_less, i_cmp - #if !defined i_eq && (defined i_cmp || defined i_less) - #define i_eq(x, y) !(i_cmp(x, y)) - #elif !defined i_eq - #define i_eq(x, y) *x == *y - #endif - #if defined i_cmp && defined i_less - #error "Only one of i_cmp and i_less may be defined" - #elif defined i_cmp - #define i_less(x, y) (i_cmp(x, y)) < 0 - #elif !defined i_less - #define i_less(x, y) *x < *y - #endif - #ifndef i_cmp - #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y)) - #endif +// i_eq, i_less, i_cmp +#if !defined i_eq && (defined i_cmp || defined i_less) + #define i_eq(x, y) !(i_cmp(x, y)) +#elif !defined i_eq + #define i_eq(x, y) *x == *y +#endif +#if defined i_cmp && defined i_less + #error "Only one of i_cmp and i_less may be defined" +#elif defined i_cmp + #define i_less(x, y) (i_cmp(x, y)) < 0 +#elif !defined i_less + #define i_less(x, y) *x < *y +#endif +#ifndef i_cmp + #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y)) #endif #if defined _i_ismap // ---- process cmap/csmap value i_val, ... ---- diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 1e0d4a2e..44254601 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -68,7 +68,6 @@ #undef i_free #undef i_use_cmp -#undef i_no_cmp #undef i_no_hash #undef i_no_clone #undef i_no_emplace -- cgit v1.2.3 From 3f9337aad678508f25ea83bcd4f5e5b95e69902c Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 11 Aug 2023 09:04:15 +0200 Subject: Minor change to cvec_push() --- include/stc/cvec.h | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/include/stc/cvec.h b/include/stc/cvec.h index e2b8fe97..dc16e94a 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -82,7 +82,6 @@ STC_API void _cx_MEMB(_drop)(_cx_Self* self); STC_API void _cx_MEMB(_clear)(_cx_Self* self); STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t cap); STC_API bool _cx_MEMB(_resize)(_cx_Self* self, intptr_t size, i_key null); -STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); STC_API _cx_iter _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n); STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n); #if defined _i_has_eq || defined _i_has_cmp @@ -94,6 +93,15 @@ STC_API _cx_iter _cx_MEMB(_binary_search_in)(_cx_iter it1, _cx_iter it2, #endif STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } +STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value) { + if (self->_len == self->_cap) + if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + 4)) + return NULL; + _cx_value *v = self->data + self->_len++; + *v = value; + return v; +} + #if !defined i_no_emplace STC_API _cx_iter _cx_MEMB(_emplace_n)(_cx_Self* self, intptr_t idx, const _cx_raw raw[], intptr_t n); @@ -313,16 +321,6 @@ _cx_MEMB(_resize)(_cx_Self* self, const intptr_t len, i_key null) { return true; } -STC_DEF _cx_value* -_cx_MEMB(_push)(_cx_Self* self, i_key value) { - if (self->_len == self->_cap) - if (!_cx_MEMB(_reserve)(self, self->_len*2 + 4)) - return NULL; - _cx_value *v = self->data + self->_len++; - *v = value; - return v; -} - STC_DEF _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, const intptr_t idx, const intptr_t n) { if (self->_len + n > self->_cap) -- cgit v1.2.3 From 0c29a8413619870f23682b74c032137e81db17e2 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Fri, 11 Aug 2023 16:04:52 +0200 Subject: Minor internals. --- include/stc/coroutine.h | 21 ++++++++++++--------- include/stc/priv/template.h | 24 ++++++++---------------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h index cecd4002..5f06e7b8 100644 --- a/include/stc/coroutine.h +++ b/include/stc/coroutine.h @@ -131,16 +131,19 @@ typedef enum { (void)((co)->cco_state = 0) /* - * Generators + * Iterator (for generators) + * User define: Gen must be an existing typedef struct: + * Gen_iter Gen_begin(Gen* g); // function + * int Gen_next(Gen_iter* it); // coroutine */ -#define cco_iter_struct(Name, ...) \ - typedef Name Name##_value; \ - typedef struct { \ - Name##_value* ref; \ +#define cco_iter_struct(Gen, ...) \ + typedef Gen Gen##_value; \ + typedef struct Gen##_iter { \ + Gen##_value* ref; \ int cco_state; \ __VA_ARGS__ \ - } Name##_iter + } Gen##_iter /* * Tasks @@ -148,9 +151,9 @@ typedef enum { struct cco_runtime; -#define cco_task_struct(Name, ...) \ - struct Name { \ - int (*cco_func)(struct Name*, struct cco_runtime*); \ +#define cco_task_struct(Task, ...) \ + struct Task { \ + int (*cco_func)(struct Task*, struct cco_runtime*); \ int cco_state, cco_expect; \ __VA_ARGS__ \ } diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 3b8a5b39..65dee203 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -140,14 +140,14 @@ #ifndef i_keyclone #define i_keyclone c_PASTE(i_key, _clone) #endif - #if !defined i_keyto && defined i_keyraw - #define i_keyto c_PASTE(i_key, _toraw) + #ifndef i_keydrop + #define i_keydrop c_PASTE(i_key, _drop) #endif #if !defined i_keyfrom && defined i_keyraw #define i_keyfrom c_PASTE(i_key, _from) #endif - #ifndef i_keydrop - #define i_keydrop c_PASTE(i_key, _drop) + #if !defined i_keyto && defined i_keyraw + #define i_keyto c_PASTE(i_key, _toraw) #endif #if !defined i_keyraw && (defined i_cmp || defined i_less || defined i_eq || defined i_hash) #define i_use_cmp @@ -245,22 +245,14 @@ #ifndef i_valclone #define i_valclone c_PASTE(i_val, _clone) #endif - #if !defined i_valto && defined i_valraw - #define i_valto c_PASTE(i_val, _toraw) + #ifndef i_valdrop + #define i_valdrop c_PASTE(i_val, _drop) #endif #if !defined i_valfrom && defined i_valraw #define i_valfrom c_PASTE(i_val, _from) #endif - #ifndef i_valdrop - #define i_valdrop c_PASTE(i_val, _drop) - #endif -#endif - -#if !defined i_valraw && !defined i_no_clone - #if !defined i_valfrom && defined i_valclone - #define i_valfrom i_valclone - #elif !defined i_valclone && defined i_valfrom - #define i_valclone i_valfrom + #if !defined i_valto && defined i_valraw + #define i_valto c_PASTE(i_val, _toraw) #endif #endif -- cgit v1.2.3 From 31ba4b2a36dee10b7e5d58561a2c0291cff6faeb Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 11 Aug 2023 22:43:59 +0200 Subject: Finalized converting to i_use_cmp (vs i_no_cmp) --- README.md | 10 ++++------ docs/cbox_api.md | 2 +- include/stc/carc.h | 9 ++++++--- include/stc/ccommon.h | 3 +-- misc/examples/smartpointers/arc_containers.c | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index fbdbd9fc..722d2559 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,6 @@ Let's make a vector of vectors, which can be cloned. All of its element vectors #define i_type Vec2D #define i_keyclass Vec // Use i_keyclass instead i_key when element type has "members" _clone(), _drop() and _cmp(). -#define i_opt c_no_cmp // Disable cmp (search/sort) for Vec2D because Vec_cmp() does not exist. #include int main(void) @@ -370,14 +369,14 @@ The list of template parameters: - `i_key` *Type* - Element key type. **[required]**. Note: `i_val` *may* be used instead for non-maps (not recommended). - `i_val` *Type* - Element value type. **[required for]** cmap/csmap as the mapped value type. -- `i_cmp` *Func* - Three-way comparison of two *i_keyraw*\* or *i_valraw*\* - **[required for]** non-integral *i_keyraw* elements unless *i_opt* is defined with *c_no_cmp*. +- `i_cmp` *Func* - Three-way comparison of two *i_keyraw*\* or *i_valraw*\* - **[required for]** non-integral *i_keyraw* elements. - `i_hash` *Func* - Hash function taking *i_keyraw*\* - defaults to *c_default_hash*. **[required for]** ***cmap/cset*** with non-POD *i_keyraw* elements. - `i_eq` *Func* - Equality comparison of two *i_keyraw*\* - defaults to *!i_cmp*. Companion with *i_hash*. Properties: - `i_tag` *Name* - Container type name tag. Defaults to *i_key* name. - `i_type` *Name* - Full container type name. Alternative to *i_tag*. -- `i_opt` *Flags* - Boolean properties: may combine *c_no_cmp*, *c_no_clone*, *c_no_atomic*, *c_is_forward*, *c_static*, *c_header* with the *|* separator. +- `i_opt` *Flags* - Boolean properties: may combine *c_no_clone*, *c_no_atomic*, *c_is_forward*, *c_static*, *c_header* with the *|* separator. Key: - `i_keydrop` *Func* - Destroy map/set key func - defaults to empty destructor. @@ -398,7 +397,7 @@ Specials: Meta-template parameters. Use instead of `i_key` / `i_val`. If `i_keyraw` is defined, it sets `i_keyto` = *Type_toraw()* and `i_keyfrom` = *Type_from()*. Only functions required by the container type is required to be defined. E.g.: - *Type_hash()* and *Type_eq()* are only required by **cmap**, **cset** and smart pointers. - - *Type_cmp()* is not used by **cstack** and **cmap/cset**, or if *#define i_opt c_no_cmp* is specified. + - *Type_cmp()* is not used by **cstack** and **cmap/cset**. - *Type_clone()* is not used if *#define i_opt c_no_clone* is specified. - `i_key_str` - Sets `i_keyclass` = *cstr*, `i_tag` = *str*, and `i_keyraw` = *const char*\*. Defines both type convertion `i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *const char\*\** as argument. @@ -409,7 +408,6 @@ NB: Do not use when defining carc/cbox types themselves. - `i_valclass` *Type*, `i_val_str`, `i_val_ssv`, `i_valboxed` - Similar rules as for ***key***. **Notes**: -- Instead of defining `i_cmp`, you may define *i_opt c_no_cmp* to disable *searching and sorting* functions. - Instead of defining `i_*clone`, you may define *i_opt c_no_clone* to disable *clone* functionality. - For `i_keyclass`, if *i_keyraw* is defined along with it, *i_keyfrom* may also be defined to enable the *emplace*-functions. NB: the signature for ***cmp***, ***eq***, and ***hash*** uses *i_keyraw* as input. @@ -764,6 +762,6 @@ Major changes: - Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`. - Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly. - Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions. -- Added: `i_opt` template parameter: compile-time options: `c_no_cmp`, `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` +- Added: `i_opt` template parameter: compile-time options: `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` - Added: [**cbox**](docs/cbox_api.md) type: smart pointer, similar to [Rust Box](https://doc.rust-lang.org/rust-by-example/std/box.html) and [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr). - Added: [**c_forpair**](docs/algorithm_api.md) macro: for-loop with "structured binding" diff --git a/docs/cbox_api.md b/docs/cbox_api.md index c683d9ef..7d25aed8 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -34,7 +34,7 @@ See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. -Define `i_opt` with `c_no_cmp` if comparison between i_key's is not needed/available. Will then +Unless `c_use_cmp` is defined, comparison between i_key's is not needed/available. Will then compare the pointer addresses when used. Additionally, `c_no_clone` or `i_is_fwd` may be defined. ## Methods diff --git a/include/stc/carc.h b/include/stc/carc.h index e987f453..1b1c22eb 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -43,7 +43,6 @@ void Person_drop(Person* p) { #define i_type ArcPers #define i_valclass Person // clone, drop, cmp, hash -#define i_opt c_no_cmp|c_no_hash // exclude cmp, hash #include int main(void) { @@ -86,7 +85,10 @@ int main(void) { #include "priv/template.h" typedef i_keyraw _cx_raw; -#if !c_option(c_no_atomic) +#if c_option(c_no_atomic) + #define i_no_atomic +#endif +#if !defined i_no_atomic #define _i_atomic_inc(v) c_atomic_inc(v) #define _i_atomic_dec_and_test(v) c_atomic_dec_and_test(v) #else @@ -213,7 +215,8 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { { return c_default_hash(&self->get); } #endif // i_use_cmp +#include "priv/template2.h" +#undef i_no_atomic #undef _i_atomic_inc #undef _i_atomic_dec_and_test -#include "priv/template2.h" #undef _i_carc diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index b37ad1da..45fa01c6 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -116,9 +116,8 @@ typedef long long _llong; #define c_no_atomic (1<<1) #define c_no_clone (1<<2) #define c_no_emplace (1<<3) -#define c_no_cmp (1<<4) +#define c_no_hash (1<<4) #define c_use_cmp (1<<5) -#define c_no_hash (1<<6) /* Function macros and others */ #define c_litstrlen(literal) (c_sizeof("" literal) - 1) diff --git a/misc/examples/smartpointers/arc_containers.c b/misc/examples/smartpointers/arc_containers.c index c2bff56f..79211d2b 100644 --- a/misc/examples/smartpointers/arc_containers.c +++ b/misc/examples/smartpointers/arc_containers.c @@ -12,7 +12,7 @@ #define i_key Map #define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) // no need for atomic ref. count in single thread: -#define i_opt c_no_atomic|c_no_cmp +#define i_opt c_no_atomic #include #define i_type Stack -- cgit v1.2.3 From ea878349e94ef00643b2510045f6482385cff1a7 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 11 Aug 2023 23:11:01 +0200 Subject: Updated godbolt code. --- README.md | 2 +- docs/algorithm_api.md | 2 +- docs/coroutine_api.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 722d2559..d516f389 100644 --- a/README.md +++ b/README.md @@ -240,7 +240,7 @@ int main(void) ``` This example uses four different container types: -[ [Run this code](https://godbolt.org/z/qor16Gf6j) ] +[ [Run this code](https://godbolt.org/z/j68od14hv) ] ```c #include diff --git a/docs/algorithm_api.md b/docs/algorithm_api.md index 127aa120..63bced22 100644 --- a/docs/algorithm_api.md +++ b/docs/algorithm_api.md @@ -128,7 +128,7 @@ Iterate a container or a crange with chained `&&` filtering. | `c_flt_counter(it)` | Increment current and return count | | `c_flt_getcount(it)` | Number of items passed skip*/take*/counter | -[ [Run this example](https://godbolt.org/z/n9aYrYPv8) ] +[ [Run this example](https://godbolt.org/z/exqYEK6qa) ] ```c #include #include diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md index 6bd558f2..f7d81a34 100644 --- a/docs/coroutine_api.md +++ b/docs/coroutine_api.md @@ -78,7 +78,7 @@ yield or await from a (deeply) nested coroutine call using cco_task objects desc The first example is a generator of Pythagorian triples, and stops when diagonal size > max_c. -[ [Run this code](https://godbolt.org/z/3Efn17cP6) ] +[ [Run this code](https://godbolt.org/z/d5zW3f9Gv) ] ```c #include #include @@ -126,7 +126,7 @@ The next variant skips the triples which are upscaled version of smaller ones by the gcd() function. Note that the gcd1_triples struct contains the triples struct so that both functions have separate call frames: -[ [Run this code](https://godbolt.org/z/ndhMq1haj) ] +[ [Run this code](https://godbolt.org/z/a7da9M8P5) ] ```c int gcd(int a, int b) { // greatest common denominator while (b) { -- cgit v1.2.3 From 1802558d41112e99d965000c97c45ebf7984d70c Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 13 Aug 2023 14:14:25 +0200 Subject: Fixed cqueue.h: cqueue_X_copy() was not defined inside a `c_no_clone` check. Reverted to 2X expansion for cvec to compete with gcc speed. --- include/stc/cvec.h | 14 +++++++------- include/stc/priv/cqueue_hdr.h | 11 +++++------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/stc/cvec.h b/include/stc/cvec.h index dc16e94a..12cd6875 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -94,13 +94,13 @@ STC_API _cx_iter _cx_MEMB(_binary_search_in)(_cx_iter it1, _cx_iter it2, STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value) { - if (self->_len == self->_cap) - if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + 4)) - return NULL; - _cx_value *v = self->data + self->_len++; - *v = value; - return v; -} + if (self->_len == self->_cap) + if (!_cx_MEMB(_reserve)(self, self->_len*2 + 4)) + return NULL; + _cx_value *v = self->data + self->_len++; + *v = value; + return v; + } #if !defined i_no_emplace STC_API _cx_iter diff --git a/include/stc/priv/cqueue_hdr.h b/include/stc/priv/cqueue_hdr.h index 1cad8684..06f3bd74 100644 --- a/include/stc/priv/cqueue_hdr.h +++ b/include/stc/priv/cqueue_hdr.h @@ -59,6 +59,11 @@ STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* othe STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val) { return i_keyclone(val); } +STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { + if (self->data == other->data) return; + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); + } #endif // !i_no_clone STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) { return _cdeq_toidx(self, self->end); } @@ -88,12 +93,6 @@ STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { // move front out of queu return self->data[s]; } -STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { - if (self->data == other->data) return; - _cx_MEMB(_drop)(self); - *self = _cx_MEMB(_clone)(*other); -} - STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { return c_LITERAL(_cx_iter){ .ref=_cx_MEMB(_empty)(self) ? NULL : self->data + self->start, -- cgit v1.2.3 From 972aa23a674f743c187e82444c2271aaa3e9cd06 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 13 Aug 2023 17:38:10 +0200 Subject: Removed csview_null - use csview_init(). --- docs/csview_api.md | 2 -- include/stc/csview.h | 8 +++----- misc/examples/coroutines/cotasks1.c | 2 +- misc/examples/coroutines/cotasks2.c | 2 +- misc/examples/coroutines/filetask.c | 2 +- src/cregex.c | 6 +++--- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/docs/csview_api.md b/docs/csview_api.md index 79a5c07b..49e4f9d1 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -29,7 +29,6 @@ All csview definitions and prototypes are available by including a single header ```c csview c_sv(const char literal_only[]); // construct from literal, no strlen() csview c_sv(const char* str, intptr_t n); // construct from str and length n -csview csview_lit(const char literal_only[]); // alias for c_sv(lit) csview csview_from(const char* str); // construct from const char* csview csview_from_n(const char* str, intptr_t n); // alias for c_sv(str, n) @@ -112,7 +111,6 @@ uint64_t csview_hash(const csview* x); | Name | Value | Usage | |:---------------|:---------------------|:---------------------------------------------| -| `csview_null` | same as `c_sv("")` | `sview = csview_null;` | | `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` | ## Example diff --git a/include/stc/csview.h b/include/stc/csview.h index 85965928..bbf7cd8e 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -27,11 +27,9 @@ #ifndef CSVIEW_H_INCLUDED #define CSVIEW_H_INCLUDED -#define csview_null c_sv_1("") -#define csview_init() csview_null +#define csview_init() c_sv_1("") #define csview_drop(p) c_default_drop(p) #define csview_clone(sv) c_default_clone(sv) -#define csview_lit(literal) c_sv_1(literal) #define csview_from_n(str, n) c_sv_2(str, n) STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); @@ -43,7 +41,7 @@ STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); STC_INLINE csview csview_from(const char* str) { return c_LITERAL(csview){str, c_strlen(str)}; } -STC_INLINE void csview_clear(csview* self) { *self = csview_null; } +STC_INLINE void csview_clear(csview* self) { *self = csview_init(); } STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } @@ -52,7 +50,7 @@ STC_INLINE bool csview_equals(csview sv, const char* str) { intptr_t n = c_strlen(str); return sv.size == n && !c_memcmp(sv.str, str, n); } STC_INLINE intptr_t csview_find(csview sv, const char* str) - { return csview_find_sv(sv, c_sv(str, c_strlen(str))); } + { return csview_find_sv(sv, c_sv_2(str, c_strlen(str))); } STC_INLINE bool csview_contains(csview sv, const char* str) { return csview_find(sv, str) != c_NPOS; } diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c index 7df4eb34..db9632e6 100644 --- a/misc/examples/coroutines/cotasks1.c +++ b/misc/examples/coroutines/cotasks1.c @@ -43,7 +43,7 @@ struct produce_items { int produce_items(struct produce_items* p) { cco_routine (p) { - p->str = cstr_null; + p->str = cstr_init(); while (true) { cco_await(next_value(&p->next) != CCO_AWAIT); diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c index f6257a7e..12c2c4a3 100644 --- a/misc/examples/coroutines/cotasks2.c +++ b/misc/examples/coroutines/cotasks2.c @@ -41,7 +41,7 @@ cco_task_struct (produce_items, int produce_items(struct produce_items* p, cco_runtime* rt) { cco_routine (p) { - p->str = cstr_null; + p->str = cstr_init(); p->next.cco_func = next_value; while (true) { diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c index 74388359..9650cb60 100644 --- a/misc/examples/coroutines/filetask.c +++ b/misc/examples/coroutines/filetask.c @@ -17,7 +17,7 @@ int file_read(struct file_read* co, cco_runtime* rt) { cco_routine (co) { co->fp = fopen(co->path, "r"); - co->line = cstr_null; + co->line = cstr_init(); while (true) { // emulate async io: await 10ms per line diff --git a/src/cregex.c b/src/cregex.c index ac94a5dd..975a5104 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -1220,7 +1220,7 @@ _build_subst(const char* replace, int nmatch, const csview match[], cstr_buf buf = cstr_buffer(subst); intptr_t len = 0, cap = buf.cap; char* dst = buf.data; - cstr mstr = cstr_null; + cstr mstr = cstr_init(); while (*replace != '\0') { if (*replace == '$') { @@ -1293,8 +1293,8 @@ cregex_find_pattern_4(const char* pattern, const char* input, cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, bool (*mfun)(int, csview, cstr*), int rflags) { - cstr out = cstr_null; - cstr subst = cstr_null; + cstr out = cstr_init(); + cstr subst = cstr_init(); csview match[CREG_MAX_CAPTURES]; int nmatch = cregex_captures(re) + 1; if (!count) count = INT32_MAX; -- cgit v1.2.3 From 8bb2f5618e4cefe668a663936354cf53191f2129 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 13 Aug 2023 20:24:55 +0200 Subject: Updated scheduler.c example. --- include/c11/fmt.h | 6 +-- misc/examples/coroutines/scheduler.c | 73 ++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 43 deletions(-) diff --git a/include/c11/fmt.h b/include/c11/fmt.h index d2eab8bc..d7c10cbe 100644 --- a/include/c11/fmt.h +++ b/include/c11/fmt.h @@ -63,8 +63,8 @@ int main(void) { time_t now = time(NULL); struct tm t1 = *localtime(&now), t2 = t1; t2.tm_year += 2; - fmt_print(1, "Dates:\n {}\n {}\n", fmt_tm("%Y-%m-%d %X %Z", &t1), - fmt_tm("%Y-%m-%d %X %Z", &t2)); + fmt_print("Dates:\n {}\n {}\n", fmt_tm("%Y-%m-%d %X %Z", &t1), + fmt_tm("%Y-%m-%d %X %Z", &t2)); } */ #include @@ -208,7 +208,7 @@ void fmt_close(fmt_stream* ss) { } const char* fmt_tm(const char *fmt, const struct tm *tp) { - static char buf[2][64], i = 0; + static char buf[2][64], i = 1; i = !i; strftime(buf[i], 64, fmt, tp); return buf[i]; diff --git a/misc/examples/coroutines/scheduler.c b/misc/examples/coroutines/scheduler.c index 78461277..be1810d2 100644 --- a/misc/examples/coroutines/scheduler.c +++ b/misc/examples/coroutines/scheduler.c @@ -2,70 +2,63 @@ #include #include -struct Task { - int (*fn)(struct Task*); - int cco_state; - struct Scheduler* sched; -}; - -#define i_type Scheduler -#define i_key struct Task +#define i_type cco_tasks +#define i_key cco_task* +#define i_keydrop(x) { puts("free task"); free(*x); } +#define i_no_clone #include -static bool schedule(Scheduler* sched) -{ - struct Task task = *Scheduler_front(sched); - Scheduler_pop(sched); - - if (!cco_done(&task)) - task.fn(&task); - - return !Scheduler_empty(sched); -} +typedef struct { + cco_tasks tasks; +} cco_scheduler; -static int push_task(const struct Task* task) -{ - Scheduler_push(task->sched, *task); - return CCO_YIELD; +void cco_scheduler_drop(cco_scheduler* sched) { + cco_tasks_drop(&sched->tasks); } +int cco_scheduler_run(cco_scheduler* sched) { + while (!cco_tasks_empty(&sched->tasks)) { + cco_task* task = cco_tasks_pull(&sched->tasks); + if (cco_resume_task(task, NULL)) + cco_tasks_push(&sched->tasks, task); + else + cco_tasks_value_drop(&task); + } + return 0; +} -static int taskA(struct Task* task) -{ +static int taskA(cco_task* task, cco_runtime* rt) { cco_routine(task) { puts("Hello, from task A"); - cco_yield_v(push_task(task)); + cco_yield(); puts("A is back doing work"); - cco_yield_v(push_task(task)); + cco_yield(); puts("A is back doing more work"); - cco_yield_v(push_task(task)); + cco_yield(); puts("A is back doing even more work"); } return 0; } -static int taskB(struct Task* task) -{ +static int taskB(cco_task* task, cco_runtime* rt) { cco_routine(task) { puts("Hello, from task B"); - cco_yield_v(push_task(task)); + cco_yield(); puts("B is back doing work"); - cco_yield_v(push_task(task)); + cco_yield(); puts("B is back doing more work"); } return 0; } -void Use(void) -{ - Scheduler scheduler = c_init(Scheduler, { - {.fn=taskA, .sched=&scheduler}, - {.fn=taskB, .sched=&scheduler}, - }); - - while (schedule(&scheduler)) {} +void Use(void) { + cco_scheduler sched = {.tasks = c_init(cco_tasks, { + c_new(cco_task, {.cco_func=taskA}), + c_new(cco_task, {.cco_func=taskB}), + })}; - Scheduler_drop(&scheduler); + cco_scheduler_run(&sched); + cco_scheduler_drop(&sched); } int main(void) -- cgit v1.2.3 From 25dc58db206714dc02c1ae0548f6ba7dd3519d29 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 13 Aug 2023 23:15:45 +0200 Subject: API CHANGES: Changed csview: becomes a null-terminated string view. Added csubview: a null-terminated string view/span, like previous csview. Note that csview works like a csubview, so not much compability issues should arise. However, some functions have changed from _sv suffix to _ss. --- README.md | 30 ++-- docs/cmap_api.md | 2 +- docs/coroutine_api.md | 2 +- docs/cregex_api.md | 28 +-- docs/cstr_api.md | 44 +++-- docs/csubstr_api.md | 217 +++++++++++++++++++++++ docs/csview_api.md | 151 +++------------- include/stc/ccommon.h | 8 +- include/stc/cregex.h | 36 ++-- include/stc/cstr.h | 100 ++++++----- include/stc/csubstr.h | 208 ++++++++++++++++++++++ include/stc/csview.h | 155 ++++------------ include/stc/forward.h | 25 ++- include/stc/priv/template.h | 14 +- include/stc/utf8.h | 4 +- misc/benchmarks/various/string_bench_STC.cpp | 32 ++-- misc/examples/algorithms/forfilter.c | 12 +- misc/examples/regularexpressions/regex2.c | 2 +- misc/examples/regularexpressions/regex_match.c | 4 +- misc/examples/regularexpressions/regex_replace.c | 6 +- misc/examples/strings/cstr_match.c | 12 +- misc/examples/strings/replace.c | 4 +- misc/examples/strings/splitstr.c | 8 +- misc/examples/strings/sso_substr.c | 16 +- misc/examples/strings/sview_split.c | 14 +- misc/examples/strings/utf8replace_c.c | 4 +- misc/tests/cregex_test.c | 32 ++-- src/cregex.c | 28 +-- src/libstc.c | 2 +- src/singleupdate.sh | 2 +- src/utf8code.c | 2 +- 31 files changed, 733 insertions(+), 471 deletions(-) create mode 100644 docs/csubstr_api.md create mode 100644 include/stc/csubstr.h diff --git a/README.md b/README.md index d516f389..96479fa0 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Containers - [***csset*** - **std::set** sorted set alike type](docs/csset_api.md) - [***cstack*** - **std::stack** alike type](docs/cstack_api.md) - [***cstr*** - **std::string** alike type](docs/cstr_api.md) -- [***csview*** - **std::string_view** alike type](docs/csview_api.md) +- [***csubstr*** - **std::string_view** alike type](docs/csubstr_api.md) - [***cspan*** - **std::span/std::mdspan** alike type](docs/cspan_api.md) - [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md) - [***cvec*** - **std::vector** alike type](docs/cvec_api.md) @@ -351,11 +351,11 @@ linking, so *one* c-file must implement the templated container, e.g.: #include "cvec_int.h" ``` The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by -`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so +`#define i_static`. Same for the string-view type **csubstr**, but most of its functions are static inlined, so linking specifications and implementation are only needed for a few lesser used functions. Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**, -**csview**, **cregex**, **utf8**, and **crand**. +**csubstr**, **cregex**, **utf8**, and **crand**. As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent **utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc. @@ -401,8 +401,8 @@ Only functions required by the container type is required to be defined. E.g.: - *Type_clone()* is not used if *#define i_opt c_no_clone* is specified. - `i_key_str` - Sets `i_keyclass` = *cstr*, `i_tag` = *str*, and `i_keyraw` = *const char*\*. Defines both type convertion `i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *const char\*\** as argument. -- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csview\**. Defines both type convertion -`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csview\** as argument. +- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csubstr\**. Defines both type convertion +`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csubstr\** as argument. - `i_keyboxed` *Type* - Use when *Type* is a smart pointer **carc** or **cbox**. Defines *i_keyclass = Type*, and *i_keyraw = Type\**. NB: Do not use when defining carc/cbox types themselves. - `i_valclass` *Type*, `i_val_str`, `i_val_ssv`, `i_valboxed` - Similar rules as for ***key***. @@ -640,7 +640,7 @@ void maptest() STC is generally very memory efficient. Memory usage for the different containers: - **cstr**, **cvec**, **cstack**, **cpque**: 1 pointer, 2 intptr_t + memory for elements. -- **csview**, 1 pointer, 1 intptr_t. Does not own data! +- **csubstr**, 1 pointer, 1 intptr_t. Does not own data! - **cspan**, 1 pointer and 2 \* dimension \* int32_t. Does not own data! - **clist**: Type size: 1 pointer. Each node allocates a struct to store its value and a next pointer. - **cdeq**, **cqueue**: Type size: 2 pointers, 2 intptr_t. Otherwise like *cvec*. @@ -654,7 +654,7 @@ STC is generally very memory efficient. Memory usage for the different container ## Version 4.3 - Breaking changes: - - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. + - **cstr** and **csubstr** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. - Renamed => `` - Moved => `` - Much improved with some new API and added features. @@ -686,7 +686,7 @@ STC is generally very memory efficient. Memory usage for the different container - Renamed c_flt_count(i) => `c_flt_counter(i)` - Renamed c_flt_last(i) => `c_flt_getcount(i)` - Renamed c_ARRAYLEN() => c_arraylen() -- Removed deprecated c_ARGSV(). Use c_SV() +- Removed deprecated c_ARGSV(). Use c_SS() - Removed c_PAIR ## Version 4.1.1 @@ -699,7 +699,7 @@ Major changes: - [crange](docs/algorithm_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - [c_forfilter](docs/algorithm_api.md#c_forfilter) - ranges-like view filtering. - [csort](include/stc/algo/sort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. -- Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. +- Renamed `c_ARGSV()` => `c_SS()`: **csubstr** print arg. Note `c_ss()` is shorthand for *csubstr_from()*. - Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. - Some API changes in **cregex** and **cstr**. - Create single header container versions with python script. @@ -713,18 +713,18 @@ Major changes: - New + renamed loop iteration/scope macros: - `c_forlist`: macro replacing `c_forarray` and `c_apply`. Iterate a compound literal list. - `c_forrange`: macro replacing `c_forrange`. Iterate a `long long` type number sequence. -- Updated **cstr**, now always takes self as pointer, like all containers except csview. +- Updated **cstr**, now always takes self as pointer, like all containers except csubstr. - Updated **cvec**, **cdeq**, changed `*_range*` function names. ## Changes version 3.8 -- Overhauled some **cstr** and **csview** API: +- Overhauled some **cstr** and **csubstr** API: - Changed cstr_replace*() => `cstr_replace_at*(self, pos, len, repl)`: Replace at specific position. - Changed `cstr_replace_all() cstr_replace*(self, search, repl, count)`: Replace count occurences. - Renamed `cstr_find_from()` => `cstr_find_at()` - Renamed `cstr_*_u8()` => `cstr_u8_*()` - - Renamed `csview_*_u8()` => `csview_u8_*()` - - Added cstr_u8_slice() and csview_u8_slice(). - - Removed `csview_from_s()`: Use `cstr_sv(s)` instead. + - Renamed `csubstr_*_u8()` => `csubstr_u8_*()` + - Added cstr_u8_slice() and csubstr_u8_slice(). + - Removed `csubstr_from_s()`: Use `cstr_ss(s)` instead. - Added back file coption.h - Simplified **cbits** usage: all inlined. - Updated docs. @@ -759,7 +759,7 @@ Major changes: - Renamed: *cstr_new()* to `cstr_lit(literal)`, and *cstr_assign_fmt()* to `cstr_printf()`. - Renamed: *c_default_fromraw()* to `c_default_from()`. - Changed: the [**c_apply**](docs/algorithm_api.md) macros API. -- Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`. +- Replaced: *csubstr_first_token()* and *csubstr_next_token()* with one function: `csubstr_token()`. - Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly. - Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions. - Added: `i_opt` template parameter: compile-time options: `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 4e6da57d..65777221 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -282,7 +282,7 @@ typedef struct { cstr country; } Viking; -#define Viking_init() ((Viking){cstr_null, cstr_null}) +#define Viking_init() ((Viking){.name={0}, .country={0}}) static inline int Viking_cmp(const Viking* a, const Viking* b) { int c = cstr_cmp(&a->name, &b->name); diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md index f7d81a34..c44f4a4d 100644 --- a/docs/coroutine_api.md +++ b/docs/coroutine_api.md @@ -237,7 +237,7 @@ cco_task_struct (produce_items, int produce_items(struct produce_items* p, cco_runtime* rt) { cco_routine (p) { - p->str = cstr_null; + p->str = cstr_init(); p->next.cco_func = next_value; while (true) { diff --git a/docs/cregex_api.md b/docs/cregex_api.md index 52476e09..98161fe9 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -33,11 +33,11 @@ int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_ int cregex_captures(const cregex* self); // return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR -int cregex_find(const cregex* re, const char* input, csview match[], int mflags = CREG_DEFAULT); +int cregex_find(const cregex* re, const char* input, csubstr match[], int mflags = CREG_DEFAULT); // Search inside input string-view only -int cregex_find_sv(const cregex* re, csview input, csview match[]); +int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]); // All-in-one search (compile + find + drop) -int cregex_find_pattern(const char* pattern, const char* input, csview match[], int cmflags = CREG_DEFAULT); +int cregex_find_pattern(const char* pattern, const char* input, csubstr match[], int cmflags = CREG_DEFAULT); // Check if there are matches in input bool cregex_is_match(const cregex* re, const char* input); @@ -45,14 +45,14 @@ bool cregex_is_match(const cregex* re, const char* input); // Replace all matches in input cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX); // Replace count matches in input string-view. Optionally transform replacement. -cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX); -cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count, - bool(*transform)(int group, csview match, cstr* result), int rflags); +cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count = INT_MAX); +cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count, + bool(*transform)(int group, csubstr match, cstr* result), int rflags); // All-in-one replacement (compile + find/replace + drop) cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX); cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count, - bool(*transform)(int group, csview match, cstr* result), int rflags); + bool(*transform)(int group, csubstr match, cstr* result), int rflags); // destroy void cregex_drop(cregex* self); ``` @@ -109,9 +109,9 @@ int main(void) { cregex re = cregex_from(pattern); // Lets find the first date in the string: - csview match[4]; // full-match, year, month, date. + csubstr match[4]; // full-match, year, month, date. if (cregex_find(&re, input, match) == CREG_OK) - printf("Found date: %.*s\n", c_SV(match[0])); + printf("Found date: %.*s\n", c_SS(match[0])); else printf("Could not find any date\n"); @@ -127,7 +127,7 @@ int main(void) { For a single match you may use the all-in-one function: ```c if (cregex_find_pattern(pattern, input, match)) - printf("Found date: %.*s\n", c_SV(match[0])); + printf("Found date: %.*s\n", c_SS(match[0])); ``` To use: `gcc first_match.c src/cregex.c src/utf8code.c`. @@ -137,16 +137,16 @@ In order to use a callback function in the replace call, see `examples/regex_rep To iterate multiple matches in an input string, you may use ```c -csview match[5] = {0}; +csubstr match[5] = {0}; while (cregex_find(&re, input, match, CREG_NEXT) == CREG_OK) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SV(match[k])); + printf("submatch %d: %.*s\n", k, c_SS(match[k])); ``` There is also a for-loop macro to simplify it: ```c c_formatch (it, &re, input) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SV(it.match[k])); + printf("submatch %d: %.*s\n", k, c_SS(it.match[k])); ``` ## Using cregex in a project @@ -154,7 +154,7 @@ c_formatch (it, &re, input) The easiest is to `#define i_import` before `#include `. Make sure to do that in one translation unit only. For reference, **cregex** uses the following files: -- `stc/cregex.h`, `stc/utf8.h`, `stc/csview.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` +- `stc/cregex.h`, `stc/utf8.h`, `stc/csubstr.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` - `src/cregex.c`, `src/utf8code.c`. ## Regex Cheatsheet diff --git a/docs/cstr_api.md b/docs/cstr_api.md index dae5669f..36606b76 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -18,11 +18,11 @@ All cstr definitions and prototypes are available by including a single header f ## Methods ```c -cstr cstr_init(void); // constructor; same as cstr_null. +cstr cstr_init(void); // constructor; empty string cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call. cstr cstr_from(const char* str); // constructor using strlen() cstr cstr_from_n(const char* str, intptr_t n); // constructor with n first bytes of str -cstr cstr_from_sv(csview sv); // construct cstr from csview +cstr cstr_from_ss(csubstr sv); // construct cstr from csubstr cstr cstr_with_capacity(intptr_t cap); cstr cstr_with_size(intptr_t len, char fill); // repeat fill len times cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting @@ -34,7 +34,7 @@ void cstr_drop(cstr* self); // destructo const char* cstr_str(const cstr* self); // cast to const char* char* cstr_data(cstr* self); // cast to mutable char* -csview cstr_sv(const cstr* self); // cast to string view +csubstr cstr_ss(const cstr* self); // cast to string view cstr_buf cstr_buffer(cstr* self); // cast to mutable buffer (with capacity) intptr_t cstr_size(const cstr* self); @@ -48,13 +48,13 @@ void cstr_clear(cstr* self); char* cstr_assign(cstr* self, const char* str); char* cstr_assign_n(cstr* self, const char* str, intptr_t n); // assign n first bytes of str -char* cstr_assign_sv(cstr* self, csview sv); +char* cstr_assign_ss(cstr* self, csubstr sv); char* cstr_copy(cstr* self, cstr s); // copy-assign a cstr int cstr_printf(cstr* self, const char* fmt, ...); // source and target must not overlap. char* cstr_append(cstr* self, const char* str); char* cstr_append_n(cstr* self, const char* str, intptr_t n); // append n first bytes of str -char* cstr_append_sv(cstr* self, csview str); +char* cstr_append_ss(cstr* self, csubstr str); char* cstr_append_s(cstr* self, cstr str); int cstr_append_fmt(cstr* self, const char* fmt, ...); // printf() formatting char* cstr_append_uninit(cstr* self, intptr_t len); // return ptr to start of uninited data @@ -63,19 +63,19 @@ void cstr_push(cstr* self, const char* chr); // append on void cstr_pop(cstr* self); // pop one utf8 char void cstr_insert(cstr* self, intptr_t pos, const char* ins); -void cstr_insert_sv(cstr* self, intptr_t pos, csview ins); +void cstr_insert_ss(cstr* self, intptr_t pos, csubstr ins); void cstr_insert_s(cstr* self, intptr_t pos, cstr ins); void cstr_erase(cstr* self, intptr_t pos, intptr_t len); // erase len bytes from pos void cstr_replace(cstr* self, const char* search, const char* repl, unsigned count = MAX_INT); -cstr cstr_replace_sv(csview in, csview search, csview repl, unsigned count); +cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, unsigned count); void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl); // replace at a pos -void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl); +void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl); void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl); bool cstr_equals(const cstr* self, const char* str); -bool cstr_equals_sv(const cstr* self, csview sv); +bool cstr_equals_ss(const cstr* self, csubstr sv); bool cstr_equals_s(const cstr* self, cstr s); intptr_t cstr_find(const cstr* self, const char* search); @@ -83,11 +83,11 @@ intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); // bool cstr_contains(const cstr* self, const char* search); bool cstr_starts_with(const cstr* self, const char* str); -bool cstr_starts_with_sv(const cstr* self, csview sv); +bool cstr_starts_with_ss(const cstr* self, csubstr sv); bool cstr_starts_with_s(const cstr* self, cstr s); bool cstr_ends_with(const cstr* self, const char* str); -bool cstr_ends_with_sv(const cstr* self, csview sv); +bool cstr_ends_with_ss(const cstr* self, csubstr sv); bool cstr_ends_with_s(const cstr* self, cstr s); bool cstr_getline(cstr *self, FILE *stream); // cstr_getdelim(self, '\n', stream) @@ -100,8 +100,8 @@ intptr_t cstr_u8_size(const cstr* self); // number of intptr_t cstr_u8_size_n(const cstr self, intptr_t nbytes); // utf8 size within n bytes intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx); // byte pos offset at utf8 codepoint index const char* cstr_u8_at(const cstr* self, intptr_t u8idx); // char* position at utf8 codepoint index -csview cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csview -void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl); // replace u8len utf8 chars +csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csubstr +void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl); // replace u8len utf8 chars void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); // erase u8len codepoints from pos // iterate utf8 codepoints @@ -112,14 +112,14 @@ cstr_iter cstr_advance(cstr_iter it, intptr_t n); // utf8 functions requires linking with src/utf8code.c symbols: bool cstr_valid_utf8(const cstr* self); // check if str is valid utf8 -cstr cstr_casefold_sv(csview sv); // returns new casefolded utf8 cstr +cstr cstr_casefold_ss(csubstr sv); // returns new casefolded utf8 cstr cstr cstr_tolower(const char* str); // returns new lowercase utf8 cstr -cstr cstr_tolower_sv(csview sv); // returns new lowercase utf8 cstr +cstr cstr_tolower_ss(csubstr sv); // returns new lowercase utf8 cstr void cstr_lowercase(cstr* self); // transform cstr to lowercase utf8 cstr cstr_toupper(const char* str); // returns new uppercase utf8 cstr -cstr cstr_toupper_sv(csview sv); // returns new uppercase utf8 cstr +cstr cstr_toupper_ss(csubstr sv); // returns new uppercase utf8 cstr void cstr_uppercase(cstr* self); // transform cstr to uppercase utf8 int cstr_icmp(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison @@ -132,11 +132,10 @@ Note that all methods with arguments `(..., const char* str, intptr_t n)`, `n` m #### Helper methods: ```c -int cstr_cmp(const cstr* s1, const cstr* s2); -bool cstr_eq(const cstr* s1, const cstr* s2); -bool cstr_hash(const cstr* self); - -char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen); +int cstr_cmp(const cstr* s1, const cstr* s2); +bool cstr_eq(const cstr* s1, const cstr* s2); +bool cstr_hash(const cstr* self); +char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen); ``` ## Types @@ -145,7 +144,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt |:----------------|:---------------------------------------------|:---------------------| | `cstr` | `struct { ... }` | The string type | | `cstr_value` | `char` | String element type | -| `csview` | `struct { const char *str; intptr_t size; }` | String view type | +| `csubstr` | `struct { const char *str; intptr_t size; }` | String view type | | `cstr_buf` | `struct { char *data; intptr_t size, cap; }` | String buffer type | ## Constants and macros @@ -153,7 +152,6 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt | Name | Value | |:------------------|:------------------| | `c_NPOS` | `INTPTR_MAX` | -| `cstr_null` | empty cstr value | ## Example ```c diff --git a/docs/csubstr_api.md b/docs/csubstr_api.md new file mode 100644 index 00000000..925c69db --- /dev/null +++ b/docs/csubstr_api.md @@ -0,0 +1,217 @@ +# STC [csubstr](../include/stc/csubstr.h): String View +![String](pics/string.jpg) + +The type **csubstr** is a string view and can refer to a constant contiguous sequence of char-elements with the first +element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size. + +**csubstr** is non-null terminated, and therefore not a replacent for `const char*` - see [csview](csview_api.md) for +that. **csubstr** never allocates memory, and therefore need not be destructed. +Its lifetime is limited by the source string storage. It keeps the length of the string, and does not need to call +*strlen()* to acquire the length. + +Note: a **csubstr** may ***not be null-terminated***, and must therefore be printed this way: +```c +printf("%.*s", c_SS(sstr)) +``` + +See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional +description. + +## Header file + +All csubstr definitions and prototypes are available by including a single header file. + +```c +#define i_implement +#include +#include // after cstr.h: include extra cstr-csubstr functions +``` +## Methods + +```c +csubstr c_ss(const char literal_only[]); // construct from literal, no strlen() +csubstr c_ss(const char* str, intptr_t n); // construct from str and length n +csubstr csubstr_from(const char* str); // construct from const char* +csubstr csubstr_from_n(const char* str, intptr_t n); // alias for c_ss(str, n) + +intptr_t csubstr_size(csubstr sv); +bool csubstr_empty(csubstr sv); +void csubstr_clear(csubstr* self); + +bool csubstr_equals(csubstr sv, csubstr sv2); +intptr_t csubstr_find(csubstr sv, const char* str); +intptr_t csubstr_find_ss(csubstr sv, csubstr find); +bool csubstr_contains(csubstr sv, const char* str); +bool csubstr_starts_with(csubstr sv, const char* str); +bool csubstr_ends_with(csubstr sv, const char* str); + +csubstr csubstr_substr_ex(csubstr sv, intptr_t pos, intptr_t n); // negative pos count from end +csubstr csubstr_slice_ex(csubstr sv, intptr_t p1, intptr_t p2); // negative p1, p2 count from end +csubstr csubstr_token(csubstr sv, const char* sep, intptr_t* start); // *start > sv.size after last token +``` + +#### UTF8 methods +```c +intptr_t csubstr_u8_size(csubstr sv); +csubstr csubstr_u8_substr(csubstr sv, intptr_t bytepos, intptr_t u8len); +bool csubstr_valid_utf8(csubstr sv); // requires linking with src/utf8code.c + +csubstr_iter csubstr_begin(const csubstr* self); +csubstr_iter csubstr_end(const csubstr* self); +void csubstr_next(csubstr_iter* it); // utf8 codepoint step, not byte! +csubstr_iter csubstr_advance(csubstr_iter it, intptr_t n); +``` + +#### Extended cstr methods +```c +csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n); +csubstr cstr_substr_ex(const cstr* s, intptr_t pos, intptr_t n); // negative pos count from end +csubstr cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); + +csubstr cstr_slice(const cstr* self, intptr_t p1, intptr_t p2); +csubstr cstr_slice_ex(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end +``` +#### Iterate tokens with *c_fortoken*, *c_fortoken_ss* + +To iterate tokens in an input string separated by a string: +```c +c_fortoken (i, "hello, one, two, three", ", ") + printf("token: %.*s\n", c_SS(i.token)); +``` + +#### Helper methods +```c +int csubstr_cmp(const csubstr* x, const csubstr* y); +int csubstr_icmp(const csubstr* x, const csubstr* y); +bool csubstr_eq(const csubstr* x, const csubstr* y); +uint64_t csubstr_hash(const csubstr* x); +``` + +## Types + +| Type name | Type definition | Used to represent... | +|:----------------|:-------------------------------------------|:-------------------------| +| `csubstr` | `struct { const char *str; intptr_t size; }` | The string view type | +| `csubstr_value` | `char` | The string element type | +| `csubstr_iter` | `struct { csubstr_value *ref; }` | UTF8 iterator | + +## Constants and macros + +| Name | Value | Usage | +|:---------------|:---------------------|:---------------------------------------------| +| `c_SS(sv)` | printf argument | `printf("sv: %.*s\n", c_SS(sv));` | + +## Example +```c +#define i_implement +#include +#include + +int main(void) +{ + cstr str1 = cstr_lit("We think in generalities, but we live in details."); + // (quoting Alfred N. Whitehead) + + csubstr sv1 = cstr_substr_ex(&str1, 3, 5); // "think" + intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 + csubstr sv2 = cstr_substr_ex(&str1, pos, 4); // get "live" + csubstr sv3 = cstr_slice_ex(&str1, -8, -1); // get "details" + printf("%.*s %.*s %.*s\n", + c_SS(sv1), c_SS(sv2), c_SS(sv3)); + cstr s1 = cstr_lit("Apples are red"); + cstr s2 = cstr_from_ss(cstr_substr_ex(&s1, -3, 3)); // "red" + cstr s3 = cstr_from_ss(cstr_substr_ex(&s1, 0, 6)); // "Apples" + printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); + + c_drop(cstr, &str1, &s1, &s2, &s3); +} +``` +Output: +``` +think live details +red Apples +``` + +### Example 2: UTF8 handling +```c +#define i_import // include dependent cstr, utf8 and cregex function definitions. +#include + +int main(void) +{ + cstr s1 = cstr_lit("hell😀 w😀rld"); + + cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_ss("ø")); + printf("%s\n", cstr_str(&s1)); + + c_foreach (i, cstr, s1) + printf("%.*s,", c_SS(i.u8.chr)); + + cstr_drop(&s1); +} +``` +Output: +``` +hell😀 wørld +h,e,l,l,😀, ,w,ø,r,l,d, +``` + +### Example 3: csubstr tokenizer (string split) +Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, +and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. +```c +#include +#include + +void print_split(csubstr input, const char* sep) +{ + c_fortoken_ss (i, input, sep) + printf("[%.*s]\n", c_SS(i.token)); + puts(""); +} +#define i_implement +#include +#define i_key_str +#include + +cstack_str string_split(csubstr input, const char* sep) +{ + cstack_str out = cstack_str_init(); + + c_fortoken_ss (i, input, sep) + cstack_str_push(&out, cstr_from_ss(i.token)); + + return out; +} + +int main(void) +{ + print_split(c_ss("//This is a//double-slash//separated//string"), "//"); + print_split(c_ss("This has no matching separator"), "xx"); + + cstack_str s = string_split(c_ss("Split,this,,string,now,"), ","); + + c_foreach (i, cstack_str, s) + printf("[%s]\n", cstr_str(i.ref)); + puts(""); + + cstack_str_drop(&s); +} +``` +Output: +``` +[] +[This is a] +[double-slash] +[separated] +[string] + +[This has no matching separator] + +[Split] +[this] +[] +[string] +[now] +[] +``` diff --git a/docs/csview_api.md b/docs/csview_api.md index 49e4f9d1..4fdff0d1 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -1,19 +1,14 @@ # STC [csview](../include/stc/csview.h): String View ![String](pics/string.jpg) -The type **csview** is a string view and can refer to a constant contiguous sequence of char-elements with the first -element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size. +The type **csview** is a ***null-terminated*** string view and refers to a constant contiguous sequence of +char-elements with the first element of the sequence at position zero. The implementation holds two +members: a pointer to constant char and a size. See [csubstr](csubstr_api.md) for a ***non null-terminated*** +string view/span type. -**csview** is an efficient replacent for `const char*`. It never allocates memory, and therefore need not be destructed. -Its lifetime is limited by the source string storage. It keeps the length of the string, and does not call *strlen()* -when passing it around. It is faster when using`csview` as convertion type (raw) than `const char*` in associative -containers with cstr keys. - -Note: a **csview** may ***not be null-terminated***, and must therefore be printed like: -`printf("%.*s", csview_ARG(sv))`. - -See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional -description. +Because **csview** is null-terminated, it can be a more efficient replacent for `const char*`. It never +allocates memory, and need therefore not be destructed. Its lifetime is limited by the source string +storage. It keeps the length of the string, and does not call *strlen()* when passing it around. ## Header file @@ -42,17 +37,12 @@ intptr_t csview_find_sv(csview sv, csview find); bool csview_contains(csview sv, const char* str); bool csview_starts_with(csview sv, const char* str); bool csview_ends_with(csview sv, const char* str); - -csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); // negative pos count from end -csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); // negative p1, p2 count from end -csview csview_token(csview sv, const char* sep, intptr_t* start); // *start > sv.size after last token ``` #### UTF8 methods ```c intptr_t csview_u8_size(csview sv); -csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len); -bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c +bool csview_valid_utf8(csview sv); // depends on src/utf8code.c csview_iter csview_begin(const csview* self); csview_iter csview_end(const csview* self); @@ -74,27 +64,10 @@ uint32_t utf8_peek(const char* s); // codep uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative) ``` -#### Extended cstr methods -```c -csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n); -csview cstr_substr_ex(const cstr* s, intptr_t pos, intptr_t n); // negative pos count from end -csview cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); - -csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2); -csview cstr_slice_ex(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end -``` -#### Iterate tokens with *c_fortoken*, *c_fortoken_sv* - -To iterate tokens in an input string separated by a string: -```c -c_fortoken (i, "hello, one, two, three", ", ") - printf("token: %.*s\n", c_SV(i.token)); -``` - #### Helper methods ```c int csview_cmp(const csview* x, const csview* y); -int csview_icmp(const csview* x, const csview* y); +int csview_icmp(const csview* x, const csview* y); // depends on src/utf8code.c: bool csview_eq(const csview* x, const csview* y); uint64_t csview_hash(const csview* x); ``` @@ -107,46 +80,36 @@ uint64_t csview_hash(const csview* x); | `csview_value` | `char` | The string element type | | `csview_iter` | `struct { csview_value *ref; }` | UTF8 iterator | -## Constants and macros - -| Name | Value | Usage | -|:---------------|:---------------------|:---------------------------------------------| -| `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` | - -## Example +## Example: UTF8 iteration and case conversion ```c -#define i_implement +#define i_import #include #include int main(void) { - cstr str1 = cstr_lit("We think in generalities, but we live in details."); - // (quoting Alfred N. Whitehead) - - csview sv1 = cstr_substr_ex(&str1, 3, 5); // "think" - intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 - csview sv2 = cstr_substr_ex(&str1, pos, 4); // get "live" - csview sv3 = cstr_slice_ex(&str1, -8, -1); // get "details" - printf("%.*s %.*s %.*s\n", - c_SV(sv1), c_SV(sv2), c_SV(sv3)); - cstr s1 = cstr_lit("Apples are red"); - cstr s2 = cstr_from_sv(cstr_substr_ex(&s1, -3, 3)); // "red" - cstr s3 = cstr_from_sv(cstr_substr_ex(&s1, 0, 6)); // "Apples" - printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); - - c_drop(cstr, &str1, &s1, &s2, &s3); + cstr str = cstr_from("Liberté, égalité, fraternité."); + csview sv = cstr_sv(&str); + + c_foreach (i, csview, sv) + printf("%.*s ", c_SS(i.u8.chr)); + puts(""); + + cstr_uppercase(&str); + printf("%s\n", cstr_str(&str)); + + cstr_drop(&str); } ``` Output: ``` -think live details -red Apples +L i b e r t é , é g a l i t é , f r a t e r n i t é . +LIBERTÉ, ÉGALITÉ, FRATERNITÉ. ``` -### Example 2: UTF8 handling +### Example 2: UTF8 replace ```c -#define i_import // include dependent cstr, utf8 and cregex function definitions. +#define i_import // include dependent utf8 definitions. #include int main(void) @@ -157,7 +120,7 @@ int main(void) printf("%s\n", cstr_str(&s1)); c_foreach (i, cstr, s1) - printf("%.*s,", c_SV(i.u8.chr)); + printf("%.*s,", c_SS(i.u8.chr)); // u8.chr is a csubstr cstr_drop(&s1); } @@ -167,63 +130,3 @@ Output: hell😀 wørld h,e,l,l,😀, ,w,ø,r,l,d, ``` - -### Example 3: csview tokenizer (string split) -Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, -and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. -```c -#include -#include - -void print_split(csview input, const char* sep) -{ - c_fortoken_sv (i, input, sep) - printf("[%.*s]\n", c_SV(i.token)); - puts(""); -} -#define i_implement -#include -#define i_key_str -#include - -cstack_str string_split(csview input, const char* sep) -{ - cstack_str out = cstack_str_init(); - - c_fortoken_sv (i, input, sep) - cstack_str_push(&out, cstr_from_sv(i.token)); - - return out; -} - -int main(void) -{ - print_split(c_sv("//This is a//double-slash//separated//string"), "//"); - print_split(c_sv("This has no matching separator"), "xx"); - - cstack_str s = string_split(c_sv("Split,this,,string,now,"), ","); - - c_foreach (i, cstack_str, s) - printf("[%s]\n", cstr_str(i.ref)); - puts(""); - - cstack_str_drop(&s); -} -``` -Output: -``` -[] -[This is a] -[double-slash] -[separated] -[string] - -[This has no matching separator] - -[Split] -[this] -[] -[string] -[now] -[] -``` diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 45fa01c6..24967a10 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -130,11 +130,15 @@ typedef const char* ccharptr; #define ccharptr_clone(s) (s) #define ccharptr_drop(p) ((void)p) +#define c_ss(...) c_MACRO_OVERLOAD(c_ss, __VA_ARGS__) +#define c_ss_1(literal) c_ss_2(literal, c_litstrlen(literal)) +#define c_ss_2(str, n) (c_LITERAL(csubstr){str, n}) +#define c_SS(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SS(ss)); + #define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) -#define c_sv_1(lit) c_sv_2(lit, c_litstrlen(lit)) +#define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal)) #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) -#define c_SV(sv) (int)(sv).size, (sv).str // print csview: use format "%.*s" #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { diff --git a/include/stc/cregex.h b/include/stc/cregex.h index bce94b04..3aab3c8b 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -34,7 +34,7 @@ THE SOFTWARE. */ #include #include -#include "forward.h" // csview +#include "forward.h" // csubstr #include "ccommon.h" enum { @@ -82,7 +82,7 @@ typedef struct { typedef struct { const cregex* re; const char* input; - csview match[CREG_MAX_CAPTURES]; + csubstr match[CREG_MAX_CAPTURES]; } cregex_iter; #define c_formatch(it, Re, Input) \ @@ -115,11 +115,11 @@ int cregex_captures(const cregex* re); /* return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */ #define cregex_find(...) c_MACRO_OVERLOAD(cregex_find, __VA_ARGS__) #define cregex_find_3(re, input, match) cregex_find_4(re, input, match, CREG_DEFAULT) -int cregex_find_4(const cregex* re, const char* input, csview match[], int mflags); +int cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags); -/* find with csview as input. */ -STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { - csview *mp = NULL; +/* find with csubstr as input. */ +STC_INLINE int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]) { + csubstr *mp = NULL; if (match) { match[0] = input; mp = match; } return cregex_find(re, input.str, mp, CREG_STARTEND); } @@ -129,27 +129,27 @@ STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { #define cregex_find_pattern_3(pattern, input, match) \ cregex_find_pattern_4(pattern, input, match, CREG_DEFAULT) int cregex_find_pattern_4(const char* pattern, const char* input, - csview match[], int cmflags); + csubstr match[], int cmflags); STC_INLINE bool cregex_is_match(const cregex* re, const char* input) { return cregex_find_4(re, input, NULL, CREG_DEFAULT) == CREG_OK; } -/* replace csview input with replace using regular expression pattern */ -#define cregex_replace_sv(...) c_MACRO_OVERLOAD(cregex_replace_sv, __VA_ARGS__) -#define cregex_replace_sv_3(pattern, input, replace) \ - cregex_replace_sv_4(pattern, input, replace, INT32_MAX) -#define cregex_replace_sv_4(pattern, input, replace, count) \ - cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT) -cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, - bool (*transform)(int group, csview match, cstr* result), int rflags); +/* replace csubstr input with replace using regular expression pattern */ +#define cregex_replace_ss(...) c_MACRO_OVERLOAD(cregex_replace_ss, __VA_ARGS__) +#define cregex_replace_ss_3(pattern, input, replace) \ + cregex_replace_ss_4(pattern, input, replace, INT32_MAX) +#define cregex_replace_ss_4(pattern, input, replace, count) \ + cregex_replace_ss_6(pattern, input, replace, count, NULL, CREG_DEFAULT) +cstr cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, + bool (*transform)(int group, csubstr match, cstr* result), int rflags); /* replace input with replace using regular expression */ #define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__) #define cregex_replace_3(re, input, replace) cregex_replace_4(re, input, replace, INT32_MAX) STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char* replace, int count) { - csview sv = {input, c_strlen(input)}; - return cregex_replace_sv_4(re, sv, replace, count); + csubstr ss = {input, c_strlen(input)}; + return cregex_replace_ss_4(re, ss, replace, count); } /* replace + compile RE pattern, and extra arguments */ @@ -159,7 +159,7 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char #define cregex_replace_pattern_4(pattern, input, replace, count) \ cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*transform)(int group, csview match, cstr* result), int crflags); + bool (*transform)(int group, csubstr match, cstr* result), int crflags); /* destroy regex */ void cregex_drop(cregex* re); diff --git a/include/stc/cstr.h b/include/stc/cstr.h index f12d29b6..47cf65da 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -75,7 +75,7 @@ STC_API char* cstr_reserve(cstr* self, intptr_t cap); STC_API void cstr_shrink_to_fit(cstr* self); STC_API char* cstr_resize(cstr* self, intptr_t size, char value); STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); -STC_API intptr_t cstr_find_sv(const cstr* self, csview search); +STC_API intptr_t cstr_find_ss(const cstr* self, csubstr search); STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_uninit(cstr *self, intptr_t len); @@ -85,7 +85,7 @@ STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); STC_API cstr cstr_from_fmt(const char* fmt, ...); STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...); -STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); +STC_API cstr cstr_replace_ss(csubstr sv, csubstr search, csubstr repl, int32_t count); STC_API uint64_t cstr_hash(const cstr *self); STC_INLINE cstr_buf cstr_buffer(cstr* s) { @@ -94,9 +94,11 @@ STC_INLINE cstr_buf cstr_buffer(cstr* s) { : c_LITERAL(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap}; } STC_INLINE csview cstr_sv(const cstr* s) { - return cstr_is_long(s) ? c_LITERAL(csview){s->lon.data, cstr_l_size(s)} - : c_LITERAL(csview){s->sml.data, cstr_s_size(s)}; + return cstr_is_long(s) ? c_sv_2(s->lon.data, cstr_l_size(s)) + : c_sv_2(s->sml.data, cstr_s_size(s)); } +STC_INLINE csubstr cstr_ss(const cstr* s) + { csview sv = cstr_sv(s); return c_ss_2(sv.str, sv.size); } STC_INLINE cstr cstr_init(void) { return cstr_null; } @@ -110,7 +112,10 @@ STC_INLINE cstr cstr_from_n(const char* str, const intptr_t len) { STC_INLINE cstr cstr_from(const char* str) { return cstr_from_n(str, c_strlen(str)); } -STC_INLINE cstr cstr_from_sv(csview sv) +STC_INLINE cstr cstr_from_ss(csubstr sv) + { return cstr_from_n(sv.str, sv.size); } + +STC_INLINE cstr cstr_from_v(csview sv) { return cstr_from_n(sv.str, sv.size); } STC_INLINE cstr cstr_with_size(const intptr_t size, const char value) { @@ -170,9 +175,9 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self) // utf8 methods defined in/depending on src/utf8code.c: -extern cstr cstr_casefold_sv(csview sv); -extern cstr cstr_tolower_sv(csview sv); -extern cstr cstr_toupper_sv(csview sv); +extern cstr cstr_casefold_ss(csubstr sv); +extern cstr cstr_tolower_ss(csubstr sv); +extern cstr cstr_toupper_ss(csubstr sv); extern cstr cstr_tolower(const char* str); extern cstr cstr_toupper(const char* str); extern void cstr_lowercase(cstr* self); @@ -193,9 +198,9 @@ STC_INLINE intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx) STC_INLINE const char* cstr_u8_at(const cstr* self, intptr_t u8idx) { return utf8_at(cstr_str(self), u8idx); } -STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { +STC_INLINE csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx) { const char* str = cstr_str(self); - csview sv; + csubstr sv; sv.str = utf8_at(str, u8idx); sv.size = utf8_chr_size(sv.str); return sv; @@ -205,7 +210,7 @@ STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { STC_INLINE cstr_iter cstr_begin(const cstr* self) { csview sv = cstr_sv(self); - if (!sv.size) return c_LITERAL(cstr_iter){NULL}; + if (!sv.size) return c_LITERAL(cstr_iter){.ref = NULL}; return c_LITERAL(cstr_iter){.u8 = {{sv.str, utf8_chr_size(sv.str)}}}; } STC_INLINE cstr_iter cstr_end(const cstr* self) { @@ -244,6 +249,9 @@ STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { STC_INLINE bool cstr_equals(const cstr* self, const char* str) { return !strcmp(cstr_str(self), str); } +STC_INLINE bool cstr_equals_ss(const cstr* self, csubstr sv) + { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } + STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv) { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } @@ -266,14 +274,14 @@ STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search) STC_INLINE bool cstr_contains(const cstr* self, const char* search) { return strstr((char*)cstr_str(self), search) != NULL; } -STC_INLINE bool cstr_contains_sv(const cstr* self, csview search) - { return cstr_find_sv(self, search) != c_NPOS; } +STC_INLINE bool cstr_contains_ss(const cstr* self, csubstr search) + { return cstr_find_ss(self, search) != c_NPOS; } STC_INLINE bool cstr_contains_s(const cstr* self, cstr search) { return strstr((char*)cstr_str(self), cstr_str(&search)) != NULL; } -STC_INLINE bool cstr_starts_with_sv(const cstr* self, csview sub) { +STC_INLINE bool cstr_starts_with_ss(const cstr* self, csubstr sub) { if (sub.size > cstr_size(self)) return false; return !c_memcmp(cstr_str(self), sub.str, sub.size); } @@ -285,26 +293,26 @@ STC_INLINE bool cstr_starts_with(const cstr* self, const char* sub) { } STC_INLINE bool cstr_starts_with_s(const cstr* self, cstr sub) - { return cstr_starts_with_sv(self, cstr_sv(&sub)); } + { return cstr_starts_with_ss(self, cstr_ss(&sub)); } STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) { - csview sv = cstr_sv(self); + csubstr sv = cstr_ss(self); intptr_t len = c_strlen(sub); - return len <= sv.size && !utf8_icmp_sv(sv, c_sv(sub, len)); + return len <= sv.size && !utf8_icmp_ss(sv, c_ss(sub, len)); } -STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) { +STC_INLINE bool cstr_ends_with_ss(const cstr* self, csubstr sub) { csview sv = cstr_sv(self); if (sub.size > sv.size) return false; return !c_memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); } STC_INLINE bool cstr_ends_with_s(const cstr* self, cstr sub) - { return cstr_ends_with_sv(self, cstr_sv(&sub)); } + { return cstr_ends_with_ss(self, cstr_ss(&sub)); } STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub) - { return cstr_ends_with_sv(self, c_sv(sub, c_strlen(sub))); } + { return cstr_ends_with_ss(self, c_ss(sub, c_strlen(sub))); } STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { csview sv = cstr_sv(self); @@ -316,7 +324,7 @@ STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { STC_INLINE char* cstr_assign(cstr* self, const char* str) { return cstr_assign_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_assign_sv(cstr* self, csview sv) +STC_INLINE char* cstr_assign_ss(cstr* self, csubstr sv) { return cstr_assign_n(self, sv.str, sv.size); } STC_INLINE char* cstr_copy(cstr* self, cstr s) { @@ -338,44 +346,42 @@ STC_INLINE void cstr_pop(cstr* self) { STC_INLINE char* cstr_append(cstr* self, const char* str) { return cstr_append_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_append_sv(cstr* self, csview sv) +STC_INLINE char* cstr_append_ss(cstr* self, csubstr sv) { return cstr_append_n(self, sv.str, sv.size); } STC_INLINE char* cstr_append_s(cstr* self, cstr s) - { return cstr_append_sv(self, cstr_sv(&s)); } + { return cstr_append_ss(self, cstr_ss(&s)); } #define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__) #define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, INT32_MAX) STC_INLINE void cstr_replace_4(cstr* self, const char* search, const char* repl, int32_t count) { - cstr_take(self, cstr_replace_sv(cstr_sv(self), c_sv(search, c_strlen(search)), - c_sv(repl, c_strlen(repl)), count)); + cstr_take(self, cstr_replace_ss(cstr_ss(self), c_ss(search, c_strlen(search)), + c_ss(repl, c_strlen(repl)), count)); } -STC_INLINE void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl) { +STC_INLINE void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl) { char* d = _cstr_internal_move(self, pos + len, pos + repl.size); c_memcpy(d + pos, repl.str, repl.size); } STC_INLINE void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl) - { cstr_replace_at_sv(self, pos, len, c_sv(repl, c_strlen(repl))); } + { cstr_replace_at_ss(self, pos, len, c_ss(repl, c_strlen(repl))); } STC_INLINE void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl) - { cstr_replace_at_sv(self, pos, len, cstr_sv(&repl)); } + { cstr_replace_at_ss(self, pos, len, cstr_ss(&repl)); } -STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl) - { cstr_replace_at_sv(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } +STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl) + { cstr_replace_at_ss(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } STC_INLINE void cstr_insert(cstr* self, intptr_t pos, const char* str) - { cstr_replace_at_sv(self, pos, 0, c_sv(str, c_strlen(str))); } + { cstr_replace_at_ss(self, pos, 0, c_ss(str, c_strlen(str))); } -STC_INLINE void cstr_insert_sv(cstr* self, intptr_t pos, csview sv) - { cstr_replace_at_sv(self, pos, 0, sv); } +STC_INLINE void cstr_insert_ss(cstr* self, intptr_t pos, csubstr sv) + { cstr_replace_at_ss(self, pos, 0, sv); } -STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) { - csview sv = cstr_sv(&s); - cstr_replace_at_sv(self, pos, 0, sv); -} +STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) + { cstr_replace_at_ss(self, pos, 0, cstr_ss(&s)); } STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } @@ -394,7 +400,7 @@ fn_tocase[] = {{tolower, utf8_casefold}, {tolower, utf8_tolower}, {toupper, utf8_toupper}}; -static cstr cstr_tocase(csview sv, int k) { +static cstr cstr_tocase(csubstr sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); const char *end = sv.str + sv.size; @@ -415,26 +421,26 @@ static cstr cstr_tocase(csview sv, int k) { return out; } -cstr cstr_casefold_sv(csview sv) +cstr cstr_casefold_ss(csubstr sv) { return cstr_tocase(sv, 0); } -cstr cstr_tolower_sv(csview sv) +cstr cstr_tolower_ss(csubstr sv) { return cstr_tocase(sv, 1); } -cstr cstr_toupper_sv(csview sv) +cstr cstr_toupper_ss(csubstr sv) { return cstr_tocase(sv, 2); } cstr cstr_tolower(const char* str) - { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } + { return cstr_tolower_ss(c_ss(str, c_strlen(str))); } cstr cstr_toupper(const char* str) - { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } + { return cstr_toupper_ss(c_ss(str, c_strlen(str))); } void cstr_lowercase(cstr* self) - { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } + { cstr_take(self, cstr_tolower_ss(cstr_ss(self))); } void cstr_uppercase(cstr* self) - { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } + { cstr_take(self, cstr_toupper_ss(cstr_ss(self))); } bool cstr_valid_utf8(const cstr* self) { return utf8_valid(cstr_str(self)); } @@ -450,7 +456,7 @@ STC_DEF uint64_t cstr_hash(const cstr *self) { return cfasthash(sv.str, sv.size); } -STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { +STC_DEF intptr_t cstr_find_ss(const cstr* self, csubstr search) { csview sv = cstr_sv(self); char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); return res ? (res - sv.str) : c_NPOS; @@ -580,7 +586,7 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } } -STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { +STC_DEF cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, int32_t count) { cstr out = cstr_null; intptr_t from = 0; char* res; if (!count) count = INT32_MAX; diff --git a/include/stc/csubstr.h b/include/stc/csubstr.h new file mode 100644 index 00000000..152f7041 --- /dev/null +++ b/include/stc/csubstr.h @@ -0,0 +1,208 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#define i_header // external linkage by default. override with i_static. +#define _i_inc_utf8 +#include "utf8.h" + +#ifndef CSUBSTR_H_INCLUDED +#define CSUBSTR_H_INCLUDED + +#define csubstr_init() c_ss_1("") +#define csubstr_drop(p) c_default_drop(p) +#define csubstr_clone(ss) c_default_clone(ss) +#define csubstr_from_n(str, n) c_ss_2(str, n) + +STC_API csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos); +STC_API intptr_t csubstr_find_ss(csubstr ss, csubstr search); +STC_API uint64_t csubstr_hash(const csubstr *self); +STC_API csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2); +STC_API csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n); +STC_API csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start); + +STC_INLINE csubstr csubstr_from(const char* str) + { return c_LITERAL(csubstr){str, c_strlen(str)}; } +STC_INLINE void csubstr_clear(csubstr* self) { *self = csubstr_init(); } +STC_INLINE intptr_t csubstr_size(csubstr ss) { return ss.size; } +STC_INLINE bool csubstr_empty(csubstr ss) { return ss.size == 0; } + +STC_INLINE bool csubstr_equals(csubstr ss, const char* str) + { intptr_t n = c_strlen(str); return ss.size == n && !c_memcmp(ss.str, str, n); } + +STC_INLINE intptr_t csubstr_find(csubstr ss, const char* str) + { return csubstr_find_ss(ss, c_ss_2(str, c_strlen(str))); } + +STC_INLINE bool csubstr_contains(csubstr ss, const char* str) + { return csubstr_find(ss, str) != c_NPOS; } + +STC_INLINE bool csubstr_starts_with(csubstr ss, const char* str) { + intptr_t n = c_strlen(str); + return n > ss.size ? false : !c_memcmp(ss.str, str, n); +} + +STC_INLINE bool csubstr_ends_with(csubstr ss, const char* str) { + intptr_t n = c_strlen(str); + return n > ss.size ? false : !c_memcmp(ss.str + ss.size - n, str, n); +} + +STC_INLINE csubstr csubstr_substr(csubstr ss, intptr_t pos, intptr_t n) { + if (pos + n > ss.size) n = ss.size - pos; + ss.str += pos, ss.size = n; + return ss; +} + +STC_INLINE csubstr csubstr_slice(csubstr ss, intptr_t p1, intptr_t p2) { + if (p2 > ss.size) p2 = ss.size; + ss.str += p1, ss.size = p2 > p1 ? p2 - p1 : 0; + return ss; +} + +/* utf8 iterator */ +STC_INLINE csubstr_iter csubstr_begin(const csubstr* self) { + if (!self->size) return c_LITERAL(csubstr_iter){NULL}; + return c_LITERAL(csubstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, + self->str + self->size}}; +} +STC_INLINE csubstr_iter csubstr_end(const csubstr* self) { + return c_LITERAL(csubstr_iter){.u8 = {{NULL}, self->str + self->size}}; +} +STC_INLINE void csubstr_next(csubstr_iter* it) { + it->ref += it->u8.chr.size; + it->u8.chr.size = utf8_chr_size(it->ref); + if (it->ref == it->u8.end) it->ref = NULL; +} + +/* utf8 */ +STC_INLINE intptr_t csubstr_u8_size(csubstr ss) + { return utf8_size_n(ss.str, ss.size); } + +STC_INLINE csubstr csubstr_u8_substr(csubstr ss, intptr_t bytepos, intptr_t u8len) { + ss.str += bytepos; + ss.size = utf8_pos(ss.str, u8len); + return ss; +} + +STC_INLINE bool csubstr_valid_utf8(csubstr ss) // depends on src/utf8code.c + { return utf8_valid_n(ss.str, ss.size); } + +#define c_fortoken_ss(it, inputss, sep) \ + for (struct { csubstr _inp, token, *ref; const char *_sep; intptr_t pos; } \ + it = {._inp=inputss, .token=it._inp, .ref=&it.token, ._sep=sep} \ + ; it.pos <= it._inp.size && (it.token = csubstr_token(it._inp, it._sep, &it.pos)).str ; ) + +#define c_fortoken(it, input, sep) \ + c_fortoken_ss(it, csubstr_from(input), sep) + +/* ---- Container helper functions ---- */ + +STC_INLINE int csubstr_cmp(const csubstr* x, const csubstr* y) { + intptr_t n = x->size < y->size ? x->size : y->size; + int c = c_memcmp(x->str, y->str, n); + return c ? c : (int)(x->size - y->size); +} + +STC_INLINE int csubstr_icmp(const csubstr* x, const csubstr* y) + { return utf8_icmp_ss(*x, *y); } + +STC_INLINE bool csubstr_eq(const csubstr* x, const csubstr* y) + { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } + +#endif // CSUBSTR_H_INCLUDED + +/* csubstr interaction with cstr: */ +#ifdef CSTR_H_INCLUDED + +STC_INLINE csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n) + { return csubstr_substr(cstr_ss(self), pos, n); } + +STC_INLINE csubstr cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) + { return csubstr_slice(cstr_ss(self), p1, p2); } + +STC_INLINE csubstr cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n) + { return csubstr_substr_ex(cstr_ss(self), pos, n); } + +STC_INLINE csubstr cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) + { return csubstr_slice_ex(cstr_ss(self), p1, p2); } + +STC_INLINE csubstr cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) + { return csubstr_u8_substr(cstr_ss(self), bytepos, u8len); } +#endif + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined i_implement || defined i_static +#ifndef CSUBSTR_C_INCLUDED +#define CSUBSTR_C_INCLUDED + +STC_DEF csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (it.ref == it.u8.end) it.ref = NULL; + return it; +} + +STC_DEF intptr_t csubstr_find_ss(csubstr ss, csubstr search) { + char* res = cstrnstrn(ss.str, search.str, ss.size, search.size); + return res ? (res - ss.str) : c_NPOS; +} + +STC_DEF uint64_t csubstr_hash(const csubstr *self) + { return cfasthash(self->str, self->size); } + +STC_DEF csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n) { + if (pos < 0) { + pos += ss.size; + if (pos < 0) pos = 0; + } + if (pos > ss.size) pos = ss.size; + if (pos + n > ss.size) n = ss.size - pos; + ss.str += pos, ss.size = n; + return ss; +} + +STC_DEF csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2) { + if (p1 < 0) { + p1 += ss.size; + if (p1 < 0) p1 = 0; + } + if (p2 < 0) p2 += ss.size; + if (p2 > ss.size) p2 = ss.size; + ss.str += p1, ss.size = (p2 > p1 ? p2 - p1 : 0); + return ss; +} + +STC_DEF csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start) { + intptr_t sep_size = c_strlen(sep); + csubstr slice = {ss.str + *start, ss.size - *start}; + const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); + csubstr tok = {slice.str, res ? (res - slice.str) : slice.size}; + *start += tok.size + sep_size; + return tok; +} +#endif // CSUBSTR_C_INCLUDED +#endif // i_implement +#undef i_static +#undef i_header +#undef i_implement +#undef i_import +#undef i_opt diff --git a/include/stc/csview.h b/include/stc/csview.h index bbf7cd8e..0d1ca36c 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,7 +20,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#define i_header // external linkage by default. override with i_static. #define _i_inc_utf8 #include "utf8.h" @@ -32,25 +31,26 @@ #define csview_clone(sv) c_default_clone(sv) #define csview_from_n(str, n) c_sv_2(str, n) -STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); -STC_API intptr_t csview_find_sv(csview sv, csview search); -STC_API uint64_t csview_hash(const csview *self); -STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); -STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); -STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); - STC_INLINE csview csview_from(const char* str) - { return c_LITERAL(csview){str, c_strlen(str)}; } + { return csview_from_n(str, c_strlen(str)); } STC_INLINE void csview_clear(csview* self) { *self = csview_init(); } +STC_INLINE csubstr csview_ss(csview sv) { return c_ss_2(sv.str, sv.size); } -STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } +STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } -STC_INLINE bool csview_equals(csview sv, const char* str) - { intptr_t n = c_strlen(str); return sv.size == n && !c_memcmp(sv.str, str, n); } +STC_INLINE bool csview_equals(csview sv, const char* str) { + intptr_t n = c_strlen(str); + return sv.size == n && !c_memcmp(sv.str, str, n); +} + +STC_INLINE intptr_t csview_find_v(csview sv, csview search) { + char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); + return res ? (res - sv.str) : c_NPOS; +} STC_INLINE intptr_t csview_find(csview sv, const char* str) - { return csview_find_sv(sv, c_sv_2(str, c_strlen(str))); } + { return csview_find_v(sv, c_sv_2(str, c_strlen(str))); } STC_INLINE bool csview_contains(csview sv, const char* str) { return csview_find(sv, str) != c_NPOS; } @@ -65,55 +65,40 @@ STC_INLINE bool csview_ends_with(csview sv, const char* str) { return n > sv.size ? false : !c_memcmp(sv.str + sv.size - n, str, n); } -STC_INLINE csview csview_substr(csview sv, intptr_t pos, intptr_t n) { - if (pos + n > sv.size) n = sv.size - pos; - sv.str += pos, sv.size = n; - return sv; -} - -STC_INLINE csview csview_slice(csview sv, intptr_t p1, intptr_t p2) { - if (p2 > sv.size) p2 = sv.size; - sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; - return sv; -} - /* utf8 iterator */ STC_INLINE csview_iter csview_begin(const csview* self) { - if (!self->size) return c_LITERAL(csview_iter){NULL}; - return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, - self->str + self->size}}; + if (!self->size) return c_LITERAL(csview_iter){.ref = NULL}; + return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}}; } STC_INLINE csview_iter csview_end(const csview* self) { - return c_LITERAL(csview_iter){.u8 = {{NULL}, self->str + self->size}}; + (void)self; return c_LITERAL(csview_iter){.ref = NULL}; } STC_INLINE void csview_next(csview_iter* it) { it->ref += it->u8.chr.size; it->u8.chr.size = utf8_chr_size(it->ref); - if (it->ref == it->u8.end) it->ref = NULL; + if (!*it->ref) it->ref = NULL; +} +STC_INLINE csview_iter csview_advance(csview_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (!*it.ref) it.ref = NULL; + return it; } -/* utf8 */ +/* utf8 size */ STC_INLINE intptr_t csview_u8_size(csview sv) { return utf8_size_n(sv.str, sv.size); } -STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) { - sv.str += bytepos; - sv.size = utf8_pos(sv.str, u8len); - return sv; -} - -STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c +/* utf8 validation: depends on src/utf8code.c */ +STC_INLINE bool csview_valid_utf8(csview sv) { return utf8_valid_n(sv.str, sv.size); } -#define c_fortoken_sv(it, inputsv, sep) \ - for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \ - it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \ - ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).str ; ) - -#define c_fortoken(it, input, sep) \ - c_fortoken_sv(it, csview_from(input), sep) +/* utf8 ignore case cmp: depends on src/utf8code.c */ +STC_INLINE int csview_icmp(const csview* x, const csview* y) + { return utf8_icmp_ss(c_ss_2(x->str, x->size), c_ss_2(y->str, y->size)); } -/* ---- Container helper functions ---- */ STC_INLINE int csview_cmp(const csview* x, const csview* y) { intptr_t n = x->size < y->size ? x->size : y->size; @@ -121,87 +106,13 @@ STC_INLINE int csview_cmp(const csview* x, const csview* y) { return c ? c : (int)(x->size - y->size); } -STC_INLINE int csview_icmp(const csview* x, const csview* y) - { return utf8_icmp_sv(*x, *y); } - STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } -#endif // CSVIEW_H_INCLUDED - -/* csview interaction with cstr: */ -#ifdef CSTR_H_INCLUDED - -STC_INLINE csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n) - { return csview_substr(cstr_sv(self), pos, n); } - -STC_INLINE csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) - { return csview_slice(cstr_sv(self), p1, p2); } - -STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n) - { return csview_substr_ex(cstr_sv(self), pos, n); } - -STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) - { return csview_slice_ex(cstr_sv(self), p1, p2); } - -STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) - { return csview_u8_substr(cstr_sv(self), bytepos, u8len); } -#endif - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement || defined i_static -#ifndef CSVIEW_C_INCLUDED -#define CSVIEW_C_INCLUDED - -STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (it.ref == it.u8.end) it.ref = NULL; - return it; -} - -STC_DEF intptr_t csview_find_sv(csview sv, csview search) { - char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); - return res ? (res - sv.str) : c_NPOS; -} - -STC_DEF uint64_t csview_hash(const csview *self) +STC_INLINE uint64_t csview_hash(const csview *self) { return cfasthash(self->str, self->size); } -STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { - if (pos < 0) { - pos += sv.size; - if (pos < 0) pos = 0; - } - if (pos > sv.size) pos = sv.size; - if (pos + n > sv.size) n = sv.size - pos; - sv.str += pos, sv.size = n; - return sv; -} - -STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { - if (p1 < 0) { - p1 += sv.size; - if (p1 < 0) p1 = 0; - } - if (p2 < 0) p2 += sv.size; - if (p2 > sv.size) p2 = sv.size; - sv.str += p1, sv.size = (p2 > p1 ? p2 - p1 : 0); - return sv; -} - -STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { - intptr_t sep_size = c_strlen(sep); - csview slice = {sv.str + *start, sv.size - *start}; - const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); - csview tok = {slice.str, res ? (res - slice.str) : slice.size}; - *start += tok.size + sep_size; - return tok; -} -#endif // CSVIEW_C_INCLUDED -#endif // i_implement +#endif // CSVIEW_H_INCLUDED #undef i_static #undef i_header #undef i_implement diff --git a/include/stc/forward.h b/include/stc/forward.h index 572a319f..5c9c4f4d 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -39,8 +39,21 @@ #define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL) #define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL) -// csview -typedef const char csview_value; +// csubstr : non-null terminated string view +typedef const char csubstr_value; +typedef struct csubstr { + csubstr_value* str; + intptr_t size; +} csubstr; + +typedef union { + csubstr_value* ref; + struct { csubstr chr; csubstr_value* end; } u8; +} csubstr_iter; + + +// csview : null-terminated string view +typedef csubstr_value csview_value; typedef struct csview { csview_value* str; intptr_t size; @@ -48,10 +61,11 @@ typedef struct csview { typedef union { csview_value* ref; - struct { csview chr; csview_value* end; } u8; + struct { csubstr chr; } u8; } csview_iter; -// cstr + +// cstr : null-terminated string (short string optimized - sso) typedef char cstr_value; typedef struct { cstr_value* data; intptr_t size, cap; } cstr_buf; typedef union cstr { @@ -61,9 +75,10 @@ typedef union cstr { typedef union { cstr_value* ref; - struct { csview chr; } u8; + struct { csubstr chr; } u8; } cstr_iter; + #define c_true(...) __VA_ARGS__ #define c_false(...) diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 65dee203..47225ec8 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -114,10 +114,10 @@ #endif #elif defined i_key_ssv #define i_keyclass cstr - #define i_rawclass csview - #define i_keyfrom cstr_from_sv - #define i_keyto cstr_sv - #define i_eq csview_eq + #define i_rawclass csubstr + #define i_keyfrom cstr_from_ss + #define i_keyto cstr_ss + #define i_eq csubstr_eq #ifndef i_tag #define i_tag ssv #endif @@ -232,9 +232,9 @@ #define i_valraw const char* #elif defined i_val_ssv #define i_valclass cstr - #define i_valraw csview - #define i_valfrom cstr_from_sv - #define i_valto cstr_sv + #define i_valraw csubstr + #define i_valfrom cstr_from_ss + #define i_valto cstr_ss #elif defined i_valboxed #define i_valclass i_valboxed #define i_valraw c_PASTE(i_valboxed, _raw) diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 6d12856f..7d2adee0 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -48,7 +48,7 @@ extern uint32_t utf8_toupper(uint32_t c); extern bool utf8_iscased(uint32_t c); extern bool utf8_isword(uint32_t c); extern bool utf8_valid_n(const char* s, intptr_t nbytes); -extern int utf8_icmp_sv(csview s1, csview s2); +extern int utf8_icmp_ss(csubstr s1, csubstr s2); extern int utf8_encode(char *out, uint32_t c); extern uint32_t utf8_peek_off(const char *s, int offset); @@ -92,7 +92,7 @@ STC_INLINE uint32_t utf8_peek(const char* s) { /* case-insensitive utf8 string comparison */ STC_INLINE int utf8_icmp(const char* s1, const char* s2) { - return utf8_icmp_sv(c_sv(s1, INTPTR_MAX), c_sv(s2, INTPTR_MAX)); + return utf8_icmp_ss(c_ss(s1, INTPTR_MAX), c_ss(s2, INTPTR_MAX)); } STC_INLINE bool utf8_valid(const char* s) { diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp index a5dfd901..9173d4b6 100644 --- a/misc/benchmarks/various/string_bench_STC.cpp +++ b/misc/benchmarks/various/string_bench_STC.cpp @@ -7,16 +7,16 @@ #define i_implement #include // string #define i_implement -#include // string_view +#include // string_view #include #define i_key_str #include // vec of cstr with const char* lookup -#define i_type cvec_sv // override default type name (cvec_csview) -#define i_key csview -#define i_cmp csview_cmp -#include // cvec_vs: vec of csview +#define i_type cvec_ss // override default type name (cvec_csubstr) +#define i_key csubstr +#define i_cmp csubstr_cmp +#include // cvec_vs: vec of csubstr #define i_key_str #define i_val size_t @@ -24,7 +24,7 @@ #define i_key_ssv #define i_val size_t -#include // sorted map of cstr, csview lookup +#include // sorted map of cstr, csubstr lookup #define i_key_str #define i_val size_t @@ -32,7 +32,7 @@ #define i_key_ssv #define i_val size_t -#include // unordered map of cstr, csview lookup +#include // unordered map of cstr, csubstr lookup cvec_str read_file(const char* name) @@ -67,7 +67,7 @@ private: std::chrono::high_resolution_clock::time_point begin; }; -void initShortStringVec(cvec_str* vs, cvec_sv* vsv) +void initShortStringVec(cvec_str* vs, cvec_ss* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -101,14 +101,14 @@ void initShortStringVec(cvec_str* vs, cvec_sv* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_sv(i.ref)); + cvec_sv_push_back(vsv, cstr_ss(i.ref)); num += cstr_size(i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; std::cout << "avg str len: " << num / (float)cvec_sv_size(vsv) << std::endl; } -void initLongStringVec(cvec_str* vs, cvec_sv* vsv) +void initLongStringVec(cvec_str* vs, cvec_ss* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -147,7 +147,7 @@ void initLongStringVec(cvec_str* vs, cvec_sv* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_sv(i.ref)); + cvec_sv_push_back(vsv, cstr_ss(i.ref)); num += cstr_size(i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; @@ -175,7 +175,7 @@ void initMaps(const cvec_str* vs, csmap_str* mapTrans, csmap_ssv* mapSview, void benchmark( const cvec_str* vec_string, - const cvec_sv* vec_stringview, + const cvec_ss* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -187,7 +187,7 @@ const size_t MAX_LOOP = 2000; int main(void) { c_auto (cvec_str, vec_string) - c_auto (cvec_sv, vec_stringview) + c_auto (cvec_ss, vec_stringview) c_auto (csmap_str, mapTrans) c_auto (csmap_ssv, mapSview) c_auto (cmap_str, unordmapTrans) @@ -229,7 +229,7 @@ int main(void) void benchmark( const cvec_str* vec_string, - const cvec_sv* vec_stringview, + const cvec_ss* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -258,7 +258,7 @@ void benchmark( stopwatch.start("Trans Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_sv, *vec_stringview) + c_foreach (j, cvec_ss, *vec_stringview) { const csmap_ssv_value* v = csmap_ssv_get(mapSview, *j.ref); if (v) @@ -286,7 +286,7 @@ void benchmark( stopwatch.start("Trans Unord Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_sv, *vec_stringview) + c_foreach (j, cvec_ss, *vec_stringview) { const cmap_ssv_value* v = cmap_ssv_get(unordmapSview, *j.ref); if (v) diff --git a/misc/examples/algorithms/forfilter.c b/misc/examples/algorithms/forfilter.c index c1426045..d058660d 100644 --- a/misc/examples/algorithms/forfilter.c +++ b/misc/examples/algorithms/forfilter.c @@ -2,7 +2,7 @@ #define i_import #include #define i_implement -#include +#include #include #define i_type IVec @@ -82,7 +82,7 @@ fn main() { } */ #define i_type SVec -#define i_keyclass csview +#define i_keyclass csubstr #include void demo3(void) @@ -94,11 +94,11 @@ void demo3(void) SVec words_containing_i = {0}; c_forfilter (w, SVec, words, - csview_contains(*w.ref, "i")) + csubstr_contains(*w.ref, "i")) SVec_push(&words_containing_i, *w.ref); c_foreach (w, SVec, words_containing_i) - printf(" %.*s", c_SV(*w.ref)); + printf(" %.*s", c_SS(*w.ref)); puts(""); c_drop(SVec, &words, &words_containing_i); @@ -107,10 +107,10 @@ void demo3(void) void demo4(void) { // Keep only uppercase letters and convert them to lowercase: - csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte + csubstr s = c_ss("ab123cReAghNGnΩoEp"); // Ω = multi-byte cstr out = {0}; - c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) { + c_forfilter (i, csubstr, s, utf8_isupper(utf8_peek(i.ref))) { char chr[4]; utf8_encode(chr, utf8_tolower(utf8_peek(i.ref))); cstr_push(&out, chr); diff --git a/misc/examples/regularexpressions/regex2.c b/misc/examples/regularexpressions/regex2.c index a798b1a1..85890070 100644 --- a/misc/examples/regularexpressions/regex2.c +++ b/misc/examples/regularexpressions/regex2.c @@ -27,7 +27,7 @@ int main(void) c_formatch (j, &re, s[i].input) { c_forrange (k, cregex_captures(&re) + 1) - printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); + printf(" submatch %lld: %.*s\n", k, c_SS(j.match[k])); } } cregex_drop(&re); diff --git a/misc/examples/regularexpressions/regex_match.c b/misc/examples/regularexpressions/regex_match.c index 11426d2d..6eaea781 100644 --- a/misc/examples/regularexpressions/regex_match.c +++ b/misc/examples/regularexpressions/regex_match.c @@ -1,7 +1,7 @@ #define i_import #include #define i_implement -#include +#include #define i_key float #include @@ -28,7 +28,7 @@ int main(void) printf(" %g\n", (double)*i.ref); // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); + cstr nums = cregex_replace_ss(&re, csubstr_from(str), " $0,", 0, NULL, CREG_STRIP); printf("\n%s\n", cstr_str(&nums)); cstr_drop(&nums); diff --git a/misc/examples/regularexpressions/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c index f1ea2711..f5fd8691 100644 --- a/misc/examples/regularexpressions/regex_replace.c +++ b/misc/examples/regularexpressions/regex_replace.c @@ -1,8 +1,8 @@ #define i_import #include -#include +#include -bool add_10_years(int i, csview match, cstr* out) { +bool add_10_years(int i, csubstr match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -47,7 +47,7 @@ int main(void) printf("euros: %s\n", cstr_str(&str)); /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); printf("strip: %s\n", cstr_str(&str)); /* Wrap all words in ${} */ diff --git a/misc/examples/strings/cstr_match.c b/misc/examples/strings/cstr_match.c index be03e981..3c41bd43 100644 --- a/misc/examples/strings/cstr_match.c +++ b/misc/examples/strings/cstr_match.c @@ -1,11 +1,11 @@ #define i_implement #include -#include +#include #include int main(void) { - cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"); + cstr ss = cstr_from("The quick brown fox jumps over the lazy dog.JPG"); intptr_t pos = cstr_find_at(&ss, 0, "brown"); printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "" : cstr_str(&ss) + pos); @@ -16,11 +16,11 @@ int main(void) printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); cstr s1 = cstr_lit("hell😀 w😀rl🐨"); - csview ch1 = cstr_u8_chr(&s1, 7); - csview ch2 = cstr_u8_chr(&s1, 10); + csubstr ch1 = cstr_u8_chr(&s1, 7); + csubstr ch2 = cstr_u8_chr(&s1, 10); printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); - printf("ch1: %.*s\n", c_SV(ch1)); - printf("ch2: %.*s\n", c_SV(ch2)); + printf("ch1: %.*s\n", c_SS(ch1)); + printf("ch2: %.*s\n", c_SS(ch2)); c_drop(cstr, &ss, &s1); } diff --git a/misc/examples/strings/replace.c b/misc/examples/strings/replace.c index 59a56bf7..2411f1a7 100644 --- a/misc/examples/strings/replace.c +++ b/misc/examples/strings/replace.c @@ -20,13 +20,13 @@ int main(void) cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) printf("(1) %s\n", cstr_str(&s)); - cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) + cstr_replace_at_ss(&s, 19, 6, c_ss(s3+7, 6)); // "this is an example phrase." (2) printf("(2) %s\n", cstr_str(&s)); cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) printf("(3) %s\n", cstr_str(&s)); - cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) + cstr_replace_at_ss(&s, 8, 6, c_ss("a shorty", 7)); // "this is a short phrase." (4) printf("(4) %s\n", cstr_str(&s)); cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) diff --git a/misc/examples/strings/splitstr.c b/misc/examples/strings/splitstr.c index ef7ed174..6fa76d34 100644 --- a/misc/examples/strings/splitstr.c +++ b/misc/examples/strings/splitstr.c @@ -2,20 +2,20 @@ #define i_import // cstr + utf8 functions #include #define i_implement -#include +#include int main(void) { - puts("Split with c_fortoken (csview):"); + puts("Split with c_fortoken (csubstr):"); c_fortoken (i, "Hello World C99!", " ") - printf("'%.*s'\n", c_SV(i.token)); + printf("'%.*s'\n", c_SS(i.token)); puts("\nSplit with c_formatch (regex):"); cregex re = cregex_from("[^ ]+"); c_formatch (i, &re, " Hello World C99! ") - printf("'%.*s'\n", c_SV(i.match[0])); + printf("'%.*s'\n", c_SS(i.match[0])); cregex_drop(&re); } diff --git a/misc/examples/strings/sso_substr.c b/misc/examples/strings/sso_substr.c index 687658df..3c6b1046 100644 --- a/misc/examples/strings/sso_substr.c +++ b/misc/examples/strings/sso_substr.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { cstr str = cstr_lit("We think in generalities, but we live in details."); - csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" - intptr_t pos = cstr_find(&str, "live"); // position of "live" - csview sv2 = cstr_substr_ex(&str, pos, 4); // "live" - csview sv3 = cstr_slice_ex(&str, -8, -1); // "details" - printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); + csubstr sv1 = cstr_substr_ex(&str, 3, 5); // "think" + intptr_t pos = cstr_find(&str, "live"); // position of "live" + csubstr sv2 = cstr_substr_ex(&str, pos, 4); // "live" + csubstr sv3 = cstr_slice_ex(&str, -8, -1); // "details" + printf("%.*s, %.*s, %.*s\n", c_SS(sv1), c_SS(sv2), c_SS(sv3)); cstr_assign(&str, "apples are green or red"); - cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red" - cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples" + cstr s2 = cstr_from_ss(cstr_substr_ex(&str, -3, 3)); // "red" + cstr s3 = cstr_from_ss(cstr_substr_ex(&str, 0, 6)); // "apples" printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), cstr_is_long(&str), cstr_is_long(&s2)); c_drop (cstr, &str, &s2, &s3); diff --git a/misc/examples/strings/sview_split.c b/misc/examples/strings/sview_split.c index ac275da0..6abbf5e7 100644 --- a/misc/examples/strings/sview_split.c +++ b/misc/examples/strings/sview_split.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { // No memory allocations or string length calculations! - const csview date = c_sv("2021/03/12"); + const csubstr date = c_ss("2021/03/12"); intptr_t pos = 0; - const csview year = csview_token(date, "/", &pos); - const csview month = csview_token(date, "/", &pos); - const csview day = csview_token(date, "/", &pos); + const csubstr year = csubstr_token(date, "/", &pos); + const csubstr month = csubstr_token(date, "/", &pos); + const csubstr day = csubstr_token(date, "/", &pos); - printf("%.*s, %.*s, %.*s\n", c_SV(year), c_SV(month), c_SV(day)); + printf("%.*s, %.*s, %.*s\n", c_SS(year), c_SS(month), c_SS(day)); - cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); + cstr y = cstr_from_ss(year), m = cstr_from_ss(month), d = cstr_from_ss(day); printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); c_drop(cstr, &y, &m, &d); } diff --git a/misc/examples/strings/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c index 1d54486f..03a0442f 100644 --- a/misc/examples/strings/utf8replace_c.c +++ b/misc/examples/strings/utf8replace_c.c @@ -10,12 +10,12 @@ int main(void) cstr_u8_replace_at(&hello, cstr_u8_to_pos(&hello, 7), 1, - c_sv("🐨") + c_ss("🐨") ); printf("%s\n", cstr_str(&hello)); c_foreach (c, cstr, hello) - printf("%.*s,", c_SV(c.u8.chr)); + printf("%.*s,", c_SS(c.u8.chr)); cstr str = cstr_lit("scooby, dooby doo"); cstr_replace(&str, "oo", "00"); diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 4e192de6..7cd03930 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -1,6 +1,6 @@ #define i_import #include -#include +#include #include #include "ctest.h" @@ -14,7 +14,7 @@ CTEST(cregex, compile_match_char) cregex re = cregex_from("äsdf"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_FULLMATCH), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); // ä is two bytes wide @@ -32,7 +32,7 @@ CTEST(cregex, compile_match_anchors) cregex re = cregex_from(inp="^äs.f$"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -50,7 +50,7 @@ CTEST(cregex, compile_match_quantifiers1) re = cregex_from("ä+"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="ääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 4); @@ -70,7 +70,7 @@ CTEST(cregex, compile_match_quantifiers2) re = cregex_from("bä*"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="bääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -90,7 +90,7 @@ CTEST(cregex, compile_match_escaped_chars) cregex re = cregex_from("\\n\\r\\t\\{"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, "\n\r\t{", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "\n\r\t", &match), CREG_NOMATCH); @@ -108,7 +108,7 @@ CTEST(cregex, compile_match_class_simple) re3 = cregex_from("\\D"); ASSERT_EQ(re3.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re1, " " , &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\r", &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\n", &match), CREG_OK); @@ -129,7 +129,7 @@ CTEST(cregex, compile_match_or) re = cregex_from("as|df"); ASSERT_EQ(re.error, 0); - csview match[4]; + csubstr match[4]; ASSERT_EQ(cregex_find(&re, "as", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "df", match), CREG_OK); @@ -146,7 +146,7 @@ CTEST(cregex, compile_match_class_complex_0) cregex re = cregex_from("[asdf]"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "s", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "d", &match), CREG_OK); @@ -160,7 +160,7 @@ CTEST(cregex, compile_match_class_complex_1) cregex re = cregex_from("[a-zä0-9öA-Z]"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "5", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "A", &match), CREG_OK); @@ -175,7 +175,7 @@ CTEST(cregex, compile_match_cap) cregex re = cregex_from("(abc)d"); ASSERT_EQ(re.error, 0); - csview match[4]; + csubstr match[4]; ASSERT_EQ(cregex_find(&re, "abcd", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "llljabcdkk", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "abc", match), CREG_NOMATCH); @@ -189,7 +189,7 @@ CTEST(cregex, search_all) c_auto (cregex, re) { re = cregex_from("ab"); - csview m = {0}; + csubstr m = {0}; int res; ASSERT_EQ(re.error, CREG_OK); inp="ab,ab,ab"; @@ -220,9 +220,9 @@ CTEST(cregex, captures_cap) re = cregex_from("(ab)((cd)+)"); ASSERT_EQ(cregex_captures(&re), 3); - csview cap[5]; + csubstr cap[5]; ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap), CREG_OK); - ASSERT_TRUE(csview_equals(cap[0], "abcdcd")); + ASSERT_TRUE(csubstr_equals(cap[0], "abcdcd")); ASSERT_EQ(M_END(cap[0]), 8); ASSERT_EQ(M_START(cap[1]), 2); @@ -235,7 +235,7 @@ CTEST(cregex, captures_cap) } } -static bool add_10_years(int i, csview match, cstr* out) { +static bool add_10_years(int i, csubstr match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -280,7 +280,7 @@ CTEST(cregex, replace) ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022"); // Strip out everything but the matches - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;"); } } diff --git a/src/cregex.c b/src/cregex.c index 975a5104..c045b9f3 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -100,7 +100,7 @@ typedef struct _Reprog /* * Sub expression matches */ -typedef csview _Resub; +typedef csubstr _Resub; /* * substitution list @@ -1215,8 +1215,8 @@ _regexec(const _Reprog *progp, /* program to run */ static void -_build_subst(const char* replace, int nmatch, const csview match[], - bool (*mfun)(int, csview, cstr*), cstr* subst) { +_build_subst(const char* replace, int nmatch, const csubstr match[], + bool (*mfun)(int, csubstr, cstr*), cstr* subst) { cstr_buf buf = cstr_buffer(subst); intptr_t len = 0, cap = buf.cap; char* dst = buf.data; @@ -1233,7 +1233,7 @@ _build_subst(const char* replace, int nmatch, const csview match[], if (replace[1] >= '0' && replace[1] <= '9' && replace[2] == ';') { g = g*10 + (replace[1] - '0'); replace += 2; } if (g < nmatch) { - csview m = mfun && mfun(g, match[g], &mstr) ? cstr_sv(&mstr) : match[g]; + csubstr m = mfun && mfun(g, match[g], &mstr) ? cstr_ss(&mstr) : match[g]; if (len + m.size > cap) dst = cstr_reserve(subst, cap += cap/2 + m.size); for (int i = 0; i < m.size; ++i) @@ -1270,7 +1270,7 @@ cregex_captures(const cregex* self) { } int -cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { +cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags) { int res = _regexec(re->prog, input, cregex_captures(re) + 1, match, mflags); switch (res) { case 1: return CREG_OK; @@ -1281,7 +1281,7 @@ cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { int cregex_find_pattern_4(const char* pattern, const char* input, - csview match[], int cmflags) { + csubstr match[], int cmflags) { cregex re = cregex_init(); int res = cregex_compile(&re, pattern, cmflags); if (res != CREG_OK) return res; @@ -1291,16 +1291,16 @@ cregex_find_pattern_4(const char* pattern, const char* input, } cstr -cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, - bool (*mfun)(int, csview, cstr*), int rflags) { +cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, + bool (*mfun)(int, csubstr, cstr*), int rflags) { cstr out = cstr_init(); cstr subst = cstr_init(); - csview match[CREG_MAX_CAPTURES]; + csubstr match[CREG_MAX_CAPTURES]; int nmatch = cregex_captures(re) + 1; if (!count) count = INT32_MAX; bool copy = !(rflags & CREG_STRIP); - while (count-- && cregex_find_sv(re, input, match) == CREG_OK) { + while (count-- && cregex_find_ss(re, input, match) == CREG_OK) { _build_subst(replace, nmatch, match, mfun, &subst); const intptr_t mpos = (match[0].str - input.str); if (copy & (mpos > 0)) cstr_append_n(&out, input.str, mpos); @@ -1308,19 +1308,19 @@ cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int cou input.str = match[0].str + match[0].size; input.size -= mpos + match[0].size; } - if (copy) cstr_append_sv(&out, input); + if (copy) cstr_append_ss(&out, input); cstr_drop(&subst); return out; } cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*mfun)(int, csview, cstr*), int crflags) { + bool (*mfun)(int, csubstr, cstr*), int crflags) { cregex re = cregex_init(); if (cregex_compile(&re, pattern, crflags) != CREG_OK) assert(0); - csview sv = {input, c_strlen(input)}; - cstr out = cregex_replace_sv(&re, sv, replace, count, mfun, crflags); + csubstr ss = c_ss(input, c_strlen(input)); + cstr out = cregex_replace_ss(&re, ss, replace, count, mfun, crflags); cregex_drop(&re); return out; } diff --git a/src/libstc.c b/src/libstc.c index 462c97c4..b0d27350 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,7 +1,7 @@ #define i_import #include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement -#include "../include/stc/csview.h" +#include "../include/stc/csubstr.h" #define i_implement #include "../include/stc/crand.h" #if __STDC_VERSION__ >= 201112L diff --git a/src/singleupdate.sh b/src/singleupdate.sh index e706dd97..be99d4a7 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -17,12 +17,12 @@ python singleheader.py $d/include/stc/cqueue.h $d/../stcsingle/stc/cqueue.h python singleheader.py $d/include/stc/crand.h $d/../stcsingle/stc/crand.h python singleheader.py $d/include/stc/cregex.h $d/../stcsingle/stc/cregex.h python singleheader.py $d/include/stc/cset.h $d/../stcsingle/stc/cset.h - python singleheader.py $d/include/stc/csmap.h $d/../stcsingle/stc/csmap.h python singleheader.py $d/include/stc/cspan.h $d/../stcsingle/stc/cspan.h python singleheader.py $d/include/stc/csset.h $d/../stcsingle/stc/csset.h python singleheader.py $d/include/stc/cstack.h $d/../stcsingle/stc/cstack.h python singleheader.py $d/include/stc/cstr.h $d/../stcsingle/stc/cstr.h +python singleheader.py $d/include/stc/csubstr.h $d/../stcsingle/stc/csubstr.h python singleheader.py $d/include/stc/csview.h $d/../stcsingle/stc/csview.h python singleheader.py $d/include/stc/cvec.h $d/../stcsingle/stc/cvec.h python singleheader.py $d/include/stc/extend.h $d/../stcsingle/stc/extend.h diff --git a/src/utf8code.c b/src/utf8code.c index 4abf10ea..ddc4cb97 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -101,7 +101,7 @@ uint32_t utf8_toupper(uint32_t c) { return c; } -int utf8_icmp_sv(const csview s1, const csview s2) { +int utf8_icmp_ss(const csubstr s1, const csubstr s2) { utf8_decode_t d1 = {.state=0}, d2 = {.state=0}; intptr_t j1 = 0, j2 = 0; while ((j1 < s1.size) & (j2 < s2.size)) { -- cgit v1.2.3 From fb5863de1d6ea8a5be8371e57bcd58bf31798a0a Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 14 Aug 2023 09:42:35 +0200 Subject: Finished last commit (cleanup, fixes). --- docs/cstr_api.md | 26 ++++++------ docs/csubstr_api.md | 83 ++++++++++++++++++++------------------ docs/csview_api.md | 8 ++-- include/stc/ccommon.h | 4 +- include/stc/cstr.h | 5 +-- include/stc/csubstr.h | 5 ++- include/stc/csview.h | 12 ++---- misc/examples/strings/sso_substr.c | 6 +-- 8 files changed, 74 insertions(+), 75 deletions(-) diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 36606b76..07b9b4c8 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -22,7 +22,8 @@ cstr cstr_init(void); // construct cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call. cstr cstr_from(const char* str); // constructor using strlen() cstr cstr_from_n(const char* str, intptr_t n); // constructor with n first bytes of str -cstr cstr_from_ss(csubstr sv); // construct cstr from csubstr +cstr cstr_from_sv(csview sv); // construct cstr from csview +cstr cstr_from_ss(csubstr ss); // construct cstr from csubstr cstr cstr_with_capacity(intptr_t cap); cstr cstr_with_size(intptr_t len, char fill); // repeat fill len times cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting @@ -32,10 +33,11 @@ cstr* cstr_take(cstr* self, cstr s); // take owne cstr cstr_move(cstr* self); // move string to caller, leave self empty void cstr_drop(cstr* self); // destructor -const char* cstr_str(const cstr* self); // cast to const char* -char* cstr_data(cstr* self); // cast to mutable char* -csubstr cstr_ss(const cstr* self); // cast to string view -cstr_buf cstr_buffer(cstr* self); // cast to mutable buffer (with capacity) +const char* cstr_str(const cstr* self); // to const char* +csview cstr_sv(const cstr* self); // to csview +csubstr cstr_ss(const cstr* self); // to csubstr +char* cstr_data(cstr* self); // to mutable char* +cstr_buf cstr_buffer(cstr* self); // to mutable buffer (with capacity) intptr_t cstr_size(const cstr* self); intptr_t cstr_capacity(const cstr* self); @@ -48,7 +50,7 @@ void cstr_clear(cstr* self); char* cstr_assign(cstr* self, const char* str); char* cstr_assign_n(cstr* self, const char* str, intptr_t n); // assign n first bytes of str -char* cstr_assign_ss(cstr* self, csubstr sv); +char* cstr_assign_ss(cstr* self, csubstr ss); char* cstr_copy(cstr* self, cstr s); // copy-assign a cstr int cstr_printf(cstr* self, const char* fmt, ...); // source and target must not overlap. @@ -75,7 +77,7 @@ void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csu void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl); bool cstr_equals(const cstr* self, const char* str); -bool cstr_equals_ss(const cstr* self, csubstr sv); +bool cstr_equals_ss(const cstr* self, csubstr ss); bool cstr_equals_s(const cstr* self, cstr s); intptr_t cstr_find(const cstr* self, const char* search); @@ -83,11 +85,11 @@ intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); // bool cstr_contains(const cstr* self, const char* search); bool cstr_starts_with(const cstr* self, const char* str); -bool cstr_starts_with_ss(const cstr* self, csubstr sv); +bool cstr_starts_with_ss(const cstr* self, csubstr ss); bool cstr_starts_with_s(const cstr* self, cstr s); bool cstr_ends_with(const cstr* self, const char* str); -bool cstr_ends_with_ss(const cstr* self, csubstr sv); +bool cstr_ends_with_ss(const cstr* self, csubstr ss); bool cstr_ends_with_s(const cstr* self, cstr s); bool cstr_getline(cstr *self, FILE *stream); // cstr_getdelim(self, '\n', stream) @@ -112,14 +114,14 @@ cstr_iter cstr_advance(cstr_iter it, intptr_t n); // utf8 functions requires linking with src/utf8code.c symbols: bool cstr_valid_utf8(const cstr* self); // check if str is valid utf8 -cstr cstr_casefold_ss(csubstr sv); // returns new casefolded utf8 cstr +cstr cstr_casefold_ss(csubstr ss); // returns new casefolded utf8 cstr cstr cstr_tolower(const char* str); // returns new lowercase utf8 cstr -cstr cstr_tolower_ss(csubstr sv); // returns new lowercase utf8 cstr +cstr cstr_tolower_ss(csubstr ss); // returns new lowercase utf8 cstr void cstr_lowercase(cstr* self); // transform cstr to lowercase utf8 cstr cstr_toupper(const char* str); // returns new uppercase utf8 cstr -cstr cstr_toupper_ss(csubstr sv); // returns new uppercase utf8 cstr +cstr cstr_toupper_ss(csubstr ss); // returns new uppercase utf8 cstr void cstr_uppercase(cstr* self); // transform cstr to uppercase utf8 int cstr_icmp(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison diff --git a/docs/csubstr_api.md b/docs/csubstr_api.md index 925c69db..6cf76cf7 100644 --- a/docs/csubstr_api.md +++ b/docs/csubstr_api.md @@ -1,15 +1,16 @@ # STC [csubstr](../include/stc/csubstr.h): String View ![String](pics/string.jpg) -The type **csubstr** is a string view and can refer to a constant contiguous sequence of char-elements with the first -element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size. +The type **csubstr** is a non-null terminated string view and can refer to a constant contiguous sequence of +char-elements with the first element of the sequence at position zero. The implementation holds two members: +a pointer to constant char and a size. -**csubstr** is non-null terminated, and therefore not a replacent for `const char*` - see [csview](csview_api.md) for -that. **csubstr** never allocates memory, and therefore need not be destructed. -Its lifetime is limited by the source string storage. It keeps the length of the string, and does not need to call -*strlen()* to acquire the length. +Because **csubstr** is non-null terminated, it is not a replacent for `const char*` - see [csview](csview_api.md) +for that. **csubstr** never allocates memory, and therefore need not be destructed. Its lifetime is limited by +the source string storage. It keeps the length of the string, and does not need to call *strlen()* to acquire +the length. -Note: a **csubstr** may ***not be null-terminated***, and must therefore be printed this way: +Note: a **csubstr** must be printed the following way: ```c printf("%.*s", c_SS(sstr)) ``` @@ -29,47 +30,49 @@ All csubstr definitions and prototypes are available by including a single heade ## Methods ```c -csubstr c_ss(const char literal_only[]); // construct from literal, no strlen() -csubstr c_ss(const char* str, intptr_t n); // construct from str and length n +csubstr c_ss(const char literal_only[]); // construct from literal, no strlen() +csubstr c_ss(const char* str, intptr_t n); // construct from str and length n csubstr csubstr_from(const char* str); // construct from const char* csubstr csubstr_from_n(const char* str, intptr_t n); // alias for c_ss(str, n) -intptr_t csubstr_size(csubstr sv); -bool csubstr_empty(csubstr sv); +intptr_t csubstr_size(csubstr ss); +bool csubstr_empty(csubstr ss); void csubstr_clear(csubstr* self); -bool csubstr_equals(csubstr sv, csubstr sv2); -intptr_t csubstr_find(csubstr sv, const char* str); -intptr_t csubstr_find_ss(csubstr sv, csubstr find); -bool csubstr_contains(csubstr sv, const char* str); -bool csubstr_starts_with(csubstr sv, const char* str); -bool csubstr_ends_with(csubstr sv, const char* str); +bool csubstr_equals(csubstr ss, const char* str); +intptr_t csubstr_equals_ss(csubstr ss, csubstr find); +intptr_t csubstr_find(csubstr ss, const char* str); +intptr_t csubstr_find_ss(csubstr ss, csubstr find); +bool csubstr_contains(csubstr ss, const char* str); +bool csubstr_starts_with(csubstr ss, const char* str); +bool csubstr_ends_with(csubstr ss, const char* str); +csubstr csubstr_substr(csubstr ss, intptr_t pos, intptr_t n); +csubstr csubstr_slice(csubstr ss, intptr_t pos1, intptr_t pos2); -csubstr csubstr_substr_ex(csubstr sv, intptr_t pos, intptr_t n); // negative pos count from end -csubstr csubstr_slice_ex(csubstr sv, intptr_t p1, intptr_t p2); // negative p1, p2 count from end -csubstr csubstr_token(csubstr sv, const char* sep, intptr_t* start); // *start > sv.size after last token +csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n); // negative pos count from end +csubstr csubstr_slice_ex(csubstr ss, intptr_t pos1, intptr_t pos2); // negative pos1, pos2 count from end +csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start); // *start > ss.size after last token ``` #### UTF8 methods ```c -intptr_t csubstr_u8_size(csubstr sv); -csubstr csubstr_u8_substr(csubstr sv, intptr_t bytepos, intptr_t u8len); -bool csubstr_valid_utf8(csubstr sv); // requires linking with src/utf8code.c - +intptr_t csubstr_u8_size(csubstr ss); +csubstr csubstr_u8_substr(csubstr ss, intptr_t bytepos, intptr_t u8len); +bool csubstr_valid_utf8(csubstr ss); // requires linking with src/utf8code.c + csubstr_iter csubstr_begin(const csubstr* self); csubstr_iter csubstr_end(const csubstr* self); -void csubstr_next(csubstr_iter* it); // utf8 codepoint step, not byte! +void csubstr_next(csubstr_iter* it); // utf8 codepoint step, not byte! csubstr_iter csubstr_advance(csubstr_iter it, intptr_t n); ``` -#### Extended cstr methods +#### cstr methods returning csubstr ```c +csubstr cstr_slice(const cstr* self, intptr_t pos1, intptr_t pos2); +csubstr cstr_slice_ex(const cstr* self, intptr_t pos1, intptr_t pos2); // see csubstr_slice_ex() csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n); -csubstr cstr_substr_ex(const cstr* s, intptr_t pos, intptr_t n); // negative pos count from end +csubstr cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n); // see csubstr_substr_ex() csubstr cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); - -csubstr cstr_slice(const cstr* self, intptr_t p1, intptr_t p2); -csubstr cstr_slice_ex(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end ``` #### Iterate tokens with *c_fortoken*, *c_fortoken_ss* @@ -99,7 +102,7 @@ uint64_t csubstr_hash(const csubstr* x); | Name | Value | Usage | |:---------------|:---------------------|:---------------------------------------------| -| `c_SS(sv)` | printf argument | `printf("sv: %.*s\n", c_SS(sv));` | +| `c_SS(ss)` | printf argument | `printf("ss: %.*s\n", c_SS(ss));` | ## Example ```c @@ -109,18 +112,18 @@ uint64_t csubstr_hash(const csubstr* x); int main(void) { - cstr str1 = cstr_lit("We think in generalities, but we live in details."); - // (quoting Alfred N. Whitehead) + cstr str1 = cstr_from("We think in generalities, but we live in details."); + // (quoting Alfred N. Whitehead) - csubstr sv1 = cstr_substr_ex(&str1, 3, 5); // "think" - intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 - csubstr sv2 = cstr_substr_ex(&str1, pos, 4); // get "live" - csubstr sv3 = cstr_slice_ex(&str1, -8, -1); // get "details" + csubstr ss1 = cstr_substr_ex(&str1, 3, 5); // "think" + intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 + csubstr ss2 = cstr_substr_ex(&str1, pos, 4); // get "live" + csubstr ss3 = cstr_slice_ex(&str1, -8, -1); // get "details" printf("%.*s %.*s %.*s\n", - c_SS(sv1), c_SS(sv2), c_SS(sv3)); + c_SS(ss1), c_SS(ss2), c_SS(ss3)); cstr s1 = cstr_lit("Apples are red"); - cstr s2 = cstr_from_ss(cstr_substr_ex(&s1, -3, 3)); // "red" - cstr s3 = cstr_from_ss(cstr_substr_ex(&s1, 0, 6)); // "Apples" + cstr s2 = cstr_from_ss(cstr_substr_ex(&s1, -3, 3)); // "red" + cstr s3 = cstr_from_ss(cstr_substr_ex(&s1, 0, 6)); // "Apples" printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); c_drop(cstr, &str1, &s1, &s2, &s3); diff --git a/docs/csview_api.md b/docs/csview_api.md index 4fdff0d1..f7e0e2b0 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -23,17 +23,15 @@ All csview definitions and prototypes are available by including a single header ```c csview c_sv(const char literal_only[]); // construct from literal, no strlen() -csview c_sv(const char* str, intptr_t n); // construct from str and length n csview csview_from(const char* str); // construct from const char* -csview csview_from_n(const char* str, intptr_t n); // alias for c_sv(str, n) intptr_t csview_size(csview sv); -bool csview_empty(csview sv); +bool csview_empty(csview sv); // check if size == 0 void csview_clear(csview* self); +csubstr csview_ss(csview sv); // convert to csubstr type -bool csview_equals(csview sv, csview sv2); +bool csview_equals(csview sv, const char* str); intptr_t csview_find(csview sv, const char* str); -intptr_t csview_find_sv(csview sv, csview find); bool csview_contains(csview sv, const char* str); bool csview_starts_with(csview sv, const char* str); bool csview_ends_with(csview sv, const char* str); diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 24967a10..1b4a2277 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -135,9 +135,9 @@ typedef const char* ccharptr; #define c_ss_2(str, n) (c_LITERAL(csubstr){str, n}) #define c_SS(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SS(ss)); -#define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) -#define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal)) +#define c_sv(literal) c_sv_2(literal, c_litstrlen(literal)) #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) +#define c_SV(sv) c_SS(sv) // [deprecated] - unneeded #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 47cf65da..ce398628 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -115,7 +115,7 @@ STC_INLINE cstr cstr_from(const char* str) STC_INLINE cstr cstr_from_ss(csubstr sv) { return cstr_from_n(sv.str, sv.size); } -STC_INLINE cstr cstr_from_v(csview sv) +STC_INLINE cstr cstr_from_sv(csview sv) { return cstr_from_n(sv.str, sv.size); } STC_INLINE cstr cstr_with_size(const intptr_t size, const char value) { @@ -252,9 +252,6 @@ STC_INLINE bool cstr_equals(const cstr* self, const char* str) STC_INLINE bool cstr_equals_ss(const cstr* self, csubstr sv) { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } -STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv) - { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } - STC_INLINE bool cstr_equals_s(const cstr* self, cstr s) { return !cstr_cmp(self, &s); } diff --git a/include/stc/csubstr.h b/include/stc/csubstr.h index 152f7041..c7a43052 100644 --- a/include/stc/csubstr.h +++ b/include/stc/csubstr.h @@ -45,8 +45,11 @@ STC_INLINE void csubstr_clear(csubstr* self) { *self = csubstr_init(); } STC_INLINE intptr_t csubstr_size(csubstr ss) { return ss.size; } STC_INLINE bool csubstr_empty(csubstr ss) { return ss.size == 0; } +STC_INLINE bool csubstr_equals_ss(csubstr ss1, csubstr ss2) + { return ss1.size == ss2.size && !c_memcmp(ss1.str, ss2.str, ss1.size); } + STC_INLINE bool csubstr_equals(csubstr ss, const char* str) - { intptr_t n = c_strlen(str); return ss.size == n && !c_memcmp(ss.str, str, n); } + { return csubstr_equals_ss(ss, c_ss_2(str, c_strlen(str))); } STC_INLINE intptr_t csubstr_find(csubstr ss, const char* str) { return csubstr_find_ss(ss, c_ss_2(str, c_strlen(str))); } diff --git a/include/stc/csview.h b/include/stc/csview.h index 0d1ca36c..367258e4 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -26,13 +26,12 @@ #ifndef CSVIEW_H_INCLUDED #define CSVIEW_H_INCLUDED -#define csview_init() c_sv_1("") +#define csview_init() c_sv("") #define csview_drop(p) c_default_drop(p) #define csview_clone(sv) c_default_clone(sv) -#define csview_from_n(str, n) c_sv_2(str, n) STC_INLINE csview csview_from(const char* str) - { return csview_from_n(str, c_strlen(str)); } + { return c_sv_2(str, c_strlen(str)); } STC_INLINE void csview_clear(csview* self) { *self = csview_init(); } STC_INLINE csubstr csview_ss(csview sv) { return c_ss_2(sv.str, sv.size); } @@ -44,14 +43,11 @@ STC_INLINE bool csview_equals(csview sv, const char* str) { return sv.size == n && !c_memcmp(sv.str, str, n); } -STC_INLINE intptr_t csview_find_v(csview sv, csview search) { - char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); +STC_INLINE intptr_t csview_find(csview sv, const char* search) { + char* res = cstrnstrn(sv.str, search, sv.size, c_strlen(search)); return res ? (res - sv.str) : c_NPOS; } -STC_INLINE intptr_t csview_find(csview sv, const char* str) - { return csview_find_v(sv, c_sv_2(str, c_strlen(str))); } - STC_INLINE bool csview_contains(csview sv, const char* str) { return csview_find(sv, str) != c_NPOS; } diff --git a/misc/examples/strings/sso_substr.c b/misc/examples/strings/sso_substr.c index 3c6b1046..2262e349 100644 --- a/misc/examples/strings/sso_substr.c +++ b/misc/examples/strings/sso_substr.c @@ -5,7 +5,7 @@ int main(void) { - cstr str = cstr_lit("We think in generalities, but we live in details."); + cstr str = cstr_from("We think in generalities, but we live in details."); csubstr sv1 = cstr_substr_ex(&str, 3, 5); // "think" intptr_t pos = cstr_find(&str, "live"); // position of "live" csubstr sv2 = cstr_substr_ex(&str, pos, 4); // "live" @@ -13,8 +13,8 @@ int main(void) printf("%.*s, %.*s, %.*s\n", c_SS(sv1), c_SS(sv2), c_SS(sv3)); cstr_assign(&str, "apples are green or red"); - cstr s2 = cstr_from_ss(cstr_substr_ex(&str, -3, 3)); // "red" - cstr s3 = cstr_from_ss(cstr_substr_ex(&str, 0, 6)); // "apples" + cstr s2 = cstr_from_ss(cstr_substr_ex(&str, -3, 3)); // "red" + cstr s3 = cstr_from_ss(cstr_substr_ex(&str, 0, 6)); // "apples" printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), cstr_is_long(&str), cstr_is_long(&s2)); c_drop (cstr, &str, &s2, &s3); -- cgit v1.2.3 From 2b6b4785c5c26bc47d800c1a7c7a48784df2d57b Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 14 Aug 2023 10:33:32 +0200 Subject: Some docs updates. --- README.md | 9 +++++---- docs/csubstr_api.md | 9 +++++---- docs/csview_api.md | 8 ++++---- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 96479fa0..1c8c3878 100644 --- a/README.md +++ b/README.md @@ -18,18 +18,19 @@ Containers - [***cbox*** - **std::unique_ptr** alike type](docs/cbox_api.md) - [***cbits*** - **std::bitset** alike type](docs/cbits_api.md) - [***clist*** - **std::forward_list** alike type](docs/clist_api.md) +- [***cstack*** - **std::stack** alike type](docs/cstack_api.md) +- [***cvec*** - **std::vector** alike type](docs/cvec_api.md) - [***cqueue*** - **std::queue** alike type](docs/cqueue_api.md) +- [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md) - [***cpque*** - **std::priority_queue** alike type](docs/cpque_api.md) - [***cmap*** - **std::unordered_map** alike type](docs/cmap_api.md) - [***cset*** - **std::unordered_set** alike type](docs/cset_api.md) - [***csmap*** - **std::map** sorted map alike type](docs/csmap_api.md) - [***csset*** - **std::set** sorted set alike type](docs/csset_api.md) -- [***cstack*** - **std::stack** alike type](docs/cstack_api.md) - [***cstr*** - **std::string** alike type](docs/cstr_api.md) - [***csubstr*** - **std::string_view** alike type](docs/csubstr_api.md) -- [***cspan*** - **std::span/std::mdspan** alike type](docs/cspan_api.md) -- [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md) -- [***cvec*** - **std::vector** alike type](docs/cvec_api.md) +- [***csview*** - null-terminated string view type](docs/csview_api.md) +- [***cspan*** - **std::span** + **std::mdspan** alike type](docs/cspan_api.md) Algorithms ---------- diff --git a/docs/csubstr_api.md b/docs/csubstr_api.md index 6cf76cf7..7094cf82 100644 --- a/docs/csubstr_api.md +++ b/docs/csubstr_api.md @@ -1,18 +1,19 @@ -# STC [csubstr](../include/stc/csubstr.h): String View +# STC [csubstr](../include/stc/csubstr.h): Sub-string View ![String](pics/string.jpg) The type **csubstr** is a non-null terminated string view and can refer to a constant contiguous sequence of char-elements with the first element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size. -Because **csubstr** is non-null terminated, it is not a replacent for `const char*` - see [csview](csview_api.md) +Because **csubstr** is non-null terminated, it is not a replacent view for `const char*` - see [csview](csview_api.md) for that. **csubstr** never allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string storage. It keeps the length of the string, and does not need to call *strlen()* to acquire the length. -Note: a **csubstr** must be printed the following way: +- **csubstr** iterators works on UTF8 codepoints - like **cstr** and **csview** (see Example 2). +- Because it is null-terminated, it must be printed the following way: ```c -printf("%.*s", c_SS(sstr)) +printf("%.*s", c_SS(sstr)); ``` See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional diff --git a/docs/csview_api.md b/docs/csview_api.md index f7e0e2b0..d28e3ed2 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -1,4 +1,4 @@ -# STC [csview](../include/stc/csview.h): String View +# STC [csview](../include/stc/csview.h): Null-terminated UTF8 String View ![String](pics/string.jpg) The type **csview** is a ***null-terminated*** string view and refers to a constant contiguous sequence of @@ -6,9 +6,9 @@ char-elements with the first element of the sequence at position zero. The imple members: a pointer to constant char and a size. See [csubstr](csubstr_api.md) for a ***non null-terminated*** string view/span type. -Because **csview** is null-terminated, it can be a more efficient replacent for `const char*`. It never -allocates memory, and need therefore not be destructed. Its lifetime is limited by the source string -storage. It keeps the length of the string, and does not call *strlen()* when passing it around. +Because **csview** is null-terminated, it can be an efficient replacent for `const char*`. It never +allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string +storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations. ## Header file -- cgit v1.2.3 From 78d8668e6d527070568a405408ed906e51055bf4 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 14 Aug 2023 16:46:24 +0200 Subject: Reverted csubstr => csview. Sorry about that! Added crawstr to become the null-terminated string view. --- README.md | 32 ++-- docs/crawstr_api.md | 130 +++++++++++++ docs/cregex_api.md | 28 +-- docs/cstr_api.md | 34 ++-- docs/csubstr_api.md | 221 ----------------------- docs/csview_api.md | 217 +++++++++++++++------- include/stc/ccommon.h | 13 +- include/stc/crawstr.h | 116 ++++++++++++ include/stc/cregex.h | 36 ++-- include/stc/cstr.h | 148 +++++++-------- include/stc/csubstr.h | 211 ---------------------- include/stc/csview.h | 159 ++++++++++++---- include/stc/forward.h | 34 ++-- include/stc/priv/template.h | 14 +- include/stc/utf8.h | 4 +- misc/benchmarks/various/string_bench_STC.cpp | 32 ++-- misc/examples/algorithms/forfilter.c | 12 +- misc/examples/regularexpressions/regex2.c | 2 +- misc/examples/regularexpressions/regex_match.c | 4 +- misc/examples/regularexpressions/regex_replace.c | 6 +- misc/examples/strings/cstr_match.c | 10 +- misc/examples/strings/replace.c | 4 +- misc/examples/strings/splitstr.c | 8 +- misc/examples/strings/sso_substr.c | 14 +- misc/examples/strings/sview_split.c | 14 +- misc/examples/strings/utf8replace_c.c | 4 +- misc/tests/cregex_test.c | 32 ++-- src/cregex.c | 28 +-- src/libstc.c | 2 +- src/singleupdate.sh | 2 +- src/utf8code.c | 2 +- 31 files changed, 786 insertions(+), 787 deletions(-) create mode 100644 docs/crawstr_api.md delete mode 100644 docs/csubstr_api.md create mode 100644 include/stc/crawstr.h delete mode 100644 include/stc/csubstr.h diff --git a/README.md b/README.md index 1c8c3878..d99d8a76 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ Containers - [***csmap*** - **std::map** sorted map alike type](docs/csmap_api.md) - [***csset*** - **std::set** sorted set alike type](docs/csset_api.md) - [***cstr*** - **std::string** alike type](docs/cstr_api.md) -- [***csubstr*** - **std::string_view** alike type](docs/csubstr_api.md) -- [***csview*** - null-terminated string view type](docs/csview_api.md) +- [***csview*** - **std::string_view** alike type](docs/csview_api.md) +- [***crawstr*** - null-terminated string view type](docs/crawstr_api.md) - [***cspan*** - **std::span** + **std::mdspan** alike type](docs/cspan_api.md) Algorithms @@ -352,11 +352,11 @@ linking, so *one* c-file must implement the templated container, e.g.: #include "cvec_int.h" ``` The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by -`#define i_static`. Same for the string-view type **csubstr**, but most of its functions are static inlined, so +`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so linking specifications and implementation are only needed for a few lesser used functions. Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**, -**csubstr**, **cregex**, **utf8**, and **crand**. +**csview**, **cregex**, **utf8**, and **crand**. As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent **utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc. @@ -402,8 +402,8 @@ Only functions required by the container type is required to be defined. E.g.: - *Type_clone()* is not used if *#define i_opt c_no_clone* is specified. - `i_key_str` - Sets `i_keyclass` = *cstr*, `i_tag` = *str*, and `i_keyraw` = *const char*\*. Defines both type convertion `i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *const char\*\** as argument. -- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csubstr\**. Defines both type convertion -`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csubstr\** as argument. +- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csview\**. Defines both type convertion +`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csview\** as argument. - `i_keyboxed` *Type* - Use when *Type* is a smart pointer **carc** or **cbox**. Defines *i_keyclass = Type*, and *i_keyraw = Type\**. NB: Do not use when defining carc/cbox types themselves. - `i_valclass` *Type*, `i_val_str`, `i_val_ssv`, `i_valboxed` - Similar rules as for ***key***. @@ -641,7 +641,7 @@ void maptest() STC is generally very memory efficient. Memory usage for the different containers: - **cstr**, **cvec**, **cstack**, **cpque**: 1 pointer, 2 intptr_t + memory for elements. -- **csubstr**, 1 pointer, 1 intptr_t. Does not own data! +- **csview**, 1 pointer, 1 intptr_t. Does not own data! - **cspan**, 1 pointer and 2 \* dimension \* int32_t. Does not own data! - **clist**: Type size: 1 pointer. Each node allocates a struct to store its value and a next pointer. - **cdeq**, **cqueue**: Type size: 2 pointers, 2 intptr_t. Otherwise like *cvec*. @@ -655,7 +655,7 @@ STC is generally very memory efficient. Memory usage for the different container ## Version 4.3 - Breaking changes: - - **cstr** and **csubstr** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. + - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. - Renamed => `` - Moved => `` - Much improved with some new API and added features. @@ -687,7 +687,7 @@ STC is generally very memory efficient. Memory usage for the different container - Renamed c_flt_count(i) => `c_flt_counter(i)` - Renamed c_flt_last(i) => `c_flt_getcount(i)` - Renamed c_ARRAYLEN() => c_arraylen() -- Removed deprecated c_ARGSV(). Use c_SS() +- Removed deprecated c_ARGSV(). Use c_SV() - Removed c_PAIR ## Version 4.1.1 @@ -700,7 +700,7 @@ Major changes: - [crange](docs/algorithm_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - [c_forfilter](docs/algorithm_api.md#c_forfilter) - ranges-like view filtering. - [csort](include/stc/algo/sort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. -- Renamed `c_ARGSV()` => `c_SS()`: **csubstr** print arg. Note `c_ss()` is shorthand for *csubstr_from()*. +- Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. - Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. - Some API changes in **cregex** and **cstr**. - Create single header container versions with python script. @@ -714,18 +714,18 @@ Major changes: - New + renamed loop iteration/scope macros: - `c_forlist`: macro replacing `c_forarray` and `c_apply`. Iterate a compound literal list. - `c_forrange`: macro replacing `c_forrange`. Iterate a `long long` type number sequence. -- Updated **cstr**, now always takes self as pointer, like all containers except csubstr. +- Updated **cstr**, now always takes self as pointer, like all containers except csview. - Updated **cvec**, **cdeq**, changed `*_range*` function names. ## Changes version 3.8 -- Overhauled some **cstr** and **csubstr** API: +- Overhauled some **cstr** and **csview** API: - Changed cstr_replace*() => `cstr_replace_at*(self, pos, len, repl)`: Replace at specific position. - Changed `cstr_replace_all() cstr_replace*(self, search, repl, count)`: Replace count occurences. - Renamed `cstr_find_from()` => `cstr_find_at()` - Renamed `cstr_*_u8()` => `cstr_u8_*()` - - Renamed `csubstr_*_u8()` => `csubstr_u8_*()` - - Added cstr_u8_slice() and csubstr_u8_slice(). - - Removed `csubstr_from_s()`: Use `cstr_ss(s)` instead. + - Renamed `csview_*_u8()` => `csview_u8_*()` + - Added cstr_u8_slice() and csview_u8_slice(). + - Removed `csview_from_s()`: Use `cstr_sv(s)` instead. - Added back file coption.h - Simplified **cbits** usage: all inlined. - Updated docs. @@ -760,7 +760,7 @@ Major changes: - Renamed: *cstr_new()* to `cstr_lit(literal)`, and *cstr_assign_fmt()* to `cstr_printf()`. - Renamed: *c_default_fromraw()* to `c_default_from()`. - Changed: the [**c_apply**](docs/algorithm_api.md) macros API. -- Replaced: *csubstr_first_token()* and *csubstr_next_token()* with one function: `csubstr_token()`. +- Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`. - Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly. - Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions. - Added: `i_opt` template parameter: compile-time options: `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` diff --git a/docs/crawstr_api.md b/docs/crawstr_api.md new file mode 100644 index 00000000..d44c302d --- /dev/null +++ b/docs/crawstr_api.md @@ -0,0 +1,130 @@ +# STC [crawstr](../include/stc/crawstr.h): Null-terminated UTF8 String View +![String](pics/string.jpg) + +The type **crawstr** is a ***null-terminated*** string view and refers to a constant contiguous sequence of +char-elements with the first element of the sequence at position zero. The implementation holds two +members: a pointer to constant char and a size. See [csview](csview_api.md) for a ***non null-terminated*** +string view/span type. + +Because **crawstr** is null-terminated, it can be an efficient replacent for `const char*`. It never +allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string +storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations. + +## Header file + +All crawstr definitions and prototypes are available by including a single header file. + +```c +#define i_implement +#include +#include +``` +## Methods + +```c +crawstr crawstr_from(const char* str); // construct from const char* +crawstr c_rs(const char literal_only[]); // construct from literal, no strlen() + +intptr_t crawstr_size(crawstr rs); +bool crawstr_empty(crawstr rs); // check if size == 0 +void crawstr_clear(crawstr* self); +csview crawstr_sv(crawstr rs); // convert to csview type + +bool crawstr_equals(crawstr rs, const char* str); +intptr_t crawstr_find(crawstr rs, const char* str); +bool crawstr_contains(crawstr rs, const char* str); +bool crawstr_starts_with(crawstr rs, const char* str); +bool crawstr_ends_with(crawstr rs, const char* str); +``` + +#### UTF8 methods +```c +intptr_t crawstr_u8_size(crawstr rs); +bool crawstr_valid_utf8(crawstr rs); // depends on src/utf8code.c + +crawstr_iter crawstr_begin(const crawstr* self); +crawstr_iter crawstr_end(const crawstr* self); +void crawstr_next(crawstr_iter* it); // utf8 codepoint step, not byte! +crawstr_iter crawstr_advance(crawstr_iter it, intptr_t n); + + // from utf8.h +intptr_t utf8_size(const char *s); +intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes +const char* utf8_at(const char *s, intptr_t index); // from UTF8 index to char* position +intptr_t utf8_pos(const char* s, intptr_t index); // from UTF8 index to byte index position +unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4 + // implemented in src/utf8code.c: +bool utf8_valid(const char* s); +bool utf8_valid_n(const char* s, intptr_t nbytes); +uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, return state. +unsigned utf8_encode(char *out, uint32_t codepoint); // encode unicode cp into out buffer +uint32_t utf8_peek(const char* s); // codepoint value of character at s +uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative) +``` + +#### Helper methods +```c +int crawstr_cmp(const crawstr* x, const crawstr* y); +int crawstr_icmp(const crawstr* x, const crawstr* y); // depends on src/utf8code.c: +bool crawstr_eq(const crawstr* x, const crawstr* y); +uint64_t crawstr_hash(const crawstr* x); +``` + +## Types + +| Type name | Type definition | Used to represent... | +|:----------------|:-------------------------------------------|:-------------------------| +| `crawstr` | `struct { const char *str; intptr_t size; }` | The string view type | +| `crawstr_value` | `char` | The string element type | +| `crawstr_iter` | `struct { crawstr_value *ref; }` | UTF8 iterator | + +## Example: UTF8 iteration and case conversion +```c +#define i_import +#include +#include + +int main(void) +{ + cstr str = cstr_from("Liberté, égalité, fraternité."); + crawstr rs = cstr_rs(&str); + + c_foreach (i, crawstr, rs) + printf("%.*s ", c_SV(i.u8.chr)); + puts(""); + + cstr_uppercase(&str); + printf("%s\n", cstr_str(&str)); + + cstr_drop(&str); +} +``` +Output: +``` +L i b e r t é , é g a l i t é , f r a t e r n i t é . +LIBERTÉ, ÉGALITÉ, FRATERNITÉ. +``` + +### Example 2: UTF8 replace +```c +#define i_import // include dependent utf8 definitions. +#include + +int main(void) +{ + cstr s1 = cstr_lit("hell😀 w😀rld"); + + cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_rs("ø")); + printf("%s\n", cstr_str(&s1)); + + c_foreach (i, cstr, s1) + printf("%.*s,", c_SV(i.u8.chr)); // u8.chr is a csview + + cstr_drop(&s1); +} +``` +Output: +``` +hell😀 wørld +h,e,l,l,😀, ,w,ø,r,l,d, +``` diff --git a/docs/cregex_api.md b/docs/cregex_api.md index 98161fe9..52476e09 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -33,11 +33,11 @@ int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_ int cregex_captures(const cregex* self); // return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR -int cregex_find(const cregex* re, const char* input, csubstr match[], int mflags = CREG_DEFAULT); +int cregex_find(const cregex* re, const char* input, csview match[], int mflags = CREG_DEFAULT); // Search inside input string-view only -int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]); +int cregex_find_sv(const cregex* re, csview input, csview match[]); // All-in-one search (compile + find + drop) -int cregex_find_pattern(const char* pattern, const char* input, csubstr match[], int cmflags = CREG_DEFAULT); +int cregex_find_pattern(const char* pattern, const char* input, csview match[], int cmflags = CREG_DEFAULT); // Check if there are matches in input bool cregex_is_match(const cregex* re, const char* input); @@ -45,14 +45,14 @@ bool cregex_is_match(const cregex* re, const char* input); // Replace all matches in input cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX); // Replace count matches in input string-view. Optionally transform replacement. -cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count = INT_MAX); -cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count, - bool(*transform)(int group, csubstr match, cstr* result), int rflags); +cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX); +cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count, + bool(*transform)(int group, csview match, cstr* result), int rflags); // All-in-one replacement (compile + find/replace + drop) cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX); cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count, - bool(*transform)(int group, csubstr match, cstr* result), int rflags); + bool(*transform)(int group, csview match, cstr* result), int rflags); // destroy void cregex_drop(cregex* self); ``` @@ -109,9 +109,9 @@ int main(void) { cregex re = cregex_from(pattern); // Lets find the first date in the string: - csubstr match[4]; // full-match, year, month, date. + csview match[4]; // full-match, year, month, date. if (cregex_find(&re, input, match) == CREG_OK) - printf("Found date: %.*s\n", c_SS(match[0])); + printf("Found date: %.*s\n", c_SV(match[0])); else printf("Could not find any date\n"); @@ -127,7 +127,7 @@ int main(void) { For a single match you may use the all-in-one function: ```c if (cregex_find_pattern(pattern, input, match)) - printf("Found date: %.*s\n", c_SS(match[0])); + printf("Found date: %.*s\n", c_SV(match[0])); ``` To use: `gcc first_match.c src/cregex.c src/utf8code.c`. @@ -137,16 +137,16 @@ In order to use a callback function in the replace call, see `examples/regex_rep To iterate multiple matches in an input string, you may use ```c -csubstr match[5] = {0}; +csview match[5] = {0}; while (cregex_find(&re, input, match, CREG_NEXT) == CREG_OK) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SS(match[k])); + printf("submatch %d: %.*s\n", k, c_SV(match[k])); ``` There is also a for-loop macro to simplify it: ```c c_formatch (it, &re, input) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SS(it.match[k])); + printf("submatch %d: %.*s\n", k, c_SV(it.match[k])); ``` ## Using cregex in a project @@ -154,7 +154,7 @@ c_formatch (it, &re, input) The easiest is to `#define i_import` before `#include `. Make sure to do that in one translation unit only. For reference, **cregex** uses the following files: -- `stc/cregex.h`, `stc/utf8.h`, `stc/csubstr.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` +- `stc/cregex.h`, `stc/utf8.h`, `stc/csview.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` - `src/cregex.c`, `src/utf8code.c`. ## Regex Cheatsheet diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 07b9b4c8..1da57b0c 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -22,8 +22,8 @@ cstr cstr_init(void); // construct cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call. cstr cstr_from(const char* str); // constructor using strlen() cstr cstr_from_n(const char* str, intptr_t n); // constructor with n first bytes of str -cstr cstr_from_sv(csview sv); // construct cstr from csview -cstr cstr_from_ss(csubstr ss); // construct cstr from csubstr +cstr cstr_from_sv(csview ss); // construct cstr from csview +cstr cstr_from_rs(crawstr rs); // construct cstr from crawstr cstr cstr_with_capacity(intptr_t cap); cstr cstr_with_size(intptr_t len, char fill); // repeat fill len times cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting @@ -35,7 +35,7 @@ void cstr_drop(cstr* self); // destructo const char* cstr_str(const cstr* self); // to const char* csview cstr_sv(const cstr* self); // to csview -csubstr cstr_ss(const cstr* self); // to csubstr +crawstr cstr_rs(const cstr* self); // to crawstr char* cstr_data(cstr* self); // to mutable char* cstr_buf cstr_buffer(cstr* self); // to mutable buffer (with capacity) @@ -50,13 +50,13 @@ void cstr_clear(cstr* self); char* cstr_assign(cstr* self, const char* str); char* cstr_assign_n(cstr* self, const char* str, intptr_t n); // assign n first bytes of str -char* cstr_assign_ss(cstr* self, csubstr ss); +char* cstr_assign_sv(cstr* self, csview ss); char* cstr_copy(cstr* self, cstr s); // copy-assign a cstr int cstr_printf(cstr* self, const char* fmt, ...); // source and target must not overlap. char* cstr_append(cstr* self, const char* str); char* cstr_append_n(cstr* self, const char* str, intptr_t n); // append n first bytes of str -char* cstr_append_ss(cstr* self, csubstr str); +char* cstr_append_sv(cstr* self, csview str); char* cstr_append_s(cstr* self, cstr str); int cstr_append_fmt(cstr* self, const char* fmt, ...); // printf() formatting char* cstr_append_uninit(cstr* self, intptr_t len); // return ptr to start of uninited data @@ -65,19 +65,19 @@ void cstr_push(cstr* self, const char* chr); // append on void cstr_pop(cstr* self); // pop one utf8 char void cstr_insert(cstr* self, intptr_t pos, const char* ins); -void cstr_insert_ss(cstr* self, intptr_t pos, csubstr ins); +void cstr_insert_sv(cstr* self, intptr_t pos, csview ins); void cstr_insert_s(cstr* self, intptr_t pos, cstr ins); void cstr_erase(cstr* self, intptr_t pos, intptr_t len); // erase len bytes from pos void cstr_replace(cstr* self, const char* search, const char* repl, unsigned count = MAX_INT); -cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, unsigned count); +cstr cstr_replace_sv(csview in, csview search, csview repl, unsigned count); void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl); // replace at a pos -void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl); +void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl); void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl); bool cstr_equals(const cstr* self, const char* str); -bool cstr_equals_ss(const cstr* self, csubstr ss); +bool cstr_equals_sv(const cstr* self, csview ss); bool cstr_equals_s(const cstr* self, cstr s); intptr_t cstr_find(const cstr* self, const char* search); @@ -85,11 +85,11 @@ intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); // bool cstr_contains(const cstr* self, const char* search); bool cstr_starts_with(const cstr* self, const char* str); -bool cstr_starts_with_ss(const cstr* self, csubstr ss); +bool cstr_starts_with_sv(const cstr* self, csview ss); bool cstr_starts_with_s(const cstr* self, cstr s); bool cstr_ends_with(const cstr* self, const char* str); -bool cstr_ends_with_ss(const cstr* self, csubstr ss); +bool cstr_ends_with_sv(const cstr* self, csview ss); bool cstr_ends_with_s(const cstr* self, cstr s); bool cstr_getline(cstr *self, FILE *stream); // cstr_getdelim(self, '\n', stream) @@ -102,8 +102,8 @@ intptr_t cstr_u8_size(const cstr* self); // number of intptr_t cstr_u8_size_n(const cstr self, intptr_t nbytes); // utf8 size within n bytes intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx); // byte pos offset at utf8 codepoint index const char* cstr_u8_at(const cstr* self, intptr_t u8idx); // char* position at utf8 codepoint index -csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csubstr -void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl); // replace u8len utf8 chars +csview cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csview +void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl); // replace u8len utf8 chars void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); // erase u8len codepoints from pos // iterate utf8 codepoints @@ -114,14 +114,14 @@ cstr_iter cstr_advance(cstr_iter it, intptr_t n); // utf8 functions requires linking with src/utf8code.c symbols: bool cstr_valid_utf8(const cstr* self); // check if str is valid utf8 -cstr cstr_casefold_ss(csubstr ss); // returns new casefolded utf8 cstr +cstr cstr_casefold_sv(csview ss); // returns new casefolded utf8 cstr cstr cstr_tolower(const char* str); // returns new lowercase utf8 cstr -cstr cstr_tolower_ss(csubstr ss); // returns new lowercase utf8 cstr +cstr cstr_tolower_sv(csview ss); // returns new lowercase utf8 cstr void cstr_lowercase(cstr* self); // transform cstr to lowercase utf8 cstr cstr_toupper(const char* str); // returns new uppercase utf8 cstr -cstr cstr_toupper_ss(csubstr ss); // returns new uppercase utf8 cstr +cstr cstr_toupper_sv(csview ss); // returns new uppercase utf8 cstr void cstr_uppercase(cstr* self); // transform cstr to uppercase utf8 int cstr_icmp(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison @@ -146,7 +146,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr |:----------------|:---------------------------------------------|:---------------------| | `cstr` | `struct { ... }` | The string type | | `cstr_value` | `char` | String element type | -| `csubstr` | `struct { const char *str; intptr_t size; }` | String view type | +| `csview` | `struct { const char *str; intptr_t size; }` | String view type | | `cstr_buf` | `struct { char *data; intptr_t size, cap; }` | String buffer type | ## Constants and macros diff --git a/docs/csubstr_api.md b/docs/csubstr_api.md deleted file mode 100644 index 7094cf82..00000000 --- a/docs/csubstr_api.md +++ /dev/null @@ -1,221 +0,0 @@ -# STC [csubstr](../include/stc/csubstr.h): Sub-string View -![String](pics/string.jpg) - -The type **csubstr** is a non-null terminated string view and can refer to a constant contiguous sequence of -char-elements with the first element of the sequence at position zero. The implementation holds two members: -a pointer to constant char and a size. - -Because **csubstr** is non-null terminated, it is not a replacent view for `const char*` - see [csview](csview_api.md) -for that. **csubstr** never allocates memory, and therefore need not be destructed. Its lifetime is limited by -the source string storage. It keeps the length of the string, and does not need to call *strlen()* to acquire -the length. - -- **csubstr** iterators works on UTF8 codepoints - like **cstr** and **csview** (see Example 2). -- Because it is null-terminated, it must be printed the following way: -```c -printf("%.*s", c_SS(sstr)); -``` - -See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional -description. - -## Header file - -All csubstr definitions and prototypes are available by including a single header file. - -```c -#define i_implement -#include -#include // after cstr.h: include extra cstr-csubstr functions -``` -## Methods - -```c -csubstr c_ss(const char literal_only[]); // construct from literal, no strlen() -csubstr c_ss(const char* str, intptr_t n); // construct from str and length n -csubstr csubstr_from(const char* str); // construct from const char* -csubstr csubstr_from_n(const char* str, intptr_t n); // alias for c_ss(str, n) - -intptr_t csubstr_size(csubstr ss); -bool csubstr_empty(csubstr ss); -void csubstr_clear(csubstr* self); - -bool csubstr_equals(csubstr ss, const char* str); -intptr_t csubstr_equals_ss(csubstr ss, csubstr find); -intptr_t csubstr_find(csubstr ss, const char* str); -intptr_t csubstr_find_ss(csubstr ss, csubstr find); -bool csubstr_contains(csubstr ss, const char* str); -bool csubstr_starts_with(csubstr ss, const char* str); -bool csubstr_ends_with(csubstr ss, const char* str); -csubstr csubstr_substr(csubstr ss, intptr_t pos, intptr_t n); -csubstr csubstr_slice(csubstr ss, intptr_t pos1, intptr_t pos2); - -csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n); // negative pos count from end -csubstr csubstr_slice_ex(csubstr ss, intptr_t pos1, intptr_t pos2); // negative pos1, pos2 count from end -csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start); // *start > ss.size after last token -``` - -#### UTF8 methods -```c -intptr_t csubstr_u8_size(csubstr ss); -csubstr csubstr_u8_substr(csubstr ss, intptr_t bytepos, intptr_t u8len); -bool csubstr_valid_utf8(csubstr ss); // requires linking with src/utf8code.c - -csubstr_iter csubstr_begin(const csubstr* self); -csubstr_iter csubstr_end(const csubstr* self); -void csubstr_next(csubstr_iter* it); // utf8 codepoint step, not byte! -csubstr_iter csubstr_advance(csubstr_iter it, intptr_t n); -``` - -#### cstr methods returning csubstr -```c -csubstr cstr_slice(const cstr* self, intptr_t pos1, intptr_t pos2); -csubstr cstr_slice_ex(const cstr* self, intptr_t pos1, intptr_t pos2); // see csubstr_slice_ex() -csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n); -csubstr cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n); // see csubstr_substr_ex() -csubstr cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); -``` -#### Iterate tokens with *c_fortoken*, *c_fortoken_ss* - -To iterate tokens in an input string separated by a string: -```c -c_fortoken (i, "hello, one, two, three", ", ") - printf("token: %.*s\n", c_SS(i.token)); -``` - -#### Helper methods -```c -int csubstr_cmp(const csubstr* x, const csubstr* y); -int csubstr_icmp(const csubstr* x, const csubstr* y); -bool csubstr_eq(const csubstr* x, const csubstr* y); -uint64_t csubstr_hash(const csubstr* x); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:----------------|:-------------------------------------------|:-------------------------| -| `csubstr` | `struct { const char *str; intptr_t size; }` | The string view type | -| `csubstr_value` | `char` | The string element type | -| `csubstr_iter` | `struct { csubstr_value *ref; }` | UTF8 iterator | - -## Constants and macros - -| Name | Value | Usage | -|:---------------|:---------------------|:---------------------------------------------| -| `c_SS(ss)` | printf argument | `printf("ss: %.*s\n", c_SS(ss));` | - -## Example -```c -#define i_implement -#include -#include - -int main(void) -{ - cstr str1 = cstr_from("We think in generalities, but we live in details."); - // (quoting Alfred N. Whitehead) - - csubstr ss1 = cstr_substr_ex(&str1, 3, 5); // "think" - intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 - csubstr ss2 = cstr_substr_ex(&str1, pos, 4); // get "live" - csubstr ss3 = cstr_slice_ex(&str1, -8, -1); // get "details" - printf("%.*s %.*s %.*s\n", - c_SS(ss1), c_SS(ss2), c_SS(ss3)); - cstr s1 = cstr_lit("Apples are red"); - cstr s2 = cstr_from_ss(cstr_substr_ex(&s1, -3, 3)); // "red" - cstr s3 = cstr_from_ss(cstr_substr_ex(&s1, 0, 6)); // "Apples" - printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); - - c_drop(cstr, &str1, &s1, &s2, &s3); -} -``` -Output: -``` -think live details -red Apples -``` - -### Example 2: UTF8 handling -```c -#define i_import // include dependent cstr, utf8 and cregex function definitions. -#include - -int main(void) -{ - cstr s1 = cstr_lit("hell😀 w😀rld"); - - cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_ss("ø")); - printf("%s\n", cstr_str(&s1)); - - c_foreach (i, cstr, s1) - printf("%.*s,", c_SS(i.u8.chr)); - - cstr_drop(&s1); -} -``` -Output: -``` -hell😀 wørld -h,e,l,l,😀, ,w,ø,r,l,d, -``` - -### Example 3: csubstr tokenizer (string split) -Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, -and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. -```c -#include -#include - -void print_split(csubstr input, const char* sep) -{ - c_fortoken_ss (i, input, sep) - printf("[%.*s]\n", c_SS(i.token)); - puts(""); -} -#define i_implement -#include -#define i_key_str -#include - -cstack_str string_split(csubstr input, const char* sep) -{ - cstack_str out = cstack_str_init(); - - c_fortoken_ss (i, input, sep) - cstack_str_push(&out, cstr_from_ss(i.token)); - - return out; -} - -int main(void) -{ - print_split(c_ss("//This is a//double-slash//separated//string"), "//"); - print_split(c_ss("This has no matching separator"), "xx"); - - cstack_str s = string_split(c_ss("Split,this,,string,now,"), ","); - - c_foreach (i, cstack_str, s) - printf("[%s]\n", cstr_str(i.ref)); - puts(""); - - cstack_str_drop(&s); -} -``` -Output: -``` -[] -[This is a] -[double-slash] -[separated] -[string] - -[This has no matching separator] - -[Split] -[this] -[] -[string] -[now] -[] -``` diff --git a/docs/csview_api.md b/docs/csview_api.md index d28e3ed2..eafc6854 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -1,14 +1,23 @@ -# STC [csview](../include/stc/csview.h): Null-terminated UTF8 String View +# STC [csview](../include/stc/csview.h): Sub-string View ![String](pics/string.jpg) -The type **csview** is a ***null-terminated*** string view and refers to a constant contiguous sequence of -char-elements with the first element of the sequence at position zero. The implementation holds two -members: a pointer to constant char and a size. See [csubstr](csubstr_api.md) for a ***non null-terminated*** -string view/span type. +The type **csview** is a non-null terminated string view and can refer to a constant contiguous sequence of +char-elements with the first element of the sequence at position zero. The implementation holds two members: +a pointer to constant char and a size. -Because **csview** is null-terminated, it can be an efficient replacent for `const char*`. It never -allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string -storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations. +Because **csview** is non-null terminated, it is not an ideal replacent view for `const char*` - see [crawstr](crawstr_api.md) +for that. **csview** never allocates memory, and therefore need not be destructed. Its lifetime is limited by +the source string storage. It keeps the length of the string, and does not need to call *strlen()* to acquire +the length. + +- **csview** iterators works on UTF8 codepoints - like **cstr** and **crawstr** (see Example 2). +- Because it is null-terminated, it must be printed the following way: +```c +printf("%.*s", c_SV(sstr)); +``` + +See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional +description. ## Header file @@ -22,52 +31,64 @@ All csview definitions and prototypes are available by including a single header ## Methods ```c -csview c_sv(const char literal_only[]); // construct from literal, no strlen() -csview csview_from(const char* str); // construct from const char* +csview c_sv(const char literal_only[]); // construct from literal, no strlen() +csview c_sv(const char* str, intptr_t n); // construct from str and length n +csview csview_from(const char* str); // construct from const char* +csview csview_from_n(const char* str, intptr_t n); // alias for c_sv(str, n) + +intptr_t csview_size(csview sv); +bool csview_empty(csview sv); +void csview_clear(csview* self); + +bool csview_equals(csview sv, const char* str); +intptr_t csview_equals_sv(csview sv, csview find); +intptr_t csview_find(csview sv, const char* str); +intptr_t csview_find_sv(csview sv, csview find); +bool csview_contains(csview sv, const char* str); +bool csview_starts_with(csview sv, const char* str); +bool csview_ends_with(csview sv, const char* str); +csview csview_substr(csview sv, intptr_t pos, intptr_t n); +csview csview_slice(csview sv, intptr_t pos1, intptr_t pos2); + +csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); // negative pos count from end +csview csview_slice_ex(csview sv, intptr_t pos1, intptr_t pos2); // negative pos1, pos2 count from end +csview csview_token(csview sv, const char* sep, intptr_t* start); // *start > sv.size after last token +``` -intptr_t csview_size(csview sv); -bool csview_empty(csview sv); // check if size == 0 -void csview_clear(csview* self); -csubstr csview_ss(csview sv); // convert to csubstr type +#### UTF8 methods +```c +intptr_t csview_u8_size(csview sv); +csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len); +bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c + +csview_iter csview_begin(const csview* self); +csview_iter csview_end(const csview* self); +void csview_next(csview_iter* it); // utf8 codepoint step, not byte! +csview_iter csview_advance(csview_iter it, intptr_t n); +``` -bool csview_equals(csview sv, const char* str); -intptr_t csview_find(csview sv, const char* str); -bool csview_contains(csview sv, const char* str); -bool csview_starts_with(csview sv, const char* str); -bool csview_ends_with(csview sv, const char* str); +#### cstr methods returning csview +```c +csview cstr_slice(const cstr* self, intptr_t pos1, intptr_t pos2); +csview cstr_slice_ex(const cstr* self, intptr_t pos1, intptr_t pos2); // see csview_slice_ex() +csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n); +csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n); // see csview_substr_ex() +csview cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); ``` +#### Iterate tokens with *c_fortoken*, *c_fortoken_sv* -#### UTF8 methods +To iterate tokens in an input string separated by a string: ```c -intptr_t csview_u8_size(csview sv); -bool csview_valid_utf8(csview sv); // depends on src/utf8code.c - -csview_iter csview_begin(const csview* self); -csview_iter csview_end(const csview* self); -void csview_next(csview_iter* it); // utf8 codepoint step, not byte! -csview_iter csview_advance(csview_iter it, intptr_t n); - - // from utf8.h -intptr_t utf8_size(const char *s); -intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes -const char* utf8_at(const char *s, intptr_t index); // from UTF8 index to char* position -intptr_t utf8_pos(const char* s, intptr_t index); // from UTF8 index to byte index position -unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4 - // implemented in src/utf8code.c: -bool utf8_valid(const char* s); -bool utf8_valid_n(const char* s, intptr_t nbytes); -uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, return state. -unsigned utf8_encode(char *out, uint32_t codepoint); // encode unicode cp into out buffer -uint32_t utf8_peek(const char* s); // codepoint value of character at s -uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative) +c_fortoken (i, "hello, one, two, three", ", ") + printf("token: %.*s\n", c_SV(i.token)); ``` #### Helper methods ```c -int csview_cmp(const csview* x, const csview* y); -int csview_icmp(const csview* x, const csview* y); // depends on src/utf8code.c: -bool csview_eq(const csview* x, const csview* y); -uint64_t csview_hash(const csview* x); +int csview_cmp(const csview* x, const csview* y); +int csview_icmp(const csview* x, const csview* y); +bool csview_eq(const csview* x, const csview* y); +uint64_t csview_hash(const csview* x); ``` ## Types @@ -78,36 +99,46 @@ uint64_t csview_hash(const csview* x); | `csview_value` | `char` | The string element type | | `csview_iter` | `struct { csview_value *ref; }` | UTF8 iterator | -## Example: UTF8 iteration and case conversion +## Constants and macros + +| Name | Value | Usage | +|:---------------|:---------------------|:---------------------------------------------| +| `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` | + +## Example ```c -#define i_import +#define i_implement #include #include int main(void) { - cstr str = cstr_from("Liberté, égalité, fraternité."); - csview sv = cstr_sv(&str); - - c_foreach (i, csview, sv) - printf("%.*s ", c_SS(i.u8.chr)); - puts(""); - - cstr_uppercase(&str); - printf("%s\n", cstr_str(&str)); - - cstr_drop(&str); + cstr str1 = cstr_from("We think in generalities, but we live in details."); + // (quoting Alfred N. Whitehead) + + csview ss1 = cstr_substr_ex(&str1, 3, 5); // "think" + intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 + csview ss2 = cstr_substr_ex(&str1, pos, 4); // get "live" + csview ss3 = cstr_slice_ex(&str1, -8, -1); // get "details" + printf("%.*s %.*s %.*s\n", + c_SV(ss1), c_SV(ss2), c_SV(ss3)); + cstr s1 = cstr_lit("Apples are red"); + cstr s2 = cstr_from_sv(cstr_substr_ex(&s1, -3, 3)); // "red" + cstr s3 = cstr_from_sv(cstr_substr_ex(&s1, 0, 6)); // "Apples" + printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); + + c_drop(cstr, &str1, &s1, &s2, &s3); } ``` Output: ``` -L i b e r t é , é g a l i t é , f r a t e r n i t é . -LIBERTÉ, ÉGALITÉ, FRATERNITÉ. +think live details +red Apples ``` -### Example 2: UTF8 replace +### Example 2: UTF8 handling ```c -#define i_import // include dependent utf8 definitions. +#define i_import // include dependent cstr, utf8 and cregex function definitions. #include int main(void) @@ -118,7 +149,7 @@ int main(void) printf("%s\n", cstr_str(&s1)); c_foreach (i, cstr, s1) - printf("%.*s,", c_SS(i.u8.chr)); // u8.chr is a csubstr + printf("%.*s,", c_SV(i.u8.chr)); cstr_drop(&s1); } @@ -128,3 +159,63 @@ Output: hell😀 wørld h,e,l,l,😀, ,w,ø,r,l,d, ``` + +### Example 3: csview tokenizer (string split) +Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, +and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. +```c +#include +#include + +void print_split(csview input, const char* sep) +{ + c_fortoken_sv (i, input, sep) + printf("[%.*s]\n", c_SV(i.token)); + puts(""); +} +#define i_implement +#include +#define i_key_str +#include + +cstack_str string_split(csview input, const char* sep) +{ + cstack_str out = cstack_str_init(); + + c_fortoken_sv (i, input, sep) + cstack_str_push(&out, cstr_from_sv(i.token)); + + return out; +} + +int main(void) +{ + print_split(c_sv("//This is a//double-slash//separated//string"), "//"); + print_split(c_sv("This has no matching separator"), "xx"); + + cstack_str s = string_split(c_sv("Split,this,,string,now,"), ","); + + c_foreach (i, cstack_str, s) + printf("[%s]\n", cstr_str(i.ref)); + puts(""); + + cstack_str_drop(&s); +} +``` +Output: +``` +[] +[This is a] +[double-slash] +[separated] +[string] + +[This has no matching separator] + +[Split] +[this] +[] +[string] +[now] +[] +``` diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 1b4a2277..e5422adc 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -130,14 +130,13 @@ typedef const char* ccharptr; #define ccharptr_clone(s) (s) #define ccharptr_drop(p) ((void)p) -#define c_ss(...) c_MACRO_OVERLOAD(c_ss, __VA_ARGS__) -#define c_ss_1(literal) c_ss_2(literal, c_litstrlen(literal)) -#define c_ss_2(str, n) (c_LITERAL(csubstr){str, n}) -#define c_SS(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SS(ss)); - -#define c_sv(literal) c_sv_2(literal, c_litstrlen(literal)) +#define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) +#define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal)) #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) -#define c_SV(sv) c_SS(sv) // [deprecated] - unneeded +#define c_SV(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SV(ss)); + +#define c_rs(literal) c_rs_2(literal, c_litstrlen(literal)) +#define c_rs_2(str, n) (c_LITERAL(crawstr){str, n}) #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) diff --git a/include/stc/crawstr.h b/include/stc/crawstr.h new file mode 100644 index 00000000..7cf62e94 --- /dev/null +++ b/include/stc/crawstr.h @@ -0,0 +1,116 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#define _i_inc_utf8 +#include "utf8.h" + +#ifndef CRAWSTR_H_INCLUDED +#define CRAWSTR_H_INCLUDED + +#define crawstr_init() c_rs("") +#define crawstr_drop(p) c_default_drop(p) +#define crawstr_clone(rs) c_default_clone(rs) + +STC_INLINE crawstr crawstr_from(const char* str) + { return c_rs_2(str, c_strlen(str)); } +STC_INLINE void crawstr_clear(crawstr* self) { *self = crawstr_init(); } +STC_INLINE csview crawstr_sv(crawstr rs) { return c_sv_2(rs.str, rs.size); } + +STC_INLINE intptr_t crawstr_size(crawstr rs) { return rs.size; } +STC_INLINE bool crawstr_empty(crawstr rs) { return rs.size == 0; } + +STC_INLINE bool crawstr_equals(crawstr rs, const char* str) { + intptr_t n = c_strlen(str); + return rs.size == n && !c_memcmp(rs.str, str, n); +} + +STC_INLINE intptr_t crawstr_find(crawstr rs, const char* search) { + char* res = cstrnstrn(rs.str, search, rs.size, c_strlen(search)); + return res ? (res - rs.str) : c_NPOS; +} + +STC_INLINE bool crawstr_contains(crawstr rs, const char* str) + { return crawstr_find(rs, str) != c_NPOS; } + +STC_INLINE bool crawstr_starts_with(crawstr rs, const char* str) { + intptr_t n = c_strlen(str); + return n > rs.size ? false : !c_memcmp(rs.str, str, n); +} + +STC_INLINE bool crawstr_ends_with(crawstr rs, const char* str) { + intptr_t n = c_strlen(str); + return n > rs.size ? false : !c_memcmp(rs.str + rs.size - n, str, n); +} + +/* utf8 iterator */ +STC_INLINE crawstr_iter crawstr_begin(const crawstr* self) { + if (!self->size) return c_LITERAL(crawstr_iter){.ref = NULL}; + return c_LITERAL(crawstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}}; +} +STC_INLINE crawstr_iter crawstr_end(const crawstr* self) { + (void)self; return c_LITERAL(crawstr_iter){.ref = NULL}; +} +STC_INLINE void crawstr_next(crawstr_iter* it) { + it->ref += it->u8.chr.size; + it->u8.chr.size = utf8_chr_size(it->ref); + if (!*it->ref) it->ref = NULL; +} +STC_INLINE crawstr_iter crawstr_advance(crawstr_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (!*it.ref) it.ref = NULL; + return it; +} + +/* utf8 size */ +STC_INLINE intptr_t crawstr_u8_size(crawstr rs) + { return utf8_size_n(rs.str, rs.size); } + +/* utf8 validation: depends on src/utf8code.c */ +STC_INLINE bool crawstr_valid_utf8(crawstr rs) + { return utf8_valid_n(rs.str, rs.size); } + +/* utf8 ignore case cmp: depends on src/utf8code.c */ +STC_INLINE int crawstr_icmp(const crawstr* x, const crawstr* y) + { return utf8_icmp_sv(c_sv_2(x->str, x->size), c_sv_2(y->str, y->size)); } + + +STC_INLINE int crawstr_cmp(const crawstr* x, const crawstr* y) { + intptr_t n = x->size < y->size ? x->size : y->size; + int c = c_memcmp(x->str, y->str, n); + return c ? c : (int)(x->size - y->size); +} + +STC_INLINE bool crawstr_eq(const crawstr* x, const crawstr* y) + { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } + +STC_INLINE uint64_t crawstr_hash(const crawstr *self) + { return cfasthash(self->str, self->size); } + +#endif // CRAWSTR_H_INCLUDED +#undef i_static +#undef i_header +#undef i_implement +#undef i_import +#undef i_opt diff --git a/include/stc/cregex.h b/include/stc/cregex.h index 3aab3c8b..bce94b04 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -34,7 +34,7 @@ THE SOFTWARE. */ #include #include -#include "forward.h" // csubstr +#include "forward.h" // csview #include "ccommon.h" enum { @@ -82,7 +82,7 @@ typedef struct { typedef struct { const cregex* re; const char* input; - csubstr match[CREG_MAX_CAPTURES]; + csview match[CREG_MAX_CAPTURES]; } cregex_iter; #define c_formatch(it, Re, Input) \ @@ -115,11 +115,11 @@ int cregex_captures(const cregex* re); /* return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */ #define cregex_find(...) c_MACRO_OVERLOAD(cregex_find, __VA_ARGS__) #define cregex_find_3(re, input, match) cregex_find_4(re, input, match, CREG_DEFAULT) -int cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags); +int cregex_find_4(const cregex* re, const char* input, csview match[], int mflags); -/* find with csubstr as input. */ -STC_INLINE int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]) { - csubstr *mp = NULL; +/* find with csview as input. */ +STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { + csview *mp = NULL; if (match) { match[0] = input; mp = match; } return cregex_find(re, input.str, mp, CREG_STARTEND); } @@ -129,27 +129,27 @@ STC_INLINE int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]) #define cregex_find_pattern_3(pattern, input, match) \ cregex_find_pattern_4(pattern, input, match, CREG_DEFAULT) int cregex_find_pattern_4(const char* pattern, const char* input, - csubstr match[], int cmflags); + csview match[], int cmflags); STC_INLINE bool cregex_is_match(const cregex* re, const char* input) { return cregex_find_4(re, input, NULL, CREG_DEFAULT) == CREG_OK; } -/* replace csubstr input with replace using regular expression pattern */ -#define cregex_replace_ss(...) c_MACRO_OVERLOAD(cregex_replace_ss, __VA_ARGS__) -#define cregex_replace_ss_3(pattern, input, replace) \ - cregex_replace_ss_4(pattern, input, replace, INT32_MAX) -#define cregex_replace_ss_4(pattern, input, replace, count) \ - cregex_replace_ss_6(pattern, input, replace, count, NULL, CREG_DEFAULT) -cstr cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, - bool (*transform)(int group, csubstr match, cstr* result), int rflags); +/* replace csview input with replace using regular expression pattern */ +#define cregex_replace_sv(...) c_MACRO_OVERLOAD(cregex_replace_sv, __VA_ARGS__) +#define cregex_replace_sv_3(pattern, input, replace) \ + cregex_replace_sv_4(pattern, input, replace, INT32_MAX) +#define cregex_replace_sv_4(pattern, input, replace, count) \ + cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT) +cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, + bool (*transform)(int group, csview match, cstr* result), int rflags); /* replace input with replace using regular expression */ #define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__) #define cregex_replace_3(re, input, replace) cregex_replace_4(re, input, replace, INT32_MAX) STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char* replace, int count) { - csubstr ss = {input, c_strlen(input)}; - return cregex_replace_ss_4(re, ss, replace, count); + csview sv = {input, c_strlen(input)}; + return cregex_replace_sv_4(re, sv, replace, count); } /* replace + compile RE pattern, and extra arguments */ @@ -159,7 +159,7 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char #define cregex_replace_pattern_4(pattern, input, replace, count) \ cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*transform)(int group, csubstr match, cstr* result), int crflags); + bool (*transform)(int group, csview match, cstr* result), int crflags); /* destroy regex */ void cregex_drop(cregex* re); diff --git a/include/stc/cstr.h b/include/stc/cstr.h index ce398628..7f4bad97 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -75,7 +75,7 @@ STC_API char* cstr_reserve(cstr* self, intptr_t cap); STC_API void cstr_shrink_to_fit(cstr* self); STC_API char* cstr_resize(cstr* self, intptr_t size, char value); STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); -STC_API intptr_t cstr_find_ss(const cstr* self, csubstr search); +STC_API intptr_t cstr_find_sv(const cstr* self, csview search); STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_uninit(cstr *self, intptr_t len); @@ -85,7 +85,7 @@ STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); STC_API cstr cstr_from_fmt(const char* fmt, ...); STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...); -STC_API cstr cstr_replace_ss(csubstr sv, csubstr search, csubstr repl, int32_t count); +STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); STC_API uint64_t cstr_hash(const cstr *self); STC_INLINE cstr_buf cstr_buffer(cstr* s) { @@ -93,12 +93,12 @@ STC_INLINE cstr_buf cstr_buffer(cstr* s) { ? c_LITERAL(cstr_buf){s->lon.data, cstr_l_size(s), cstr_l_cap(s)} : c_LITERAL(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap}; } -STC_INLINE csview cstr_sv(const cstr* s) { - return cstr_is_long(s) ? c_sv_2(s->lon.data, cstr_l_size(s)) - : c_sv_2(s->sml.data, cstr_s_size(s)); +STC_INLINE crawstr cstr_rs(const cstr* s) { + return cstr_is_long(s) ? c_rs_2(s->lon.data, cstr_l_size(s)) + : c_rs_2(s->sml.data, cstr_s_size(s)); } -STC_INLINE csubstr cstr_ss(const cstr* s) - { csview sv = cstr_sv(s); return c_ss_2(sv.str, sv.size); } +STC_INLINE csview cstr_sv(const cstr* s) + { crawstr rs = cstr_rs(s); return c_sv_2(rs.str, rs.size); } STC_INLINE cstr cstr_init(void) { return cstr_null; } @@ -112,12 +112,12 @@ STC_INLINE cstr cstr_from_n(const char* str, const intptr_t len) { STC_INLINE cstr cstr_from(const char* str) { return cstr_from_n(str, c_strlen(str)); } -STC_INLINE cstr cstr_from_ss(csubstr sv) - { return cstr_from_n(sv.str, sv.size); } - STC_INLINE cstr cstr_from_sv(csview sv) { return cstr_from_n(sv.str, sv.size); } +STC_INLINE cstr cstr_from_rs(crawstr rs) + { return cstr_from_n(rs.str, rs.size); } + STC_INLINE cstr cstr_with_size(const intptr_t size, const char value) { cstr s; c_memset(_cstr_init(&s, size, size), value, size); @@ -144,8 +144,8 @@ STC_INLINE cstr cstr_move(cstr* self) { } STC_INLINE cstr cstr_clone(cstr s) { - csview sv = cstr_sv(&s); - return cstr_from_n(sv.str, sv.size); + crawstr rs = cstr_rs(&s); + return cstr_from_n(rs.str, rs.size); } STC_INLINE void cstr_drop(cstr* self) { @@ -175,9 +175,9 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self) // utf8 methods defined in/depending on src/utf8code.c: -extern cstr cstr_casefold_ss(csubstr sv); -extern cstr cstr_tolower_ss(csubstr sv); -extern cstr cstr_toupper_ss(csubstr sv); +extern cstr cstr_casefold_sv(csview sv); +extern cstr cstr_tolower_sv(csview sv); +extern cstr cstr_toupper_sv(csview sv); extern cstr cstr_tolower(const char* str); extern cstr cstr_toupper(const char* str); extern void cstr_lowercase(cstr* self); @@ -198,9 +198,9 @@ STC_INLINE intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx) STC_INLINE const char* cstr_u8_at(const cstr* self, intptr_t u8idx) { return utf8_at(cstr_str(self), u8idx); } -STC_INLINE csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx) { +STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { const char* str = cstr_str(self); - csubstr sv; + csview sv; sv.str = utf8_at(str, u8idx); sv.size = utf8_chr_size(sv.str); return sv; @@ -209,9 +209,9 @@ STC_INLINE csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx) { // utf8 iterator STC_INLINE cstr_iter cstr_begin(const cstr* self) { - csview sv = cstr_sv(self); - if (!sv.size) return c_LITERAL(cstr_iter){.ref = NULL}; - return c_LITERAL(cstr_iter){.u8 = {{sv.str, utf8_chr_size(sv.str)}}}; + crawstr rs = cstr_rs(self); + if (!rs.size) return c_LITERAL(cstr_iter){.ref = NULL}; + return c_LITERAL(cstr_iter){.u8 = {{rs.str, utf8_chr_size(rs.str)}}}; } STC_INLINE cstr_iter cstr_end(const cstr* self) { (void)self; return c_LITERAL(cstr_iter){NULL}; @@ -241,7 +241,7 @@ STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2) { return utf8_icmp(cstr_str(s1), cstr_str(s2)); } STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { - csview x = cstr_sv(s1), y = cstr_sv(s2); + crawstr x = cstr_rs(s1), y = cstr_rs(s2); return x.size == y.size && !c_memcmp(x.str, y.str, x.size); } @@ -249,7 +249,7 @@ STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { STC_INLINE bool cstr_equals(const cstr* self, const char* str) { return !strcmp(cstr_str(self), str); } -STC_INLINE bool cstr_equals_ss(const cstr* self, csubstr sv) +STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv) { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } STC_INLINE bool cstr_equals_s(const cstr* self, cstr s) @@ -271,14 +271,14 @@ STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search) STC_INLINE bool cstr_contains(const cstr* self, const char* search) { return strstr((char*)cstr_str(self), search) != NULL; } -STC_INLINE bool cstr_contains_ss(const cstr* self, csubstr search) - { return cstr_find_ss(self, search) != c_NPOS; } +STC_INLINE bool cstr_contains_sv(const cstr* self, csview search) + { return cstr_find_sv(self, search) != c_NPOS; } STC_INLINE bool cstr_contains_s(const cstr* self, cstr search) { return strstr((char*)cstr_str(self), cstr_str(&search)) != NULL; } -STC_INLINE bool cstr_starts_with_ss(const cstr* self, csubstr sub) { +STC_INLINE bool cstr_starts_with_sv(const cstr* self, csview sub) { if (sub.size > cstr_size(self)) return false; return !c_memcmp(cstr_str(self), sub.str, sub.size); } @@ -290,43 +290,43 @@ STC_INLINE bool cstr_starts_with(const cstr* self, const char* sub) { } STC_INLINE bool cstr_starts_with_s(const cstr* self, cstr sub) - { return cstr_starts_with_ss(self, cstr_ss(&sub)); } + { return cstr_starts_with_sv(self, cstr_sv(&sub)); } STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) { - csubstr sv = cstr_ss(self); + csview sv = cstr_sv(self); intptr_t len = c_strlen(sub); - return len <= sv.size && !utf8_icmp_ss(sv, c_ss(sub, len)); + return len <= sv.size && !utf8_icmp_sv(sv, c_sv(sub, len)); } -STC_INLINE bool cstr_ends_with_ss(const cstr* self, csubstr sub) { - csview sv = cstr_sv(self); - if (sub.size > sv.size) return false; - return !c_memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); +STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) { + crawstr rs = cstr_rs(self); + if (sub.size > rs.size) return false; + return !c_memcmp(rs.str + rs.size - sub.size, sub.str, sub.size); } STC_INLINE bool cstr_ends_with_s(const cstr* self, cstr sub) - { return cstr_ends_with_ss(self, cstr_ss(&sub)); } + { return cstr_ends_with_sv(self, cstr_sv(&sub)); } STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub) - { return cstr_ends_with_ss(self, c_ss(sub, c_strlen(sub))); } + { return cstr_ends_with_sv(self, c_sv(sub, c_strlen(sub))); } STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { - csview sv = cstr_sv(self); + crawstr rs = cstr_rs(self); intptr_t n = c_strlen(sub); - return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub); + return n <= rs.size && !utf8_icmp(rs.str + rs.size - n, sub); } STC_INLINE char* cstr_assign(cstr* self, const char* str) { return cstr_assign_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_assign_ss(cstr* self, csubstr sv) +STC_INLINE char* cstr_assign_sv(cstr* self, csview sv) { return cstr_assign_n(self, sv.str, sv.size); } STC_INLINE char* cstr_copy(cstr* self, cstr s) { - csview sv = cstr_sv(&s); - return cstr_assign_n(self, sv.str, sv.size); + crawstr rs = cstr_rs(&s); + return cstr_assign_n(self, rs.str, rs.size); } @@ -334,51 +334,51 @@ STC_INLINE char* cstr_push(cstr* self, const char* chr) { return cstr_append_n(self, chr, utf8_chr_size(chr)); } STC_INLINE void cstr_pop(cstr* self) { - csview sv = cstr_sv(self); - const char* s = sv.str + sv.size; + crawstr rs = cstr_rs(self); + const char* s = rs.str + rs.size; while ((*--s & 0xC0) == 0x80) ; - _cstr_set_size(self, (s - sv.str)); + _cstr_set_size(self, (s - rs.str)); } STC_INLINE char* cstr_append(cstr* self, const char* str) { return cstr_append_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_append_ss(cstr* self, csubstr sv) +STC_INLINE char* cstr_append_sv(cstr* self, csview sv) { return cstr_append_n(self, sv.str, sv.size); } STC_INLINE char* cstr_append_s(cstr* self, cstr s) - { return cstr_append_ss(self, cstr_ss(&s)); } + { return cstr_append_sv(self, cstr_sv(&s)); } #define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__) #define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, INT32_MAX) STC_INLINE void cstr_replace_4(cstr* self, const char* search, const char* repl, int32_t count) { - cstr_take(self, cstr_replace_ss(cstr_ss(self), c_ss(search, c_strlen(search)), - c_ss(repl, c_strlen(repl)), count)); + cstr_take(self, cstr_replace_sv(cstr_sv(self), c_sv(search, c_strlen(search)), + c_sv(repl, c_strlen(repl)), count)); } -STC_INLINE void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl) { +STC_INLINE void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl) { char* d = _cstr_internal_move(self, pos + len, pos + repl.size); c_memcpy(d + pos, repl.str, repl.size); } STC_INLINE void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl) - { cstr_replace_at_ss(self, pos, len, c_ss(repl, c_strlen(repl))); } + { cstr_replace_at_sv(self, pos, len, c_sv(repl, c_strlen(repl))); } STC_INLINE void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl) - { cstr_replace_at_ss(self, pos, len, cstr_ss(&repl)); } + { cstr_replace_at_sv(self, pos, len, cstr_sv(&repl)); } -STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl) - { cstr_replace_at_ss(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } +STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl) + { cstr_replace_at_sv(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } STC_INLINE void cstr_insert(cstr* self, intptr_t pos, const char* str) - { cstr_replace_at_ss(self, pos, 0, c_ss(str, c_strlen(str))); } + { cstr_replace_at_sv(self, pos, 0, c_sv(str, c_strlen(str))); } -STC_INLINE void cstr_insert_ss(cstr* self, intptr_t pos, csubstr sv) - { cstr_replace_at_ss(self, pos, 0, sv); } +STC_INLINE void cstr_insert_sv(cstr* self, intptr_t pos, csview sv) + { cstr_replace_at_sv(self, pos, 0, sv); } STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) - { cstr_replace_at_ss(self, pos, 0, cstr_ss(&s)); } + { cstr_replace_at_sv(self, pos, 0, cstr_sv(&s)); } STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } @@ -397,7 +397,7 @@ fn_tocase[] = {{tolower, utf8_casefold}, {tolower, utf8_tolower}, {toupper, utf8_toupper}}; -static cstr cstr_tocase(csubstr sv, int k) { +static cstr cstr_tocase(csview sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); const char *end = sv.str + sv.size; @@ -418,26 +418,26 @@ static cstr cstr_tocase(csubstr sv, int k) { return out; } -cstr cstr_casefold_ss(csubstr sv) +cstr cstr_casefold_sv(csview sv) { return cstr_tocase(sv, 0); } -cstr cstr_tolower_ss(csubstr sv) +cstr cstr_tolower_sv(csview sv) { return cstr_tocase(sv, 1); } -cstr cstr_toupper_ss(csubstr sv) +cstr cstr_toupper_sv(csview sv) { return cstr_tocase(sv, 2); } cstr cstr_tolower(const char* str) - { return cstr_tolower_ss(c_ss(str, c_strlen(str))); } + { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } cstr cstr_toupper(const char* str) - { return cstr_toupper_ss(c_ss(str, c_strlen(str))); } + { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } void cstr_lowercase(cstr* self) - { cstr_take(self, cstr_tolower_ss(cstr_ss(self))); } + { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } void cstr_uppercase(cstr* self) - { cstr_take(self, cstr_toupper_ss(cstr_ss(self))); } + { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } bool cstr_valid_utf8(const cstr* self) { return utf8_valid(cstr_str(self)); } @@ -449,14 +449,14 @@ bool cstr_valid_utf8(const cstr* self) #define CSTR_C_INCLUDED STC_DEF uint64_t cstr_hash(const cstr *self) { - csview sv = cstr_sv(self); - return cfasthash(sv.str, sv.size); + crawstr rs = cstr_rs(self); + return cfasthash(rs.str, rs.size); } -STC_DEF intptr_t cstr_find_ss(const cstr* self, csubstr search) { - csview sv = cstr_sv(self); - char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); - return res ? (res - sv.str) : c_NPOS; +STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { + crawstr rs = cstr_rs(self); + char* res = cstrnstrn(rs.str, search.str, rs.size, search.size); + return res ? (res - rs.str) : c_NPOS; } STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { @@ -530,10 +530,10 @@ STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) { } STC_DEF intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { - csview sv = cstr_sv(self); - if (pos > sv.size) return c_NPOS; - const char* res = strstr((char*)sv.str + pos, search); - return res ? (res - sv.str) : c_NPOS; + crawstr rs = cstr_rs(self); + if (pos > rs.size) return c_NPOS; + const char* res = strstr((char*)rs.str + pos, search); + return res ? (res - rs.str) : c_NPOS; } STC_DEF char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { @@ -583,7 +583,7 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } } -STC_DEF cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, int32_t count) { +STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { cstr out = cstr_null; intptr_t from = 0; char* res; if (!count) count = INT32_MAX; diff --git a/include/stc/csubstr.h b/include/stc/csubstr.h deleted file mode 100644 index c7a43052..00000000 --- a/include/stc/csubstr.h +++ /dev/null @@ -1,211 +0,0 @@ -/* MIT License - * - * Copyright (c) 2023 Tyge Løvset - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#define i_header // external linkage by default. override with i_static. -#define _i_inc_utf8 -#include "utf8.h" - -#ifndef CSUBSTR_H_INCLUDED -#define CSUBSTR_H_INCLUDED - -#define csubstr_init() c_ss_1("") -#define csubstr_drop(p) c_default_drop(p) -#define csubstr_clone(ss) c_default_clone(ss) -#define csubstr_from_n(str, n) c_ss_2(str, n) - -STC_API csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos); -STC_API intptr_t csubstr_find_ss(csubstr ss, csubstr search); -STC_API uint64_t csubstr_hash(const csubstr *self); -STC_API csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2); -STC_API csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n); -STC_API csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start); - -STC_INLINE csubstr csubstr_from(const char* str) - { return c_LITERAL(csubstr){str, c_strlen(str)}; } -STC_INLINE void csubstr_clear(csubstr* self) { *self = csubstr_init(); } -STC_INLINE intptr_t csubstr_size(csubstr ss) { return ss.size; } -STC_INLINE bool csubstr_empty(csubstr ss) { return ss.size == 0; } - -STC_INLINE bool csubstr_equals_ss(csubstr ss1, csubstr ss2) - { return ss1.size == ss2.size && !c_memcmp(ss1.str, ss2.str, ss1.size); } - -STC_INLINE bool csubstr_equals(csubstr ss, const char* str) - { return csubstr_equals_ss(ss, c_ss_2(str, c_strlen(str))); } - -STC_INLINE intptr_t csubstr_find(csubstr ss, const char* str) - { return csubstr_find_ss(ss, c_ss_2(str, c_strlen(str))); } - -STC_INLINE bool csubstr_contains(csubstr ss, const char* str) - { return csubstr_find(ss, str) != c_NPOS; } - -STC_INLINE bool csubstr_starts_with(csubstr ss, const char* str) { - intptr_t n = c_strlen(str); - return n > ss.size ? false : !c_memcmp(ss.str, str, n); -} - -STC_INLINE bool csubstr_ends_with(csubstr ss, const char* str) { - intptr_t n = c_strlen(str); - return n > ss.size ? false : !c_memcmp(ss.str + ss.size - n, str, n); -} - -STC_INLINE csubstr csubstr_substr(csubstr ss, intptr_t pos, intptr_t n) { - if (pos + n > ss.size) n = ss.size - pos; - ss.str += pos, ss.size = n; - return ss; -} - -STC_INLINE csubstr csubstr_slice(csubstr ss, intptr_t p1, intptr_t p2) { - if (p2 > ss.size) p2 = ss.size; - ss.str += p1, ss.size = p2 > p1 ? p2 - p1 : 0; - return ss; -} - -/* utf8 iterator */ -STC_INLINE csubstr_iter csubstr_begin(const csubstr* self) { - if (!self->size) return c_LITERAL(csubstr_iter){NULL}; - return c_LITERAL(csubstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, - self->str + self->size}}; -} -STC_INLINE csubstr_iter csubstr_end(const csubstr* self) { - return c_LITERAL(csubstr_iter){.u8 = {{NULL}, self->str + self->size}}; -} -STC_INLINE void csubstr_next(csubstr_iter* it) { - it->ref += it->u8.chr.size; - it->u8.chr.size = utf8_chr_size(it->ref); - if (it->ref == it->u8.end) it->ref = NULL; -} - -/* utf8 */ -STC_INLINE intptr_t csubstr_u8_size(csubstr ss) - { return utf8_size_n(ss.str, ss.size); } - -STC_INLINE csubstr csubstr_u8_substr(csubstr ss, intptr_t bytepos, intptr_t u8len) { - ss.str += bytepos; - ss.size = utf8_pos(ss.str, u8len); - return ss; -} - -STC_INLINE bool csubstr_valid_utf8(csubstr ss) // depends on src/utf8code.c - { return utf8_valid_n(ss.str, ss.size); } - -#define c_fortoken_ss(it, inputss, sep) \ - for (struct { csubstr _inp, token, *ref; const char *_sep; intptr_t pos; } \ - it = {._inp=inputss, .token=it._inp, .ref=&it.token, ._sep=sep} \ - ; it.pos <= it._inp.size && (it.token = csubstr_token(it._inp, it._sep, &it.pos)).str ; ) - -#define c_fortoken(it, input, sep) \ - c_fortoken_ss(it, csubstr_from(input), sep) - -/* ---- Container helper functions ---- */ - -STC_INLINE int csubstr_cmp(const csubstr* x, const csubstr* y) { - intptr_t n = x->size < y->size ? x->size : y->size; - int c = c_memcmp(x->str, y->str, n); - return c ? c : (int)(x->size - y->size); -} - -STC_INLINE int csubstr_icmp(const csubstr* x, const csubstr* y) - { return utf8_icmp_ss(*x, *y); } - -STC_INLINE bool csubstr_eq(const csubstr* x, const csubstr* y) - { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } - -#endif // CSUBSTR_H_INCLUDED - -/* csubstr interaction with cstr: */ -#ifdef CSTR_H_INCLUDED - -STC_INLINE csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n) - { return csubstr_substr(cstr_ss(self), pos, n); } - -STC_INLINE csubstr cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) - { return csubstr_slice(cstr_ss(self), p1, p2); } - -STC_INLINE csubstr cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n) - { return csubstr_substr_ex(cstr_ss(self), pos, n); } - -STC_INLINE csubstr cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) - { return csubstr_slice_ex(cstr_ss(self), p1, p2); } - -STC_INLINE csubstr cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) - { return csubstr_u8_substr(cstr_ss(self), bytepos, u8len); } -#endif - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement || defined i_static -#ifndef CSUBSTR_C_INCLUDED -#define CSUBSTR_C_INCLUDED - -STC_DEF csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (it.ref == it.u8.end) it.ref = NULL; - return it; -} - -STC_DEF intptr_t csubstr_find_ss(csubstr ss, csubstr search) { - char* res = cstrnstrn(ss.str, search.str, ss.size, search.size); - return res ? (res - ss.str) : c_NPOS; -} - -STC_DEF uint64_t csubstr_hash(const csubstr *self) - { return cfasthash(self->str, self->size); } - -STC_DEF csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n) { - if (pos < 0) { - pos += ss.size; - if (pos < 0) pos = 0; - } - if (pos > ss.size) pos = ss.size; - if (pos + n > ss.size) n = ss.size - pos; - ss.str += pos, ss.size = n; - return ss; -} - -STC_DEF csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2) { - if (p1 < 0) { - p1 += ss.size; - if (p1 < 0) p1 = 0; - } - if (p2 < 0) p2 += ss.size; - if (p2 > ss.size) p2 = ss.size; - ss.str += p1, ss.size = (p2 > p1 ? p2 - p1 : 0); - return ss; -} - -STC_DEF csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start) { - intptr_t sep_size = c_strlen(sep); - csubstr slice = {ss.str + *start, ss.size - *start}; - const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); - csubstr tok = {slice.str, res ? (res - slice.str) : slice.size}; - *start += tok.size + sep_size; - return tok; -} -#endif // CSUBSTR_C_INCLUDED -#endif // i_implement -#undef i_static -#undef i_header -#undef i_implement -#undef i_import -#undef i_opt diff --git a/include/stc/csview.h b/include/stc/csview.h index 367258e4..2a051ddd 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,33 +20,39 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#define i_header // external linkage by default. override with i_static. #define _i_inc_utf8 #include "utf8.h" #ifndef CSVIEW_H_INCLUDED #define CSVIEW_H_INCLUDED -#define csview_init() c_sv("") +#define csview_init() c_sv_1("") #define csview_drop(p) c_default_drop(p) #define csview_clone(sv) c_default_clone(sv) +#define csview_from_n(str, n) c_sv_2(str, n) + +STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); +STC_API intptr_t csview_find_sv(csview sv, csview search); +STC_API uint64_t csview_hash(const csview *self); +STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); +STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); +STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); STC_INLINE csview csview_from(const char* str) - { return c_sv_2(str, c_strlen(str)); } + { return c_LITERAL(csview){str, c_strlen(str)}; } STC_INLINE void csview_clear(csview* self) { *self = csview_init(); } -STC_INLINE csubstr csview_ss(csview sv) { return c_ss_2(sv.str, sv.size); } - STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } -STC_INLINE bool csview_equals(csview sv, const char* str) { - intptr_t n = c_strlen(str); - return sv.size == n && !c_memcmp(sv.str, str, n); -} +STC_INLINE bool csview_equals_sv(csview sv1, csview sv2) + { return sv1.size == sv2.size && !c_memcmp(sv1.str, sv2.str, sv1.size); } -STC_INLINE intptr_t csview_find(csview sv, const char* search) { - char* res = cstrnstrn(sv.str, search, sv.size, c_strlen(search)); - return res ? (res - sv.str) : c_NPOS; -} +STC_INLINE bool csview_equals(csview sv, const char* str) + { return csview_equals_sv(sv, c_sv_2(str, c_strlen(str))); } + +STC_INLINE intptr_t csview_find(csview sv, const char* str) + { return csview_find_sv(sv, c_sv_2(str, c_strlen(str))); } STC_INLINE bool csview_contains(csview sv, const char* str) { return csview_find(sv, str) != c_NPOS; } @@ -61,40 +67,55 @@ STC_INLINE bool csview_ends_with(csview sv, const char* str) { return n > sv.size ? false : !c_memcmp(sv.str + sv.size - n, str, n); } +STC_INLINE csview csview_substr(csview sv, intptr_t pos, intptr_t n) { + if (pos + n > sv.size) n = sv.size - pos; + sv.str += pos, sv.size = n; + return sv; +} + +STC_INLINE csview csview_slice(csview sv, intptr_t p1, intptr_t p2) { + if (p2 > sv.size) p2 = sv.size; + sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; + return sv; +} + /* utf8 iterator */ STC_INLINE csview_iter csview_begin(const csview* self) { - if (!self->size) return c_LITERAL(csview_iter){.ref = NULL}; - return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}}; + if (!self->size) return c_LITERAL(csview_iter){NULL}; + return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, + self->str + self->size}}; } STC_INLINE csview_iter csview_end(const csview* self) { - (void)self; return c_LITERAL(csview_iter){.ref = NULL}; + return c_LITERAL(csview_iter){.u8 = {{NULL}, self->str + self->size}}; } STC_INLINE void csview_next(csview_iter* it) { it->ref += it->u8.chr.size; it->u8.chr.size = utf8_chr_size(it->ref); - if (!*it->ref) it->ref = NULL; -} -STC_INLINE csview_iter csview_advance(csview_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (!*it.ref) it.ref = NULL; - return it; + if (it->ref == it->u8.end) it->ref = NULL; } -/* utf8 size */ +/* utf8 */ STC_INLINE intptr_t csview_u8_size(csview sv) { return utf8_size_n(sv.str, sv.size); } -/* utf8 validation: depends on src/utf8code.c */ -STC_INLINE bool csview_valid_utf8(csview sv) +STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) { + sv.str += bytepos; + sv.size = utf8_pos(sv.str, u8len); + return sv; +} + +STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c { return utf8_valid_n(sv.str, sv.size); } -/* utf8 ignore case cmp: depends on src/utf8code.c */ -STC_INLINE int csview_icmp(const csview* x, const csview* y) - { return utf8_icmp_ss(c_ss_2(x->str, x->size), c_ss_2(y->str, y->size)); } +#define c_fortoken_sv(it, inputsv, sep) \ + for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \ + it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \ + ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).str ; ) +#define c_fortoken(it, input, sep) \ + c_fortoken_sv(it, csview_from(input), sep) + +/* ---- Container helper functions ---- */ STC_INLINE int csview_cmp(const csview* x, const csview* y) { intptr_t n = x->size < y->size ? x->size : y->size; @@ -102,13 +123,87 @@ STC_INLINE int csview_cmp(const csview* x, const csview* y) { return c ? c : (int)(x->size - y->size); } +STC_INLINE int csview_icmp(const csview* x, const csview* y) + { return utf8_icmp_sv(*x, *y); } + STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } -STC_INLINE uint64_t csview_hash(const csview *self) +#endif // CSVIEW_H_INCLUDED + +/* csview interaction with cstr: */ +#ifdef CSTR_H_INCLUDED + +STC_INLINE csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n) + { return csview_substr(cstr_sv(self), pos, n); } + +STC_INLINE csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) + { return csview_slice(cstr_sv(self), p1, p2); } + +STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n) + { return csview_substr_ex(cstr_sv(self), pos, n); } + +STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) + { return csview_slice_ex(cstr_sv(self), p1, p2); } + +STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) + { return csview_u8_substr(cstr_sv(self), bytepos, u8len); } +#endif + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined i_implement || defined i_static +#ifndef CSVIEW_C_INCLUDED +#define CSVIEW_C_INCLUDED + +STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (it.ref == it.u8.end) it.ref = NULL; + return it; +} + +STC_DEF intptr_t csview_find_sv(csview sv, csview search) { + char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); + return res ? (res - sv.str) : c_NPOS; +} + +STC_DEF uint64_t csview_hash(const csview *self) { return cfasthash(self->str, self->size); } -#endif // CSVIEW_H_INCLUDED +STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { + if (pos < 0) { + pos += sv.size; + if (pos < 0) pos = 0; + } + if (pos > sv.size) pos = sv.size; + if (pos + n > sv.size) n = sv.size - pos; + sv.str += pos, sv.size = n; + return sv; +} + +STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { + if (p1 < 0) { + p1 += sv.size; + if (p1 < 0) p1 = 0; + } + if (p2 < 0) p2 += sv.size; + if (p2 > sv.size) p2 = sv.size; + sv.str += p1, sv.size = (p2 > p1 ? p2 - p1 : 0); + return sv; +} + +STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { + intptr_t sep_size = c_strlen(sep); + csview slice = {sv.str + *start, sv.size - *start}; + const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); + csview tok = {slice.str, res ? (res - slice.str) : slice.size}; + *start += tok.size + sep_size; + return tok; +} +#endif // CSVIEW_C_INCLUDED +#endif // i_implement #undef i_static #undef i_header #undef i_implement diff --git a/include/stc/forward.h b/include/stc/forward.h index 5c9c4f4d..839be012 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -39,21 +39,8 @@ #define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL) #define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL) -// csubstr : non-null terminated string view -typedef const char csubstr_value; -typedef struct csubstr { - csubstr_value* str; - intptr_t size; -} csubstr; - -typedef union { - csubstr_value* ref; - struct { csubstr chr; csubstr_value* end; } u8; -} csubstr_iter; - - -// csview : null-terminated string view -typedef csubstr_value csview_value; +// csview : non-null terminated string view +typedef const char csview_value; typedef struct csview { csview_value* str; intptr_t size; @@ -61,10 +48,23 @@ typedef struct csview { typedef union { csview_value* ref; - struct { csubstr chr; } u8; + struct { csview chr; csview_value* end; } u8; } csview_iter; +// crawstr : null-terminated string view +typedef csview_value crawstr_value; +typedef struct crawstr { + crawstr_value* str; + intptr_t size; +} crawstr; + +typedef union { + crawstr_value* ref; + struct { csview chr; } u8; +} crawstr_iter; + + // cstr : null-terminated string (short string optimized - sso) typedef char cstr_value; typedef struct { cstr_value* data; intptr_t size, cap; } cstr_buf; @@ -75,7 +75,7 @@ typedef union cstr { typedef union { cstr_value* ref; - struct { csubstr chr; } u8; + struct { csview chr; } u8; } cstr_iter; diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 47225ec8..65dee203 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -114,10 +114,10 @@ #endif #elif defined i_key_ssv #define i_keyclass cstr - #define i_rawclass csubstr - #define i_keyfrom cstr_from_ss - #define i_keyto cstr_ss - #define i_eq csubstr_eq + #define i_rawclass csview + #define i_keyfrom cstr_from_sv + #define i_keyto cstr_sv + #define i_eq csview_eq #ifndef i_tag #define i_tag ssv #endif @@ -232,9 +232,9 @@ #define i_valraw const char* #elif defined i_val_ssv #define i_valclass cstr - #define i_valraw csubstr - #define i_valfrom cstr_from_ss - #define i_valto cstr_ss + #define i_valraw csview + #define i_valfrom cstr_from_sv + #define i_valto cstr_sv #elif defined i_valboxed #define i_valclass i_valboxed #define i_valraw c_PASTE(i_valboxed, _raw) diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 7d2adee0..6d12856f 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -48,7 +48,7 @@ extern uint32_t utf8_toupper(uint32_t c); extern bool utf8_iscased(uint32_t c); extern bool utf8_isword(uint32_t c); extern bool utf8_valid_n(const char* s, intptr_t nbytes); -extern int utf8_icmp_ss(csubstr s1, csubstr s2); +extern int utf8_icmp_sv(csview s1, csview s2); extern int utf8_encode(char *out, uint32_t c); extern uint32_t utf8_peek_off(const char *s, int offset); @@ -92,7 +92,7 @@ STC_INLINE uint32_t utf8_peek(const char* s) { /* case-insensitive utf8 string comparison */ STC_INLINE int utf8_icmp(const char* s1, const char* s2) { - return utf8_icmp_ss(c_ss(s1, INTPTR_MAX), c_ss(s2, INTPTR_MAX)); + return utf8_icmp_sv(c_sv(s1, INTPTR_MAX), c_sv(s2, INTPTR_MAX)); } STC_INLINE bool utf8_valid(const char* s) { diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp index 9173d4b6..a5dfd901 100644 --- a/misc/benchmarks/various/string_bench_STC.cpp +++ b/misc/benchmarks/various/string_bench_STC.cpp @@ -7,16 +7,16 @@ #define i_implement #include // string #define i_implement -#include // string_view +#include // string_view #include #define i_key_str #include // vec of cstr with const char* lookup -#define i_type cvec_ss // override default type name (cvec_csubstr) -#define i_key csubstr -#define i_cmp csubstr_cmp -#include // cvec_vs: vec of csubstr +#define i_type cvec_sv // override default type name (cvec_csview) +#define i_key csview +#define i_cmp csview_cmp +#include // cvec_vs: vec of csview #define i_key_str #define i_val size_t @@ -24,7 +24,7 @@ #define i_key_ssv #define i_val size_t -#include // sorted map of cstr, csubstr lookup +#include // sorted map of cstr, csview lookup #define i_key_str #define i_val size_t @@ -32,7 +32,7 @@ #define i_key_ssv #define i_val size_t -#include // unordered map of cstr, csubstr lookup +#include // unordered map of cstr, csview lookup cvec_str read_file(const char* name) @@ -67,7 +67,7 @@ private: std::chrono::high_resolution_clock::time_point begin; }; -void initShortStringVec(cvec_str* vs, cvec_ss* vsv) +void initShortStringVec(cvec_str* vs, cvec_sv* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -101,14 +101,14 @@ void initShortStringVec(cvec_str* vs, cvec_ss* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_ss(i.ref)); + cvec_sv_push_back(vsv, cstr_sv(i.ref)); num += cstr_size(i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; std::cout << "avg str len: " << num / (float)cvec_sv_size(vsv) << std::endl; } -void initLongStringVec(cvec_str* vs, cvec_ss* vsv) +void initLongStringVec(cvec_str* vs, cvec_sv* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -147,7 +147,7 @@ void initLongStringVec(cvec_str* vs, cvec_ss* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_ss(i.ref)); + cvec_sv_push_back(vsv, cstr_sv(i.ref)); num += cstr_size(i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; @@ -175,7 +175,7 @@ void initMaps(const cvec_str* vs, csmap_str* mapTrans, csmap_ssv* mapSview, void benchmark( const cvec_str* vec_string, - const cvec_ss* vec_stringview, + const cvec_sv* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -187,7 +187,7 @@ const size_t MAX_LOOP = 2000; int main(void) { c_auto (cvec_str, vec_string) - c_auto (cvec_ss, vec_stringview) + c_auto (cvec_sv, vec_stringview) c_auto (csmap_str, mapTrans) c_auto (csmap_ssv, mapSview) c_auto (cmap_str, unordmapTrans) @@ -229,7 +229,7 @@ int main(void) void benchmark( const cvec_str* vec_string, - const cvec_ss* vec_stringview, + const cvec_sv* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -258,7 +258,7 @@ void benchmark( stopwatch.start("Trans Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_ss, *vec_stringview) + c_foreach (j, cvec_sv, *vec_stringview) { const csmap_ssv_value* v = csmap_ssv_get(mapSview, *j.ref); if (v) @@ -286,7 +286,7 @@ void benchmark( stopwatch.start("Trans Unord Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_ss, *vec_stringview) + c_foreach (j, cvec_sv, *vec_stringview) { const cmap_ssv_value* v = cmap_ssv_get(unordmapSview, *j.ref); if (v) diff --git a/misc/examples/algorithms/forfilter.c b/misc/examples/algorithms/forfilter.c index d058660d..c1426045 100644 --- a/misc/examples/algorithms/forfilter.c +++ b/misc/examples/algorithms/forfilter.c @@ -2,7 +2,7 @@ #define i_import #include #define i_implement -#include +#include #include #define i_type IVec @@ -82,7 +82,7 @@ fn main() { } */ #define i_type SVec -#define i_keyclass csubstr +#define i_keyclass csview #include void demo3(void) @@ -94,11 +94,11 @@ void demo3(void) SVec words_containing_i = {0}; c_forfilter (w, SVec, words, - csubstr_contains(*w.ref, "i")) + csview_contains(*w.ref, "i")) SVec_push(&words_containing_i, *w.ref); c_foreach (w, SVec, words_containing_i) - printf(" %.*s", c_SS(*w.ref)); + printf(" %.*s", c_SV(*w.ref)); puts(""); c_drop(SVec, &words, &words_containing_i); @@ -107,10 +107,10 @@ void demo3(void) void demo4(void) { // Keep only uppercase letters and convert them to lowercase: - csubstr s = c_ss("ab123cReAghNGnΩoEp"); // Ω = multi-byte + csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte cstr out = {0}; - c_forfilter (i, csubstr, s, utf8_isupper(utf8_peek(i.ref))) { + c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) { char chr[4]; utf8_encode(chr, utf8_tolower(utf8_peek(i.ref))); cstr_push(&out, chr); diff --git a/misc/examples/regularexpressions/regex2.c b/misc/examples/regularexpressions/regex2.c index 85890070..a798b1a1 100644 --- a/misc/examples/regularexpressions/regex2.c +++ b/misc/examples/regularexpressions/regex2.c @@ -27,7 +27,7 @@ int main(void) c_formatch (j, &re, s[i].input) { c_forrange (k, cregex_captures(&re) + 1) - printf(" submatch %lld: %.*s\n", k, c_SS(j.match[k])); + printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); } } cregex_drop(&re); diff --git a/misc/examples/regularexpressions/regex_match.c b/misc/examples/regularexpressions/regex_match.c index 6eaea781..11426d2d 100644 --- a/misc/examples/regularexpressions/regex_match.c +++ b/misc/examples/regularexpressions/regex_match.c @@ -1,7 +1,7 @@ #define i_import #include #define i_implement -#include +#include #define i_key float #include @@ -28,7 +28,7 @@ int main(void) printf(" %g\n", (double)*i.ref); // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_ss(&re, csubstr_from(str), " $0,", 0, NULL, CREG_STRIP); + cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); printf("\n%s\n", cstr_str(&nums)); cstr_drop(&nums); diff --git a/misc/examples/regularexpressions/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c index f5fd8691..f1ea2711 100644 --- a/misc/examples/regularexpressions/regex_replace.c +++ b/misc/examples/regularexpressions/regex_replace.c @@ -1,8 +1,8 @@ #define i_import #include -#include +#include -bool add_10_years(int i, csubstr match, cstr* out) { +bool add_10_years(int i, csview match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -47,7 +47,7 @@ int main(void) printf("euros: %s\n", cstr_str(&str)); /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); printf("strip: %s\n", cstr_str(&str)); /* Wrap all words in ${} */ diff --git a/misc/examples/strings/cstr_match.c b/misc/examples/strings/cstr_match.c index 3c41bd43..80013019 100644 --- a/misc/examples/strings/cstr_match.c +++ b/misc/examples/strings/cstr_match.c @@ -1,6 +1,6 @@ #define i_implement #include -#include +#include #include int main(void) @@ -16,11 +16,11 @@ int main(void) printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); cstr s1 = cstr_lit("hell😀 w😀rl🐨"); - csubstr ch1 = cstr_u8_chr(&s1, 7); - csubstr ch2 = cstr_u8_chr(&s1, 10); + csview ch1 = cstr_u8_chr(&s1, 7); + csview ch2 = cstr_u8_chr(&s1, 10); printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); - printf("ch1: %.*s\n", c_SS(ch1)); - printf("ch2: %.*s\n", c_SS(ch2)); + printf("ch1: %.*s\n", c_SV(ch1)); + printf("ch2: %.*s\n", c_SV(ch2)); c_drop(cstr, &ss, &s1); } diff --git a/misc/examples/strings/replace.c b/misc/examples/strings/replace.c index 2411f1a7..59a56bf7 100644 --- a/misc/examples/strings/replace.c +++ b/misc/examples/strings/replace.c @@ -20,13 +20,13 @@ int main(void) cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) printf("(1) %s\n", cstr_str(&s)); - cstr_replace_at_ss(&s, 19, 6, c_ss(s3+7, 6)); // "this is an example phrase." (2) + cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) printf("(2) %s\n", cstr_str(&s)); cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) printf("(3) %s\n", cstr_str(&s)); - cstr_replace_at_ss(&s, 8, 6, c_ss("a shorty", 7)); // "this is a short phrase." (4) + cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) printf("(4) %s\n", cstr_str(&s)); cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) diff --git a/misc/examples/strings/splitstr.c b/misc/examples/strings/splitstr.c index 6fa76d34..ef7ed174 100644 --- a/misc/examples/strings/splitstr.c +++ b/misc/examples/strings/splitstr.c @@ -2,20 +2,20 @@ #define i_import // cstr + utf8 functions #include #define i_implement -#include +#include int main(void) { - puts("Split with c_fortoken (csubstr):"); + puts("Split with c_fortoken (csview):"); c_fortoken (i, "Hello World C99!", " ") - printf("'%.*s'\n", c_SS(i.token)); + printf("'%.*s'\n", c_SV(i.token)); puts("\nSplit with c_formatch (regex):"); cregex re = cregex_from("[^ ]+"); c_formatch (i, &re, " Hello World C99! ") - printf("'%.*s'\n", c_SS(i.match[0])); + printf("'%.*s'\n", c_SV(i.match[0])); cregex_drop(&re); } diff --git a/misc/examples/strings/sso_substr.c b/misc/examples/strings/sso_substr.c index 2262e349..70d34440 100644 --- a/misc/examples/strings/sso_substr.c +++ b/misc/examples/strings/sso_substr.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { cstr str = cstr_from("We think in generalities, but we live in details."); - csubstr sv1 = cstr_substr_ex(&str, 3, 5); // "think" + csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" intptr_t pos = cstr_find(&str, "live"); // position of "live" - csubstr sv2 = cstr_substr_ex(&str, pos, 4); // "live" - csubstr sv3 = cstr_slice_ex(&str, -8, -1); // "details" - printf("%.*s, %.*s, %.*s\n", c_SS(sv1), c_SS(sv2), c_SS(sv3)); + csview sv2 = cstr_substr_ex(&str, pos, 4); // "live" + csview sv3 = cstr_slice_ex(&str, -8, -1); // "details" + printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); cstr_assign(&str, "apples are green or red"); - cstr s2 = cstr_from_ss(cstr_substr_ex(&str, -3, 3)); // "red" - cstr s3 = cstr_from_ss(cstr_substr_ex(&str, 0, 6)); // "apples" + cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red" + cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples" printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), cstr_is_long(&str), cstr_is_long(&s2)); c_drop (cstr, &str, &s2, &s3); diff --git a/misc/examples/strings/sview_split.c b/misc/examples/strings/sview_split.c index 6abbf5e7..ac275da0 100644 --- a/misc/examples/strings/sview_split.c +++ b/misc/examples/strings/sview_split.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { // No memory allocations or string length calculations! - const csubstr date = c_ss("2021/03/12"); + const csview date = c_sv("2021/03/12"); intptr_t pos = 0; - const csubstr year = csubstr_token(date, "/", &pos); - const csubstr month = csubstr_token(date, "/", &pos); - const csubstr day = csubstr_token(date, "/", &pos); + const csview year = csview_token(date, "/", &pos); + const csview month = csview_token(date, "/", &pos); + const csview day = csview_token(date, "/", &pos); - printf("%.*s, %.*s, %.*s\n", c_SS(year), c_SS(month), c_SS(day)); + printf("%.*s, %.*s, %.*s\n", c_SV(year), c_SV(month), c_SV(day)); - cstr y = cstr_from_ss(year), m = cstr_from_ss(month), d = cstr_from_ss(day); + cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); c_drop(cstr, &y, &m, &d); } diff --git a/misc/examples/strings/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c index 03a0442f..1d54486f 100644 --- a/misc/examples/strings/utf8replace_c.c +++ b/misc/examples/strings/utf8replace_c.c @@ -10,12 +10,12 @@ int main(void) cstr_u8_replace_at(&hello, cstr_u8_to_pos(&hello, 7), 1, - c_ss("🐨") + c_sv("🐨") ); printf("%s\n", cstr_str(&hello)); c_foreach (c, cstr, hello) - printf("%.*s,", c_SS(c.u8.chr)); + printf("%.*s,", c_SV(c.u8.chr)); cstr str = cstr_lit("scooby, dooby doo"); cstr_replace(&str, "oo", "00"); diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 7cd03930..4e192de6 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -1,6 +1,6 @@ #define i_import #include -#include +#include #include #include "ctest.h" @@ -14,7 +14,7 @@ CTEST(cregex, compile_match_char) cregex re = cregex_from("äsdf"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_FULLMATCH), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); // ä is two bytes wide @@ -32,7 +32,7 @@ CTEST(cregex, compile_match_anchors) cregex re = cregex_from(inp="^äs.f$"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -50,7 +50,7 @@ CTEST(cregex, compile_match_quantifiers1) re = cregex_from("ä+"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="ääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 4); @@ -70,7 +70,7 @@ CTEST(cregex, compile_match_quantifiers2) re = cregex_from("bä*"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="bääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -90,7 +90,7 @@ CTEST(cregex, compile_match_escaped_chars) cregex re = cregex_from("\\n\\r\\t\\{"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, "\n\r\t{", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "\n\r\t", &match), CREG_NOMATCH); @@ -108,7 +108,7 @@ CTEST(cregex, compile_match_class_simple) re3 = cregex_from("\\D"); ASSERT_EQ(re3.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re1, " " , &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\r", &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\n", &match), CREG_OK); @@ -129,7 +129,7 @@ CTEST(cregex, compile_match_or) re = cregex_from("as|df"); ASSERT_EQ(re.error, 0); - csubstr match[4]; + csview match[4]; ASSERT_EQ(cregex_find(&re, "as", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "df", match), CREG_OK); @@ -146,7 +146,7 @@ CTEST(cregex, compile_match_class_complex_0) cregex re = cregex_from("[asdf]"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "s", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "d", &match), CREG_OK); @@ -160,7 +160,7 @@ CTEST(cregex, compile_match_class_complex_1) cregex re = cregex_from("[a-zä0-9öA-Z]"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "5", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "A", &match), CREG_OK); @@ -175,7 +175,7 @@ CTEST(cregex, compile_match_cap) cregex re = cregex_from("(abc)d"); ASSERT_EQ(re.error, 0); - csubstr match[4]; + csview match[4]; ASSERT_EQ(cregex_find(&re, "abcd", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "llljabcdkk", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "abc", match), CREG_NOMATCH); @@ -189,7 +189,7 @@ CTEST(cregex, search_all) c_auto (cregex, re) { re = cregex_from("ab"); - csubstr m = {0}; + csview m = {0}; int res; ASSERT_EQ(re.error, CREG_OK); inp="ab,ab,ab"; @@ -220,9 +220,9 @@ CTEST(cregex, captures_cap) re = cregex_from("(ab)((cd)+)"); ASSERT_EQ(cregex_captures(&re), 3); - csubstr cap[5]; + csview cap[5]; ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap), CREG_OK); - ASSERT_TRUE(csubstr_equals(cap[0], "abcdcd")); + ASSERT_TRUE(csview_equals(cap[0], "abcdcd")); ASSERT_EQ(M_END(cap[0]), 8); ASSERT_EQ(M_START(cap[1]), 2); @@ -235,7 +235,7 @@ CTEST(cregex, captures_cap) } } -static bool add_10_years(int i, csubstr match, cstr* out) { +static bool add_10_years(int i, csview match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -280,7 +280,7 @@ CTEST(cregex, replace) ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022"); // Strip out everything but the matches - cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;"); } } diff --git a/src/cregex.c b/src/cregex.c index c045b9f3..e6da66b2 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -100,7 +100,7 @@ typedef struct _Reprog /* * Sub expression matches */ -typedef csubstr _Resub; +typedef csview _Resub; /* * substitution list @@ -1215,8 +1215,8 @@ _regexec(const _Reprog *progp, /* program to run */ static void -_build_subst(const char* replace, int nmatch, const csubstr match[], - bool (*mfun)(int, csubstr, cstr*), cstr* subst) { +_build_subst(const char* replace, int nmatch, const csview match[], + bool (*mfun)(int, csview, cstr*), cstr* subst) { cstr_buf buf = cstr_buffer(subst); intptr_t len = 0, cap = buf.cap; char* dst = buf.data; @@ -1233,7 +1233,7 @@ _build_subst(const char* replace, int nmatch, const csubstr match[], if (replace[1] >= '0' && replace[1] <= '9' && replace[2] == ';') { g = g*10 + (replace[1] - '0'); replace += 2; } if (g < nmatch) { - csubstr m = mfun && mfun(g, match[g], &mstr) ? cstr_ss(&mstr) : match[g]; + csview m = mfun && mfun(g, match[g], &mstr) ? cstr_sv(&mstr) : match[g]; if (len + m.size > cap) dst = cstr_reserve(subst, cap += cap/2 + m.size); for (int i = 0; i < m.size; ++i) @@ -1270,7 +1270,7 @@ cregex_captures(const cregex* self) { } int -cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags) { +cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { int res = _regexec(re->prog, input, cregex_captures(re) + 1, match, mflags); switch (res) { case 1: return CREG_OK; @@ -1281,7 +1281,7 @@ cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags) int cregex_find_pattern_4(const char* pattern, const char* input, - csubstr match[], int cmflags) { + csview match[], int cmflags) { cregex re = cregex_init(); int res = cregex_compile(&re, pattern, cmflags); if (res != CREG_OK) return res; @@ -1291,16 +1291,16 @@ cregex_find_pattern_4(const char* pattern, const char* input, } cstr -cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, - bool (*mfun)(int, csubstr, cstr*), int rflags) { +cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, + bool (*mfun)(int, csview, cstr*), int rflags) { cstr out = cstr_init(); cstr subst = cstr_init(); - csubstr match[CREG_MAX_CAPTURES]; + csview match[CREG_MAX_CAPTURES]; int nmatch = cregex_captures(re) + 1; if (!count) count = INT32_MAX; bool copy = !(rflags & CREG_STRIP); - while (count-- && cregex_find_ss(re, input, match) == CREG_OK) { + while (count-- && cregex_find_sv(re, input, match) == CREG_OK) { _build_subst(replace, nmatch, match, mfun, &subst); const intptr_t mpos = (match[0].str - input.str); if (copy & (mpos > 0)) cstr_append_n(&out, input.str, mpos); @@ -1308,19 +1308,19 @@ cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int co input.str = match[0].str + match[0].size; input.size -= mpos + match[0].size; } - if (copy) cstr_append_ss(&out, input); + if (copy) cstr_append_sv(&out, input); cstr_drop(&subst); return out; } cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*mfun)(int, csubstr, cstr*), int crflags) { + bool (*mfun)(int, csview, cstr*), int crflags) { cregex re = cregex_init(); if (cregex_compile(&re, pattern, crflags) != CREG_OK) assert(0); - csubstr ss = c_ss(input, c_strlen(input)); - cstr out = cregex_replace_ss(&re, ss, replace, count, mfun, crflags); + csview sv = c_sv(input, c_strlen(input)); + cstr out = cregex_replace_sv(&re, sv, replace, count, mfun, crflags); cregex_drop(&re); return out; } diff --git a/src/libstc.c b/src/libstc.c index b0d27350..462c97c4 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,7 +1,7 @@ #define i_import #include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement -#include "../include/stc/csubstr.h" +#include "../include/stc/csview.h" #define i_implement #include "../include/stc/crand.h" #if __STDC_VERSION__ >= 201112L diff --git a/src/singleupdate.sh b/src/singleupdate.sh index be99d4a7..8c2bba45 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -22,8 +22,8 @@ python singleheader.py $d/include/stc/cspan.h $d/../stcsingle/stc/cspan.h python singleheader.py $d/include/stc/csset.h $d/../stcsingle/stc/csset.h python singleheader.py $d/include/stc/cstack.h $d/../stcsingle/stc/cstack.h python singleheader.py $d/include/stc/cstr.h $d/../stcsingle/stc/cstr.h -python singleheader.py $d/include/stc/csubstr.h $d/../stcsingle/stc/csubstr.h python singleheader.py $d/include/stc/csview.h $d/../stcsingle/stc/csview.h +python singleheader.py $d/include/stc/crawstr.h $d/../stcsingle/stc/crawstr.h python singleheader.py $d/include/stc/cvec.h $d/../stcsingle/stc/cvec.h python singleheader.py $d/include/stc/extend.h $d/../stcsingle/stc/extend.h python singleheader.py $d/include/stc/forward.h $d/../stcsingle/stc/forward.h diff --git a/src/utf8code.c b/src/utf8code.c index ddc4cb97..4abf10ea 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -101,7 +101,7 @@ uint32_t utf8_toupper(uint32_t c) { return c; } -int utf8_icmp_ss(const csubstr s1, const csubstr s2) { +int utf8_icmp_sv(const csview s1, const csview s2) { utf8_decode_t d1 = {.state=0}, d2 = {.state=0}; intptr_t j1 = 0, j2 = 0; while ((j1 < s1.size) & (j2 < s2.size)) { -- cgit v1.2.3 From b6f7896ff21002e58e9af12fd553da32bda5f6d1 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 14 Aug 2023 21:19:28 +0200 Subject: Simplified printspan.c example --- misc/examples/spans/printspan.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/misc/examples/spans/printspan.c b/misc/examples/spans/printspan.c index eb9d80e3..b6999b61 100644 --- a/misc/examples/spans/printspan.c +++ b/misc/examples/spans/printspan.c @@ -1,18 +1,16 @@ -// printspan.c +// https://www.modernescpp.com/index.php/c-20-std-span/ #include -#define i_implement -#include #define i_key int #include + #define i_key int #include -#define i_key_str -#include #include using_cspan(intspan, int); + void printMe(intspan container) { printf("%d:", (int)cspan_size(&container)); c_foreach (e, intspan, container) @@ -20,33 +18,24 @@ void printMe(intspan container) { puts(""); } + int main(void) { - intspan sp1 = cspan_init(intspan, {1, 2}); - printMe( sp1 ); + printMe( c_init(intspan, {1, 2, 3, 4}) ); - printMe( c_init(intspan, {1, 2, 3}) ); + int arr[] = {1, 2, 3, 4, 5}; + printMe( (intspan)cspan_from_array(arr) ); - int arr[] = {1, 2, 3, 4, 5, 6}; - intspan sp2 = cspan_from_array(arr); - printMe( c_LITERAL(intspan)cspan_subspan(&sp2, 1, 4) ); - - cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5}); - printMe( c_LITERAL(intspan)cspan_from(&vec) ); - - printMe( sp2 ); + cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5, 6}); + printMe( (intspan)cspan_from(&vec) ); cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7}); - printMe( c_LITERAL(intspan)cspan_from(&stk) ); + printMe( (intspan)cspan_from(&stk) ); - csset_str set = c_init(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); - printf("%d:", (int)csset_str_size(&set)); - c_foreach (e, csset_str, set) - printf(" %s", cstr_str(e.ref)); - puts(""); + intspan spn = c_init(intspan, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + printMe( (intspan)cspan_subspan(&spn, 2, 8) ); // cleanup cvec_int_drop(&vec); cstack_int_drop(&stk); - csset_str_drop(&set); } -- cgit v1.2.3 From 50099b084e0e27aa74c53d73a9c33790e5f00aeb Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Tue, 15 Aug 2023 00:37:45 +0200 Subject: Minors. --- docs/cstr_api.md | 18 +++++++++--------- include/stc/ccommon.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 1da57b0c..39bd4e94 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -22,7 +22,7 @@ cstr cstr_init(void); // construct cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call. cstr cstr_from(const char* str); // constructor using strlen() cstr cstr_from_n(const char* str, intptr_t n); // constructor with n first bytes of str -cstr cstr_from_sv(csview ss); // construct cstr from csview +cstr cstr_from_sv(csview sv); // construct cstr from csview cstr cstr_from_rs(crawstr rs); // construct cstr from crawstr cstr cstr_with_capacity(intptr_t cap); cstr cstr_with_size(intptr_t len, char fill); // repeat fill len times @@ -50,7 +50,7 @@ void cstr_clear(cstr* self); char* cstr_assign(cstr* self, const char* str); char* cstr_assign_n(cstr* self, const char* str, intptr_t n); // assign n first bytes of str -char* cstr_assign_sv(cstr* self, csview ss); +char* cstr_assign_sv(cstr* self, csview sv); char* cstr_copy(cstr* self, cstr s); // copy-assign a cstr int cstr_printf(cstr* self, const char* fmt, ...); // source and target must not overlap. @@ -77,7 +77,7 @@ void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csv void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl); bool cstr_equals(const cstr* self, const char* str); -bool cstr_equals_sv(const cstr* self, csview ss); +bool cstr_equals_sv(const cstr* self, csview sv); bool cstr_equals_s(const cstr* self, cstr s); intptr_t cstr_find(const cstr* self, const char* search); @@ -85,11 +85,11 @@ intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); // bool cstr_contains(const cstr* self, const char* search); bool cstr_starts_with(const cstr* self, const char* str); -bool cstr_starts_with_sv(const cstr* self, csview ss); +bool cstr_starts_with_sv(const cstr* self, csview sv); bool cstr_starts_with_s(const cstr* self, cstr s); bool cstr_ends_with(const cstr* self, const char* str); -bool cstr_ends_with_sv(const cstr* self, csview ss); +bool cstr_ends_with_sv(const cstr* self, csview sv); bool cstr_ends_with_s(const cstr* self, cstr s); bool cstr_getline(cstr *self, FILE *stream); // cstr_getdelim(self, '\n', stream) @@ -102,7 +102,7 @@ intptr_t cstr_u8_size(const cstr* self); // number of intptr_t cstr_u8_size_n(const cstr self, intptr_t nbytes); // utf8 size within n bytes intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx); // byte pos offset at utf8 codepoint index const char* cstr_u8_at(const cstr* self, intptr_t u8idx); // char* position at utf8 codepoint index -csview cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csview +csview cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csview void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl); // replace u8len utf8 chars void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); // erase u8len codepoints from pos @@ -114,14 +114,14 @@ cstr_iter cstr_advance(cstr_iter it, intptr_t n); // utf8 functions requires linking with src/utf8code.c symbols: bool cstr_valid_utf8(const cstr* self); // check if str is valid utf8 -cstr cstr_casefold_sv(csview ss); // returns new casefolded utf8 cstr +cstr cstr_casefold_sv(csview sv); // returns new casefolded utf8 cstr cstr cstr_tolower(const char* str); // returns new lowercase utf8 cstr -cstr cstr_tolower_sv(csview ss); // returns new lowercase utf8 cstr +cstr cstr_tolower_sv(csview sv); // returns new lowercase utf8 cstr void cstr_lowercase(cstr* self); // transform cstr to lowercase utf8 cstr cstr_toupper(const char* str); // returns new uppercase utf8 cstr -cstr cstr_toupper_sv(csview ss); // returns new uppercase utf8 cstr +cstr cstr_toupper_sv(csview sv); // returns new uppercase utf8 cstr void cstr_uppercase(cstr* self); // transform cstr to uppercase utf8 int cstr_icmp(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index e5422adc..42631f85 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -133,7 +133,7 @@ typedef const char* ccharptr; #define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) #define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal)) #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) -#define c_SV(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SV(ss)); +#define c_SV(sv) (int)(sv).size, (sv).str // printf("%.*s\n", c_SV(sv)); #define c_rs(literal) c_rs_2(literal, c_litstrlen(literal)) #define c_rs_2(str, n) (c_LITERAL(crawstr){str, n}) -- cgit v1.2.3 From 5898353f686619a5345df7babae9c3e2ed84db29 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Tue, 15 Aug 2023 00:56:36 +0200 Subject: Reverting some internal variable names. --- include/stc/cstr.h | 60 +++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 7f4bad97..3822020f 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -93,12 +93,12 @@ STC_INLINE cstr_buf cstr_buffer(cstr* s) { ? c_LITERAL(cstr_buf){s->lon.data, cstr_l_size(s), cstr_l_cap(s)} : c_LITERAL(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap}; } -STC_INLINE crawstr cstr_rs(const cstr* s) { - return cstr_is_long(s) ? c_rs_2(s->lon.data, cstr_l_size(s)) - : c_rs_2(s->sml.data, cstr_s_size(s)); +STC_INLINE csview cstr_sv(const cstr* s) { + return cstr_is_long(s) ? c_sv_2(s->lon.data, cstr_l_size(s)) + : c_sv_2(s->sml.data, cstr_s_size(s)); } -STC_INLINE csview cstr_sv(const cstr* s) - { crawstr rs = cstr_rs(s); return c_sv_2(rs.str, rs.size); } +STC_INLINE crawstr cstr_rs(const cstr* s) + { csview sv = cstr_sv(s); return c_rs_2(sv.str, sv.size); } STC_INLINE cstr cstr_init(void) { return cstr_null; } @@ -144,8 +144,8 @@ STC_INLINE cstr cstr_move(cstr* self) { } STC_INLINE cstr cstr_clone(cstr s) { - crawstr rs = cstr_rs(&s); - return cstr_from_n(rs.str, rs.size); + csview sv = cstr_sv(&s); + return cstr_from_n(sv.str, sv.size); } STC_INLINE void cstr_drop(cstr* self) { @@ -209,9 +209,9 @@ STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { // utf8 iterator STC_INLINE cstr_iter cstr_begin(const cstr* self) { - crawstr rs = cstr_rs(self); - if (!rs.size) return c_LITERAL(cstr_iter){.ref = NULL}; - return c_LITERAL(cstr_iter){.u8 = {{rs.str, utf8_chr_size(rs.str)}}}; + csview sv = cstr_sv(self); + if (!sv.size) return c_LITERAL(cstr_iter){.ref = NULL}; + return c_LITERAL(cstr_iter){.u8 = {{sv.str, utf8_chr_size(sv.str)}}}; } STC_INLINE cstr_iter cstr_end(const cstr* self) { (void)self; return c_LITERAL(cstr_iter){NULL}; @@ -241,7 +241,7 @@ STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2) { return utf8_icmp(cstr_str(s1), cstr_str(s2)); } STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { - crawstr x = cstr_rs(s1), y = cstr_rs(s2); + csview x = cstr_sv(s1), y = cstr_sv(s2); return x.size == y.size && !c_memcmp(x.str, y.str, x.size); } @@ -300,9 +300,9 @@ STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) { STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) { - crawstr rs = cstr_rs(self); - if (sub.size > rs.size) return false; - return !c_memcmp(rs.str + rs.size - sub.size, sub.str, sub.size); + csview sv = cstr_sv(self); + if (sub.size > sv.size) return false; + return !c_memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); } STC_INLINE bool cstr_ends_with_s(const cstr* self, cstr sub) @@ -312,9 +312,9 @@ STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub) { return cstr_ends_with_sv(self, c_sv(sub, c_strlen(sub))); } STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { - crawstr rs = cstr_rs(self); + csview sv = cstr_sv(self); intptr_t n = c_strlen(sub); - return n <= rs.size && !utf8_icmp(rs.str + rs.size - n, sub); + return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub); } @@ -325,8 +325,8 @@ STC_INLINE char* cstr_assign_sv(cstr* self, csview sv) { return cstr_assign_n(self, sv.str, sv.size); } STC_INLINE char* cstr_copy(cstr* self, cstr s) { - crawstr rs = cstr_rs(&s); - return cstr_assign_n(self, rs.str, rs.size); + csview sv = cstr_sv(&s); + return cstr_assign_n(self, sv.str, sv.size); } @@ -334,10 +334,10 @@ STC_INLINE char* cstr_push(cstr* self, const char* chr) { return cstr_append_n(self, chr, utf8_chr_size(chr)); } STC_INLINE void cstr_pop(cstr* self) { - crawstr rs = cstr_rs(self); - const char* s = rs.str + rs.size; + csview sv = cstr_sv(self); + const char* s = sv.str + sv.size; while ((*--s & 0xC0) == 0x80) ; - _cstr_set_size(self, (s - rs.str)); + _cstr_set_size(self, (s - sv.str)); } STC_INLINE char* cstr_append(cstr* self, const char* str) @@ -449,14 +449,14 @@ bool cstr_valid_utf8(const cstr* self) #define CSTR_C_INCLUDED STC_DEF uint64_t cstr_hash(const cstr *self) { - crawstr rs = cstr_rs(self); - return cfasthash(rs.str, rs.size); + csview sv = cstr_sv(self); + return cfasthash(sv.str, sv.size); } STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { - crawstr rs = cstr_rs(self); - char* res = cstrnstrn(rs.str, search.str, rs.size, search.size); - return res ? (res - rs.str) : c_NPOS; + csview sv = cstr_sv(self); + char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); + return res ? (res - sv.str) : c_NPOS; } STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { @@ -530,10 +530,10 @@ STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) { } STC_DEF intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { - crawstr rs = cstr_rs(self); - if (pos > rs.size) return c_NPOS; - const char* res = strstr((char*)rs.str + pos, search); - return res ? (res - rs.str) : c_NPOS; + csview sv = cstr_sv(self); + if (pos > sv.size) return c_NPOS; + const char* res = strstr((char*)sv.str + pos, search); + return res ? (res - sv.str) : c_NPOS; } STC_DEF char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { -- cgit v1.2.3 From 5be09e526bc4ee4d1f586aa906e1f9a9c8e3e165 Mon Sep 17 00:00:00 2001 From: tylov Date: Tue, 15 Aug 2023 10:34:05 +0200 Subject: Fixed c_i2u() didn't trigger -Wsign-conversion warning. --- include/stc/ccommon.h | 6 +++--- include/stc/clist.h | 6 +++--- include/stc/cmap.h | 2 +- include/stc/cstr.h | 2 +- src/cregex.c | 14 +++++++------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 42631f85..e33e657a 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -88,16 +88,16 @@ typedef long long _llong; #define c_const_cast(T, p) ((T)(1 ? (p) : (T)0)) #define c_swap(T, xp, yp) do { T *_xp = xp, *_yp = yp, \ _tv = *_xp; *_xp = *_yp; *_yp = _tv; } while (0) +// use with gcc -Wsign-conversion #define c_sizeof (intptr_t)sizeof #define c_strlen(s) (intptr_t)strlen(s) - #define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u(ilen)) #define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u(ilen)) #define c_memmove(d, s, ilen) memmove(d, s, c_i2u(ilen)) #define c_memset(d, val, ilen) memset(d, val, c_i2u(ilen)) #define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u(ilen)) -#define c_u2i(u) ((intptr_t)(1 ? (u) : (size_t)1)) -#define c_i2u(i) ((size_t)(1 ? (i) : (intptr_t)1)) +#define c_u2i(u) (intptr_t)(1 ? (u) : (size_t)1) +#define c_i2u(i) (size_t)(1 ? (i) : -1) #define c_LTu(a, b) ((size_t)(a) < (size_t)(b)) // x and y are i_keyraw* type, defaults to i_key*: diff --git a/include/stc/clist.h b/include/stc/clist.h index d7cf30b9..6a205c2b 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -385,17 +385,17 @@ STC_DEF int _cx_MEMB(_sort_cmp_)(const _cx_value* x, const _cx_value* y) { } STC_DEF bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*)) { - size_t len = 0, cap = 0; + intptr_t len = 0, cap = 0; _cx_value *a = NULL, *p = NULL; _cx_iter i; for (i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i)) { if (len == cap) { - if ((p = (_cx_value *)i_realloc(a, (cap += cap/2 + 4)*sizeof *a))) a = p; + if ((p = (_cx_value *)i_realloc(a, (cap += cap/2 + 4)*c_sizeof *a))) a = p; else { i_free(a); return false; } } a[len++] = *i.ref; } - qsort(a, len, sizeof *a, (int(*)(const void*, const void*))cmp); + qsort(a, (size_t)len, sizeof *a, (int(*)(const void*, const void*))cmp); for (i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i), ++p) *i.ref = *p; i_free(a); return true; diff --git a/include/stc/cmap.h b/include/stc/cmap.h index e0134964..deee1f59 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -417,7 +417,7 @@ _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) { _newbucks = cnextpow2(_newbucks); _cx_Self m = { (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), - (struct chash_slot *)i_calloc(_newbucks + 1, sizeof(struct chash_slot)), + (struct chash_slot *)i_calloc(_newbucks + 1, c_sizeof(struct chash_slot)), self->size, _newbucks }; bool ok = m.data && m.slot; diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 3822020f..bc147469 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -509,7 +509,7 @@ STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) { char* data = (char *)c_malloc(cap + 1); const intptr_t len = cstr_s_size(self); /* copy full short buffer to emulate realloc() */ - c_memcpy(data, self->sml.data, sizeof self->sml); + c_memcpy(data, self->sml.data, c_sizeof self->sml); self->lon.data = data; self->lon.size = (size_t)len; cstr_l_set_cap(self, cap); diff --git a/src/cregex.c b/src/cregex.c index e6da66b2..551cb6f6 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -362,7 +362,7 @@ typedef struct _Parser bool lastwasand; /* Last token was _operand */ short nbra; short nclass; - size_t instcap; + intptr_t instcap; _Rune yyrune; /* last lex'd rune */ _Reclass *yyclassp; /* last lex'd class */ _Reclass* classp; @@ -562,11 +562,11 @@ _optimize(_Parser *par, _Reprog *pp) * necessary. Reallocate to the actual space used * and then relocate the code. */ - if ((par->freep - pp->firstinst)*2 > (ptrdiff_t)par->instcap) + if ((par->freep - pp->firstinst)*2 > par->instcap) return pp; - intptr_t ipp = (intptr_t)pp; - size_t size = sizeof(_Reprog) + (size_t)(par->freep - pp->firstinst)*sizeof(_Reinst); + intptr_t ipp = (intptr_t)pp; // convert pointer to intptr_t! + intptr_t size = c_sizeof(_Reprog) + (par->freep - pp->firstinst)*c_sizeof(_Reinst); _Reprog *npp = (_Reprog *)c_realloc(pp, size); ptrdiff_t diff = (intptr_t)npp - ipp; @@ -862,9 +862,9 @@ _regcomp1(_Reprog *pp, _Parser *par, const char *s, int cflags) _Token token; /* get memory for the program. estimated max usage */ - par->instcap = 5U + 6*strlen(s); + par->instcap = 5 + 6*c_strlen(s); _Reprog* old_pp = pp; - pp = (_Reprog *)c_realloc(pp, sizeof(_Reprog) + par->instcap*sizeof(_Reinst)); + pp = (_Reprog *)c_realloc(pp, c_sizeof(_Reprog) + par->instcap*c_sizeof(_Reinst)); if (! pp) { c_free(old_pp); par->error = CREG_OUTOFMEMORY; @@ -1152,7 +1152,7 @@ _regexec2(const _Reprog *progp, /* program to run */ _Relist *relists; /* mark space */ - relists = (_Relist *)c_malloc(2 * _BIGLISTSIZE*sizeof(_Relist)); + relists = (_Relist *)c_malloc(2 * _BIGLISTSIZE*c_sizeof(_Relist)); if (relists == NULL) return -1; -- cgit v1.2.3 From 541ce2af6bda0bb21393bdee3fed1e70f9ce40f1 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 16 Aug 2023 17:15:37 +0200 Subject: Added recursive matrix multiplication example for cspan. --- include/c11/fmt.h | 6 +-- misc/examples/spans/matmult.c | 90 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 misc/examples/spans/matmult.c diff --git a/include/c11/fmt.h b/include/c11/fmt.h index d7c10cbe..df96bae3 100644 --- a/include/c11/fmt.h +++ b/include/c11/fmt.h @@ -25,7 +25,7 @@ void fmt_close(fmt_stream* ss); * C11 or higher required. * MAX 255 chars fmt string by default. MAX 12 arguments after fmt string. -* Define FMT_IMPLEMENT or i_implement prior to #include in one translation unit. +* Define FMT_IMPLEMENT, STC_IMPLEMENT or i_implement prior to #include in one translation unit. * Define FMT_SHORTS to add print(), println() and printd() macros, without fmt_ prefix. * (c) operamint, 2022, MIT License. ----------------------------------------------------------------------------------- @@ -84,7 +84,7 @@ int main(void) { #define _fmt_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ _14, _15, _16, N, ...) N -#if defined FMT_NDEBUG || defined NDEBUG +#if defined FMT_NDEBUG || defined STC_NDEBUG || defined NDEBUG # define fmt_OK(exp) (void)(exp) #else # define fmt_OK(exp) assert(exp) @@ -196,7 +196,7 @@ void _fmt_bprint(fmt_stream*, const char* fmt, ...); const wchar_t*: "ls", \ const void*: "p") -#if defined FMT_IMPLEMENT || defined i_implement +#if defined FMT_IMPLEMENT || defined STC_IMPLEMENT || defined i_implement #include #include diff --git a/misc/examples/spans/matmult.c b/misc/examples/spans/matmult.c new file mode 100644 index 00000000..62c0c26b --- /dev/null +++ b/misc/examples/spans/matmult.c @@ -0,0 +1,90 @@ +// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2642r2.html +// C99: +#include +#include +#include + +using_cspan3(Mat, double); +typedef Mat2 OutMat; +typedef struct { Mat2 m00, m01, m10, m11; } Partition; + +Partition partition(Mat2 A) +{ + int32_t M = A.shape[0]; + int32_t N = A.shape[1]; + return (Partition){ + .m00 = cspan_slice(Mat2, &A, {0, M/2}, {0, N/2}), + .m01 = cspan_slice(Mat2, &A, {0, M/2}, {N/2, N}), + .m10 = cspan_slice(Mat2, &A, {M/2, M}, {0, N/2}), + .m11 = cspan_slice(Mat2, &A, {M/2, M}, {N/2, N}), + }; +} + +// Slow generic implementation +void base_case_matrix_product(Mat2 A, Mat2 B, OutMat C) +{ + for (int j = 0; j < C.shape[1]; ++j) { + for (int i = 0; i < C.shape[0]; ++i) { + Mat2_value C_ij = 0; + for (int k = 0; k < A.shape[1]; ++k) { + C_ij += *cspan_at(&A, i,k) * *cspan_at(&B, k,j); + } + *cspan_at(&C, i,j) += C_ij; + } + } +} + +void recursive_matrix_product(Mat2 A, Mat2 B, OutMat C) +{ + // Some hardware-dependent constant + enum {recursion_threshold = 16}; + if (C.shape[0] <= recursion_threshold || C.shape[1] <= recursion_threshold) { + base_case_matrix_product(A, B, C); + } else { + Partition c = partition(C), + a = partition(A), + b = partition(B); + recursive_matrix_product(a.m00, b.m00, c.m00); + recursive_matrix_product(a.m01, b.m10, c.m00); + recursive_matrix_product(a.m10, b.m00, c.m10); + recursive_matrix_product(a.m11, b.m10, c.m10); + recursive_matrix_product(a.m00, b.m01, c.m01); + recursive_matrix_product(a.m01, b.m11, c.m01); + recursive_matrix_product(a.m10, b.m01, c.m11); + recursive_matrix_product(a.m11, b.m11, c.m11); + } +} + + +#define i_type Values +#define i_val double +#include +#include + +int main(void) +{ + enum {N = 10, D1 = 256, D2 = D1}; + + Values values = {0}; + for (int i=0; i < N*D1*D2; ++i) + Values_push(&values, (crandf() - 0.5f)*4.0f); + + double out[D1*D2]; + Mat3 data = cspan_md_order('C', values.data, N, D1, D2); + OutMat c = cspan_md_order('C', out, D1, D2); + Mat2 a = cspan_submd3(&data, 0); + double sum = 0.0; + clock_t t = clock(); + + for (int i=1; i Date: Wed, 16 Aug 2023 17:25:08 +0200 Subject: matmult.c cleanup. --- misc/examples/spans/matmult.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/examples/spans/matmult.c b/misc/examples/spans/matmult.c index 62c0c26b..b28e6459 100644 --- a/misc/examples/spans/matmult.c +++ b/misc/examples/spans/matmult.c @@ -67,7 +67,7 @@ int main(void) Values values = {0}; for (int i=0; i < N*D1*D2; ++i) - Values_push(&values, (crandf() - 0.5f)*4.0f); + Values_push(&values, (crandf() - 0.5)*4.0); double out[D1*D2]; Mat3 data = cspan_md_order('C', values.data, N, D1, D2); @@ -85,6 +85,6 @@ int main(void) } t = clock() - t; - printf("%.16g: %f\n", sum, (float)t*1000.0f/CLOCKS_PER_SEC); + printf("%.16g: %f\n", sum, (double)t*1000.0/CLOCKS_PER_SEC); Values_drop(&values); } -- cgit v1.2.3 From 3da201d122a47f7bf6381b23702815474d64c471 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 16 Aug 2023 20:00:44 +0200 Subject: Update cspan docs. --- docs/cspan_api.md | 208 ++++++++++++++++++++++++++++++------------------------ include/c11/fmt.h | 6 +- 2 files changed, 119 insertions(+), 95 deletions(-) diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 51d72856..606e63c9 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -65,155 +65,179 @@ OutSpanN cspan_submd4(const SpanType4* parent, intptr_t x, ...); // num // {i}: reduce rank. {i,c_END}: slice to end. {c_ALL}: use full extent. OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeM* parent, {x0,x1}, {y0,y1}.., {N0,N1}); ``` -## TypesPd +## Types | Type name | Type definition / usage | Used to represent... | |:------------------|:----------------------------------------------------|:---------------------| | SpanTypeN | `struct { ValueType *data; uint32_t shape[N]; .. }` | SpanType with rank N | | SpanTypeN`_value` | `ValueType` | The ValueType | | `c_ALL` | Use with `cspan_slice()`. | Full extent | | `c_END` | " | End of extent | - + ## Example 1 -Dimension slicing in python, C, and C++: +[ [Run this code](https://godbolt.org/z/Tv9d1T3TM) ] +```c +#include +#define i_key int +#include + +#define i_key int +#include + +#include +using_cspan(intspan, int); + +void printMe(intspan container) { + printf("%d:", (int)cspan_size(&container)); + c_foreach (e, intspan, container) + printf(" %d", *e.ref); + puts(""); +} + +int main(void) +{ + printMe( c_init(intspan, {1, 2, 3, 4}) ); + + int arr[] = {1, 2, 3, 4, 5}; + printMe( (intspan)cspan_from_array(arr) ); + + cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5, 6}); + printMe( (intspan)cspan_from(&vec) ); + + cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7}); + printMe( (intspan)cspan_from(&stk) ); + + intspan spn = c_init(intspan, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + printMe( (intspan)cspan_subspan(&spn, 2, 8) ); + + // cleanup + cvec_int_drop(&vec); + cstack_int_drop(&stk); +} +``` + +## Example 2 + +Multi-dimension slicing (first in python): ```py import numpy as np +def print_span(s2): + for i in range(s2.shape[0]): + for j in range(s2.shape[1]): + print(" {}".format(s2[i, j]), end='') + print('') + print('') + if __name__ == '__main__': ms3 = np.array((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24), int) - ms3 = np.reshape(ms3, (2, 3, 4)) - ss3 = ms3[:, 1:3, 2:] - ss2 = ss3[1] + ms3 = np.reshape(ms3, (2, 3, 4), order='C') + ss3 = ms3[:, 0:3, 2:] + a = ss3[1] + b = np.transpose(a) - for i in range(ss2.shape[0]): - for j in range(ss2.shape[1]): - print(" {}".format(ss2[i, j]), end='') - print('') + print_span(ms3[1]) + print_span(a) + print_span(b) - for i in ss2.flat: - print(" {}".format(i), end='') - -# 19 20 23 24 -# 19 20 23 24 + for i in a.flat: print(" {}".format(i), end='') + print('') + # prints row-wise + for i in b.flat: print(" {}".format(i), end='') +''' + 13 14 15 16 + 17 18 19 20 + 21 22 23 24 + + 15 16 + 19 20 + 23 24 + + 15 19 23 + 16 20 24 + + 15 16 19 20 23 24 + 15 19 23 16 20 24 +''' ``` -... can be written in C using cspan: +... in C with STC cspan: + +[ [Run this code](https://godbolt.org/z/e3PeWe7e9) ] ```c #include #include -using_cspan3(myspan, int); // define myspan, myspan2, myspan3. - -int main(void) { - int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; - myspan3 ms3 = cspan_md(arr, 2, 3, 4); // C-order, i.e. row-major. - myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {1,3}, {2,c_END}); - myspan2 ss2 = cspan_submd3(&ss3, 1); +using_cspan3(myspan, int); // define myspan, myspan2, myspan3. - c_forrange (i, ss2.shape[0]) - c_forrange (j, ss2.shape[1]) - printf(" %d", *cspan_at(&ss2, i, j)); +void print_span(myspan2 ms) { + for (int i=0; i < ms.shape[0]; ++i) { + for (int j=0; j < ms.shape[1]; ++j) + printf(" %2d", *cspan_at(&ms, i, j)); + puts(""); + } puts(""); - - c_foreach (i, myspan2, ss2) - printf(" %d", *i.ref); } -``` -... and (almost) in C++23: -```c++ -#include -#include -#include int main(void) { int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; - std::mdspan ms3(arr, 2, 3, 4); - auto ss3 = std::submdspan(ms3, std::full_extent, std::tuple{1,3}, std::tuple{2,4}); - auto ss2 = std::submdspan(ss3, 1, std::full_extent, std::full_extent); + myspan3 ms3 = cspan_md_order('C', arr, 2, 3, 4); // row-major ('F' column-major) + myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {0,3}, {2,c_END}); + myspan2 a = cspan_submd3(&ss3, 1); + myspan2 b = a; + cspan_transpose(&b); - for (std::size_t i = 0; i < ss2.extent(0); ++i) - for (std::size_t j = 0; j < ss2.extent(1); ++j) - std::print(" {}", ss2[i, j]); - std::println(); + print_span((myspan2)cspan_submd3(&ms3, 1)); + print_span(a); + print_span(b); - // std::mdspan can't be iterated joined/flat! + c_foreach (i, myspan2, a) printf(" %d", *i.ref); + puts(""); + // prints in storage order, same as a. + c_foreach (i, myspan2, b) printf(" %d", *i.ref); } ``` -## Example 2 + +## Example 3 Slicing cspan without and with reducing the rank: + +[ [Run this code](https://godbolt.org/z/jjzcvPPxW) ] ```c -#define i_implement -#include -#include +#include #include +#define i_key int +#include +#define i_key int +#include using_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3 int main(void) { - // c_init() can create any STC container/span from an initializer list: Span span = c_init(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}); - // create a 3d cspan: Span3 span3 = cspan_md(span.data, 2, 4, 3); - // reduce rank: (i.e. span3[1]) - Span2 span2 = cspan_submd3(&span3, 1); - - puts("\niterate span2 flat:"); - c_foreach (i, Span2, span2) - fmt_print(" {}", *i.ref); - puts(""); - - // create span on-the-fly - int array[] = {3, 65, 4, 3, 7, 87, 45}; - c_forfilter (i, ISpan, (ISpan)cspan_from_array(array), - c_flt_skip(i, 2) && - c_flt_take(i, 3)) - fmt_print(" {}", *i.ref); - puts(""); - // slice without reducing rank: Span3 ss3 = cspan_slice(Span3, &span3, {c_ALL}, {3,4}, {c_ALL}); - puts("\niterate ss3 by dimensions:"); c_forrange (i, ss3.shape[0]) { c_forrange (j, ss3.shape[1]) { c_forrange (k, ss3.shape[2]) - fmt_print(" {:2}", *cspan_at(&ss3, i, j, k)); - fmt_print(" |"); + printf(" %2d", *cspan_at(&ss3, i, j, k)); + puts(""); } + puts(""); } + // slice and reduce rank: Span2 ss2 = cspan_slice(Span2, &span3, {c_ALL}, {3}, {c_ALL}); - puts("\niterate ss2 by dimensions:"); c_forrange (i, ss2.shape[0]) { c_forrange (j, ss2.shape[1]) - fmt_print(" {:2}", *cspan_at(&ss2, i, j)); - fmt_print(" |"); + printf(" %2d", *cspan_at(&ss2, i, j)); + puts(""); } - - puts("\niterate ss2 flat:"); - c_foreach (i, Span2, ss2) - fmt_print(" {:2}", *i.ref); - puts(""); } ``` -Output: -``` -iterate span2 flat: - 13 14 15 16 17 18 19 20 21 22 23 24 - -iterate ss3 by dimensions: - 10 11 12 | - 22 23 24 | - -iterate ss2 by dimensions: - 10 | 11 | 12 | - 22 | 23 | 24 | - -iterate ss2 flat: - 10 11 12 22 23 24 -``` diff --git a/include/c11/fmt.h b/include/c11/fmt.h index df96bae3..7787bdb0 100644 --- a/include/c11/fmt.h +++ b/include/c11/fmt.h @@ -208,9 +208,9 @@ void fmt_close(fmt_stream* ss) { } const char* fmt_tm(const char *fmt, const struct tm *tp) { - static char buf[2][64], i = 1; - i = !i; - strftime(buf[i], 64, fmt, tp); + static char buf[2][64]; + static int i; + strftime(buf[(i = !i)], sizeof buf[0], fmt, tp); return buf[i]; } -- cgit v1.2.3 From 2ba238e66efec7b6d895425c4f1160b3b72d242b Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Thu, 17 Aug 2023 04:37:22 +0200 Subject: Small refactoring. --- docs/coroutine_api.md | 12 ++++++------ docs/crawstr_api.md | 43 +++++++++++++++++++++---------------------- docs/cspan_api.md | 10 +++++----- docs/cstr_api.md | 12 +++++++++--- include/stc/crawstr.h | 9 --------- include/stc/cspan.h | 2 +- 6 files changed, 42 insertions(+), 46 deletions(-) diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md index c44f4a4d..b917e0a1 100644 --- a/docs/coroutine_api.md +++ b/docs/coroutine_api.md @@ -231,25 +231,25 @@ void print_time() // PRODUCER cco_task_struct (produce_items, struct next_value next; - cstr str; + cstr text; ); int produce_items(struct produce_items* p, cco_runtime* rt) { cco_routine (p) { - p->str = cstr_init(); + p->text = cstr_init(); p->next.cco_func = next_value; while (true) { // await for CCO_YIELD (or CCO_DONE) cco_await_task(&p->next, rt, CCO_YIELD); - cstr_printf(&p->str, "item %d", p->next.val); + cstr_printf(&p->text, "item %d", p->next.val); print_time(); - printf("produced %s\n", cstr_str(&p->str)); + printf("produced %s\n", cstr_str(&p->text)); cco_yield(); } cco_final: - cstr_drop(&p->str); + cstr_drop(&p->text); puts("done produce"); } return 0; @@ -271,7 +271,7 @@ int consume_items(struct consume_items* c, cco_runtime* rt) printf("consume #%d\n", c->i); cco_await_task(&c->produce, rt, CCO_YIELD); print_time(); - printf("consumed %s\n", cstr_str(&c->produce.str)); + printf("consumed %s\n", cstr_str(&c->produce.text)); } cco_final: cco_stop(&c->produce); diff --git a/docs/crawstr_api.md b/docs/crawstr_api.md index d44c302d..59087d06 100644 --- a/docs/crawstr_api.md +++ b/docs/crawstr_api.md @@ -22,31 +22,37 @@ All crawstr definitions and prototypes are available by including a single heade ## Methods ```c -crawstr crawstr_from(const char* str); // construct from const char* -crawstr c_rs(const char literal_only[]); // construct from literal, no strlen() +crawstr crawstr_from(const char* str); // construct from const char* +crawstr c_rs(const char literal_only[]); // construct from literal, no strlen() intptr_t crawstr_size(crawstr rs); -bool crawstr_empty(crawstr rs); // check if size == 0 +bool crawstr_empty(crawstr rs); // check if size == 0 void crawstr_clear(crawstr* self); -csview crawstr_sv(crawstr rs); // convert to csview type +csview crawstr_sv(crawstr rs); // convert to csview type +const char* crawstr_str(crawstr rs); // get null-terminated const char* bool crawstr_equals(crawstr rs, const char* str); intptr_t crawstr_find(crawstr rs, const char* str); bool crawstr_contains(crawstr rs, const char* str); bool crawstr_starts_with(crawstr rs, const char* str); bool crawstr_ends_with(crawstr rs, const char* str); -``` - -#### UTF8 methods -```c -intptr_t crawstr_u8_size(crawstr rs); -bool crawstr_valid_utf8(crawstr rs); // depends on src/utf8code.c crawstr_iter crawstr_begin(const crawstr* self); crawstr_iter crawstr_end(const crawstr* self); -void crawstr_next(crawstr_iter* it); // utf8 codepoint step, not byte! +void crawstr_next(crawstr_iter* it); // utf8 codepoint step, not byte! crawstr_iter crawstr_advance(crawstr_iter it, intptr_t n); +``` +#### Helper methods for usage in containers +```c +int crawstr_cmp(const crawstr* x, const crawstr* y); +int crawstr_icmp(const crawstr* x, const crawstr* y); // depends on src/utf8code.c: +bool crawstr_eq(const crawstr* x, const crawstr* y); +uint64_t crawstr_hash(const crawstr* x); +``` + +#### UTF8 methods +```c // from utf8.h intptr_t utf8_size(const char *s); intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes @@ -62,14 +68,6 @@ uint32_t utf8_peek(const char* s); // codep uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative) ``` -#### Helper methods -```c -int crawstr_cmp(const crawstr* x, const crawstr* y); -int crawstr_icmp(const crawstr* x, const crawstr* y); // depends on src/utf8code.c: -bool crawstr_eq(const crawstr* x, const crawstr* y); -uint64_t crawstr_hash(const crawstr* x); -``` - ## Types | Type name | Type definition | Used to represent... | @@ -86,14 +84,14 @@ uint64_t crawstr_hash(const crawstr* x); int main(void) { - cstr str = cstr_from("Liberté, égalité, fraternité."); - crawstr rs = cstr_rs(&str); + crawstr rs = c_rs("Liberté, égalité, fraternité."); + printf("%s\n", rs.str); c_foreach (i, crawstr, rs) printf("%.*s ", c_SV(i.u8.chr)); puts(""); - cstr_uppercase(&str); + cstr str = cstr_toupper_sv(crawstr_sv(rs)); printf("%s\n", cstr_str(&str)); cstr_drop(&str); @@ -101,6 +99,7 @@ int main(void) ``` Output: ``` +Liberté, égalité, fraternité. L i b e r t é , é g a l i t é , f r a t e r n i t é . LIBERTÉ, ÉGALITÉ, FRATERNITÉ. ``` diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 606e63c9..39b97473 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -222,9 +222,9 @@ int main(void) // slice without reducing rank: Span3 ss3 = cspan_slice(Span3, &span3, {c_ALL}, {3,4}, {c_ALL}); - c_forrange (i, ss3.shape[0]) { - c_forrange (j, ss3.shape[1]) { - c_forrange (k, ss3.shape[2]) + for (int i=0; i < ss3.shape[0]; ++i) { + for (int j=0; j < ss3.shape[1]; ++j) { + for (int k=0; k < ss3.shape[2]; ++k) printf(" %2d", *cspan_at(&ss3, i, j, k)); puts(""); } @@ -234,8 +234,8 @@ int main(void) // slice and reduce rank: Span2 ss2 = cspan_slice(Span2, &span3, {c_ALL}, {3}, {c_ALL}); - c_forrange (i, ss2.shape[0]) { - c_forrange (j, ss2.shape[1]) + for (int i=0; i < ss2.shape[0]; ++i) { + for (int j=0; j < ss2.shape[1]; ++j) printf(" %2d", *cspan_at(&ss2, i, j)); puts(""); } diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 39bd4e94..bcb0d172 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -1,11 +1,17 @@ # STC [cstr](../include/stc/cstr.h): String ![String](pics/string.jpg) -A **cstr** object represent sequences of characters. It supports an interface similar to that of a standard container of bytes, but adding features specifically designed to operate with strings of single-byte characters, terminated by the null character. +A **cstr** object represent sequences of characters. It supports an interface similar +to that of a standard container of bytes, but adding features specifically designed to +operate with strings of single-byte characters, terminated by the null character. -**cstr** has basic support for *UTF8* encoded strings, and has a set of compact and efficient functions for handling case-foldings and comparisons of UTF strings. +**cstr** has basic support for *UTF8* encoded strings, and has a set of compact and +efficient functions for handling case-conversion, iteration and indexing into UTF8 +codepoints. -**cstr** uses short strings optimization (sso), which eliminates heap memory allocation for string capacity less than 24 bytes. `sizeof(cstr)` is also 24. In comparison, c++ `sizeof(std::string)` is typically 32, but sso capacity is only 15 bytes. +**cstr** uses short strings optimization (sso), which eliminates heap memory allocation +for string capacity up to 22 bytes. `sizeof(cstr)` is 24. In comparison, C++ +`sizeof(std::string)` is typically 32, but sso capacity is only 15 bytes. ## Header file diff --git a/include/stc/crawstr.h b/include/stc/crawstr.h index 7cf62e94..3b836222 100644 --- a/include/stc/crawstr.h +++ b/include/stc/crawstr.h @@ -83,19 +83,10 @@ STC_INLINE crawstr_iter crawstr_advance(crawstr_iter it, intptr_t pos) { return it; } -/* utf8 size */ -STC_INLINE intptr_t crawstr_u8_size(crawstr rs) - { return utf8_size_n(rs.str, rs.size); } - -/* utf8 validation: depends on src/utf8code.c */ -STC_INLINE bool crawstr_valid_utf8(crawstr rs) - { return utf8_valid_n(rs.str, rs.size); } - /* utf8 ignore case cmp: depends on src/utf8code.c */ STC_INLINE int crawstr_icmp(const crawstr* x, const crawstr* y) { return utf8_icmp_sv(c_sv_2(x->str, x->size), c_sv_2(y->str, y->size)); } - STC_INLINE int crawstr_cmp(const crawstr* x, const crawstr* y) { intptr_t n = x->size < y->size ? x->size : y->size; int c = c_memcmp(x->str, y->str, n); diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 1b57d4d4..f806ed8f 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -24,7 +24,7 @@ /* #include #include -#include +#include using_cspan(Span2f, float, 2); using_cspan(Intspan, int); -- cgit v1.2.3 From be0e64a9a19d3ca459284c61c497d141a78df1d7 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Thu, 17 Aug 2023 05:34:38 +0200 Subject: Renamed "internal" csview member .str => .buf, as it is not null terminated like crawstr .str member. --- docs/crawstr_api.md | 32 +------------ docs/csview_api.md | 20 ++++---- include/stc/ccommon.h | 2 +- include/stc/cregex.h | 2 +- include/stc/cstr.h | 60 ++++++++++++------------ include/stc/csview.h | 46 +++++++++--------- include/stc/forward.h | 2 +- misc/examples/coroutines/cotasks1.c | 12 ++--- misc/examples/coroutines/cotasks2.c | 12 ++--- misc/examples/regularexpressions/regex_match.c | 2 +- misc/examples/regularexpressions/regex_replace.c | 2 +- misc/tests/cregex_test.c | 4 +- src/cregex.c | 34 +++++++------- src/utf8code.c | 6 +-- 14 files changed, 104 insertions(+), 132 deletions(-) diff --git a/docs/crawstr_api.md b/docs/crawstr_api.md index 59087d06..97804e23 100644 --- a/docs/crawstr_api.md +++ b/docs/crawstr_api.md @@ -15,8 +15,6 @@ storage. It keeps the length of the string, i.e. no need to call *strlen()* for All crawstr definitions and prototypes are available by including a single header file. ```c -#define i_implement -#include #include ``` ## Methods @@ -29,7 +27,6 @@ intptr_t crawstr_size(crawstr rs); bool crawstr_empty(crawstr rs); // check if size == 0 void crawstr_clear(crawstr* self); csview crawstr_sv(crawstr rs); // convert to csview type -const char* crawstr_str(crawstr rs); // get null-terminated const char* bool crawstr_equals(crawstr rs, const char* str); intptr_t crawstr_find(crawstr rs, const char* str); @@ -72,8 +69,8 @@ uint32_t utf8_peek_off(const char* s, int offset); // codep | Type name | Type definition | Used to represent... | |:----------------|:-------------------------------------------|:-------------------------| -| `crawstr` | `struct { const char *str; intptr_t size; }` | The string view type | -| `crawstr_value` | `char` | The string element type | +| `crawstr` | `struct { const char *str; intptr_t size; }` | Raw string view type | +| `crawstr_value` | `char` | Raw string element type | | `crawstr_iter` | `struct { crawstr_value *ref; }` | UTF8 iterator | ## Example: UTF8 iteration and case conversion @@ -93,7 +90,6 @@ int main(void) cstr str = cstr_toupper_sv(crawstr_sv(rs)); printf("%s\n", cstr_str(&str)); - cstr_drop(&str); } ``` @@ -103,27 +99,3 @@ Liberté, égalité, fraternité. L i b e r t é , é g a l i t é , f r a t e r n i t é . LIBERTÉ, ÉGALITÉ, FRATERNITÉ. ``` - -### Example 2: UTF8 replace -```c -#define i_import // include dependent utf8 definitions. -#include - -int main(void) -{ - cstr s1 = cstr_lit("hell😀 w😀rld"); - - cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_rs("ø")); - printf("%s\n", cstr_str(&s1)); - - c_foreach (i, cstr, s1) - printf("%.*s,", c_SV(i.u8.chr)); // u8.chr is a csview - - cstr_drop(&s1); -} -``` -Output: -``` -hell😀 wørld -h,e,l,l,😀, ,w,ø,r,l,d, -``` diff --git a/docs/csview_api.md b/docs/csview_api.md index eafc6854..5202d6f5 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -1,14 +1,14 @@ # STC [csview](../include/stc/csview.h): Sub-string View ![String](pics/string.jpg) -The type **csview** is a non-null terminated string view and can refer to a constant contiguous sequence of -char-elements with the first element of the sequence at position zero. The implementation holds two members: -a pointer to constant char and a size. +The type **csview** is a non-null terminated string view and can refer to a constant contiguous +sequence of char-elements with the first element of the sequence at position zero. The implementation +holds two members: a pointer to constant char and a size. -Because **csview** is non-null terminated, it is not an ideal replacent view for `const char*` - see [crawstr](crawstr_api.md) -for that. **csview** never allocates memory, and therefore need not be destructed. Its lifetime is limited by -the source string storage. It keeps the length of the string, and does not need to call *strlen()* to acquire -the length. +Because **csview** is non-null terminated, it cannot be a replacent view for `const char*` - +see [crawstr](crawstr_api.md) for that. **csview** never allocates memory, and therefore need not be +destructed. Its lifetime is limited by the source string storage. It keeps the length of the string, +and does not need to call *strlen()* to acquire the length. - **csview** iterators works on UTF8 codepoints - like **cstr** and **crawstr** (see Example 2). - Because it is null-terminated, it must be printed the following way: @@ -16,8 +16,8 @@ the length. printf("%.*s", c_SV(sstr)); ``` -See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional -description. +See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) +for a functional description. ## Header file @@ -95,7 +95,7 @@ uint64_t csview_hash(const csview* x); | Type name | Type definition | Used to represent... | |:----------------|:-------------------------------------------|:-------------------------| -| `csview` | `struct { const char *str; intptr_t size; }` | The string view type | +| `csview` | `struct { const char *buf; intptr_t size; }` | The string view type | | `csview_value` | `char` | The string element type | | `csview_iter` | `struct { csview_value *ref; }` | UTF8 iterator | diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index e33e657a..5c5e87e6 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -133,7 +133,7 @@ typedef const char* ccharptr; #define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) #define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal)) #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) -#define c_SV(sv) (int)(sv).size, (sv).str // printf("%.*s\n", c_SV(sv)); +#define c_SV(sv) (int)(sv).size, (sv).buf // printf("%.*s\n", c_SV(sv)); #define c_rs(literal) c_rs_2(literal, c_litstrlen(literal)) #define c_rs_2(str, n) (c_LITERAL(crawstr){str, n}) diff --git a/include/stc/cregex.h b/include/stc/cregex.h index bce94b04..c8ad6dbe 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -121,7 +121,7 @@ int cregex_find_4(const cregex* re, const char* input, csview match[], int mflag STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { csview *mp = NULL; if (match) { match[0] = input; mp = match; } - return cregex_find(re, input.str, mp, CREG_STARTEND); + return cregex_find(re, input.buf, mp, CREG_STARTEND); } /* match + compile RE pattern */ diff --git a/include/stc/cstr.h b/include/stc/cstr.h index bc147469..eeb65c39 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -98,7 +98,7 @@ STC_INLINE csview cstr_sv(const cstr* s) { : c_sv_2(s->sml.data, cstr_s_size(s)); } STC_INLINE crawstr cstr_rs(const cstr* s) - { csview sv = cstr_sv(s); return c_rs_2(sv.str, sv.size); } + { csview sv = cstr_sv(s); return c_rs_2(sv.buf, sv.size); } STC_INLINE cstr cstr_init(void) { return cstr_null; } @@ -113,7 +113,7 @@ STC_INLINE cstr cstr_from(const char* str) { return cstr_from_n(str, c_strlen(str)); } STC_INLINE cstr cstr_from_sv(csview sv) - { return cstr_from_n(sv.str, sv.size); } + { return cstr_from_n(sv.buf, sv.size); } STC_INLINE cstr cstr_from_rs(crawstr rs) { return cstr_from_n(rs.str, rs.size); } @@ -145,7 +145,7 @@ STC_INLINE cstr cstr_move(cstr* self) { STC_INLINE cstr cstr_clone(cstr s) { csview sv = cstr_sv(&s); - return cstr_from_n(sv.str, sv.size); + return cstr_from_n(sv.buf, sv.size); } STC_INLINE void cstr_drop(cstr* self) { @@ -201,8 +201,8 @@ STC_INLINE const char* cstr_u8_at(const cstr* self, intptr_t u8idx) STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { const char* str = cstr_str(self); csview sv; - sv.str = utf8_at(str, u8idx); - sv.size = utf8_chr_size(sv.str); + sv.buf = utf8_at(str, u8idx); + sv.size = utf8_chr_size(sv.buf); return sv; } @@ -211,7 +211,7 @@ STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { STC_INLINE cstr_iter cstr_begin(const cstr* self) { csview sv = cstr_sv(self); if (!sv.size) return c_LITERAL(cstr_iter){.ref = NULL}; - return c_LITERAL(cstr_iter){.u8 = {{sv.str, utf8_chr_size(sv.str)}}}; + return c_LITERAL(cstr_iter){.u8 = {{sv.buf, utf8_chr_size(sv.buf)}}}; } STC_INLINE cstr_iter cstr_end(const cstr* self) { (void)self; return c_LITERAL(cstr_iter){NULL}; @@ -242,7 +242,7 @@ STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2) STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { csview x = cstr_sv(s1), y = cstr_sv(s2); - return x.size == y.size && !c_memcmp(x.str, y.str, x.size); + return x.size == y.size && !c_memcmp(x.buf, y.buf, x.size); } @@ -250,7 +250,7 @@ STC_INLINE bool cstr_equals(const cstr* self, const char* str) { return !strcmp(cstr_str(self), str); } STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv) - { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } + { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.buf, sv.size); } STC_INLINE bool cstr_equals_s(const cstr* self, cstr s) { return !cstr_cmp(self, &s); } @@ -280,7 +280,7 @@ STC_INLINE bool cstr_contains_s(const cstr* self, cstr search) STC_INLINE bool cstr_starts_with_sv(const cstr* self, csview sub) { if (sub.size > cstr_size(self)) return false; - return !c_memcmp(cstr_str(self), sub.str, sub.size); + return !c_memcmp(cstr_str(self), sub.buf, sub.size); } STC_INLINE bool cstr_starts_with(const cstr* self, const char* sub) { @@ -302,7 +302,7 @@ STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) { STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) { csview sv = cstr_sv(self); if (sub.size > sv.size) return false; - return !c_memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); + return !c_memcmp(sv.buf + sv.size - sub.size, sub.buf, sub.size); } STC_INLINE bool cstr_ends_with_s(const cstr* self, cstr sub) @@ -314,7 +314,7 @@ STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub) STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { csview sv = cstr_sv(self); intptr_t n = c_strlen(sub); - return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub); + return n <= sv.size && !utf8_icmp(sv.buf + sv.size - n, sub); } @@ -322,11 +322,11 @@ STC_INLINE char* cstr_assign(cstr* self, const char* str) { return cstr_assign_n(self, str, c_strlen(str)); } STC_INLINE char* cstr_assign_sv(cstr* self, csview sv) - { return cstr_assign_n(self, sv.str, sv.size); } + { return cstr_assign_n(self, sv.buf, sv.size); } STC_INLINE char* cstr_copy(cstr* self, cstr s) { csview sv = cstr_sv(&s); - return cstr_assign_n(self, sv.str, sv.size); + return cstr_assign_n(self, sv.buf, sv.size); } @@ -335,16 +335,16 @@ STC_INLINE char* cstr_push(cstr* self, const char* chr) STC_INLINE void cstr_pop(cstr* self) { csview sv = cstr_sv(self); - const char* s = sv.str + sv.size; + const char* s = sv.buf + sv.size; while ((*--s & 0xC0) == 0x80) ; - _cstr_set_size(self, (s - sv.str)); + _cstr_set_size(self, (s - sv.buf)); } STC_INLINE char* cstr_append(cstr* self, const char* str) { return cstr_append_n(self, str, c_strlen(str)); } STC_INLINE char* cstr_append_sv(cstr* self, csview sv) - { return cstr_append_n(self, sv.str, sv.size); } + { return cstr_append_n(self, sv.buf, sv.size); } STC_INLINE char* cstr_append_s(cstr* self, cstr s) { return cstr_append_sv(self, cstr_sv(&s)); } @@ -358,7 +358,7 @@ STC_INLINE void cstr_replace_4(cstr* self, const char* search, const char* repl, STC_INLINE void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl) { char* d = _cstr_internal_move(self, pos + len, pos + repl.size); - c_memcpy(d + pos, repl.str, repl.size); + c_memcpy(d + pos, repl.buf, repl.size); } STC_INLINE void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl) @@ -400,12 +400,12 @@ fn_tocase[] = {{tolower, utf8_casefold}, static cstr cstr_tocase(csview sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); - const char *end = sv.str + sv.size; + const char *end = sv.buf + sv.size; uint32_t cp; intptr_t sz = 0; utf8_decode_t d = {.state=0}; - while (sv.str < end) { - do { utf8_decode(&d, (uint8_t)*sv.str++); } while (d.state); + while (sv.buf < end) { + do { utf8_decode(&d, (uint8_t)*sv.buf++); } while (d.state); if (d.codep < 128) buf[sz++] = (char)fn_tocase[k].conv_asc((int)d.codep); else { @@ -450,13 +450,13 @@ bool cstr_valid_utf8(const cstr* self) STC_DEF uint64_t cstr_hash(const cstr *self) { csview sv = cstr_sv(self); - return cfasthash(sv.str, sv.size); + return cfasthash(sv.buf, sv.size); } STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { csview sv = cstr_sv(self); - char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); - return res ? (res - sv.str) : c_NPOS; + char* res = cstrnstrn(sv.buf, search.buf, sv.size, search.size); + return res ? (res - sv.buf) : c_NPOS; } STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { @@ -532,8 +532,8 @@ STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) { STC_DEF intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { csview sv = cstr_sv(self); if (pos > sv.size) return c_NPOS; - const char* res = strstr((char*)sv.str + pos, search); - return res ? (res - sv.str) : c_NPOS; + const char* res = strstr((char*)sv.buf + pos, search); + return res ? (res - sv.buf) : c_NPOS; } STC_DEF char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { @@ -588,13 +588,13 @@ STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t coun intptr_t from = 0; char* res; if (!count) count = INT32_MAX; if (search.size) - while (count-- && (res = cstrnstrn(in.str + from, search.str, in.size - from, search.size))) { - const intptr_t pos = (res - in.str); - cstr_append_n(&out, in.str + from, pos - from); - cstr_append_n(&out, repl.str, repl.size); + while (count-- && (res = cstrnstrn(in.buf + from, search.buf, in.size - from, search.size))) { + const intptr_t pos = (res - in.buf); + cstr_append_n(&out, in.buf + from, pos - from); + cstr_append_n(&out, repl.buf, repl.size); from = pos + search.size; } - cstr_append_n(&out, in.str + from, in.size - from); + cstr_append_n(&out, in.buf + from, in.size - from); return out; } diff --git a/include/stc/csview.h b/include/stc/csview.h index 2a051ddd..5aba6926 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -46,7 +46,7 @@ STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } STC_INLINE bool csview_equals_sv(csview sv1, csview sv2) - { return sv1.size == sv2.size && !c_memcmp(sv1.str, sv2.str, sv1.size); } + { return sv1.size == sv2.size && !c_memcmp(sv1.buf, sv2.buf, sv1.size); } STC_INLINE bool csview_equals(csview sv, const char* str) { return csview_equals_sv(sv, c_sv_2(str, c_strlen(str))); } @@ -59,34 +59,34 @@ STC_INLINE bool csview_contains(csview sv, const char* str) STC_INLINE bool csview_starts_with(csview sv, const char* str) { intptr_t n = c_strlen(str); - return n > sv.size ? false : !c_memcmp(sv.str, str, n); + return n > sv.size ? false : !c_memcmp(sv.buf, str, n); } STC_INLINE bool csview_ends_with(csview sv, const char* str) { intptr_t n = c_strlen(str); - return n > sv.size ? false : !c_memcmp(sv.str + sv.size - n, str, n); + return n > sv.size ? false : !c_memcmp(sv.buf + sv.size - n, str, n); } STC_INLINE csview csview_substr(csview sv, intptr_t pos, intptr_t n) { if (pos + n > sv.size) n = sv.size - pos; - sv.str += pos, sv.size = n; + sv.buf += pos, sv.size = n; return sv; } STC_INLINE csview csview_slice(csview sv, intptr_t p1, intptr_t p2) { if (p2 > sv.size) p2 = sv.size; - sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; + sv.buf += p1, sv.size = p2 > p1 ? p2 - p1 : 0; return sv; } /* utf8 iterator */ STC_INLINE csview_iter csview_begin(const csview* self) { if (!self->size) return c_LITERAL(csview_iter){NULL}; - return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, - self->str + self->size}}; + return c_LITERAL(csview_iter){.u8 = {{self->buf, utf8_chr_size(self->buf)}, + self->buf + self->size}}; } STC_INLINE csview_iter csview_end(const csview* self) { - return c_LITERAL(csview_iter){.u8 = {{NULL}, self->str + self->size}}; + return c_LITERAL(csview_iter){.u8 = {{NULL}, self->buf + self->size}}; } STC_INLINE void csview_next(csview_iter* it) { it->ref += it->u8.chr.size; @@ -96,21 +96,21 @@ STC_INLINE void csview_next(csview_iter* it) { /* utf8 */ STC_INLINE intptr_t csview_u8_size(csview sv) - { return utf8_size_n(sv.str, sv.size); } + { return utf8_size_n(sv.buf, sv.size); } STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) { - sv.str += bytepos; - sv.size = utf8_pos(sv.str, u8len); + sv.buf += bytepos; + sv.size = utf8_pos(sv.buf, u8len); return sv; } STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c - { return utf8_valid_n(sv.str, sv.size); } + { return utf8_valid_n(sv.buf, sv.size); } #define c_fortoken_sv(it, inputsv, sep) \ for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \ it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \ - ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).str ; ) + ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).buf ; ) #define c_fortoken(it, input, sep) \ c_fortoken_sv(it, csview_from(input), sep) @@ -119,7 +119,7 @@ STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c STC_INLINE int csview_cmp(const csview* x, const csview* y) { intptr_t n = x->size < y->size ? x->size : y->size; - int c = c_memcmp(x->str, y->str, n); + int c = c_memcmp(x->buf, y->buf, n); return c ? c : (int)(x->size - y->size); } @@ -127,7 +127,7 @@ STC_INLINE int csview_icmp(const csview* x, const csview* y) { return utf8_icmp_sv(*x, *y); } STC_INLINE bool csview_eq(const csview* x, const csview* y) - { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } + { return x->size == y->size && !c_memcmp(x->buf, y->buf, x->size); } #endif // CSVIEW_H_INCLUDED @@ -165,12 +165,12 @@ STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { } STC_DEF intptr_t csview_find_sv(csview sv, csview search) { - char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); - return res ? (res - sv.str) : c_NPOS; + char* res = cstrnstrn(sv.buf, search.buf, sv.size, search.size); + return res ? (res - sv.buf) : c_NPOS; } STC_DEF uint64_t csview_hash(const csview *self) - { return cfasthash(self->str, self->size); } + { return cfasthash(self->buf, self->size); } STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { if (pos < 0) { @@ -179,7 +179,7 @@ STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { } if (pos > sv.size) pos = sv.size; if (pos + n > sv.size) n = sv.size - pos; - sv.str += pos, sv.size = n; + sv.buf += pos, sv.size = n; return sv; } @@ -190,15 +190,15 @@ STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { } if (p2 < 0) p2 += sv.size; if (p2 > sv.size) p2 = sv.size; - sv.str += p1, sv.size = (p2 > p1 ? p2 - p1 : 0); + sv.buf += p1, sv.size = (p2 > p1 ? p2 - p1 : 0); return sv; } STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { intptr_t sep_size = c_strlen(sep); - csview slice = {sv.str + *start, sv.size - *start}; - const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); - csview tok = {slice.str, res ? (res - slice.str) : slice.size}; + csview slice = {sv.buf + *start, sv.size - *start}; + const char* res = cstrnstrn(slice.buf, sep, slice.size, sep_size); + csview tok = {slice.buf, res ? (res - slice.buf) : slice.size}; *start += tok.size + sep_size; return tok; } diff --git a/include/stc/forward.h b/include/stc/forward.h index 839be012..9f7a0063 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -42,7 +42,7 @@ // csview : non-null terminated string view typedef const char csview_value; typedef struct csview { - csview_value* str; + csview_value* buf; intptr_t size; } csview; diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c index db9632e6..cffd6620 100644 --- a/misc/examples/coroutines/cotasks1.c +++ b/misc/examples/coroutines/cotasks1.c @@ -36,24 +36,24 @@ void print_time() struct produce_items { struct next_value next; - cstr str; + cstr text; int cco_state; }; int produce_items(struct produce_items* p) { cco_routine (p) { - p->str = cstr_init(); + p->text = cstr_init(); while (true) { cco_await(next_value(&p->next) != CCO_AWAIT); - cstr_printf(&p->str, "item %d", p->next.val); + cstr_printf(&p->text, "item %d", p->next.val); print_time(); - printf("produced %s\n", cstr_str(&p->str)); + printf("produced %s\n", cstr_str(&p->text)); cco_yield(); } cco_final: - cstr_drop(&p->str); + cstr_drop(&p->text); puts("done produce"); } return 0; @@ -74,7 +74,7 @@ int consume_items(struct consume_items* c, struct produce_items* p) printf("consume #%d\n", c->i); cco_await(produce_items(p) != CCO_AWAIT); print_time(); - printf("consumed %s\n", cstr_str(&p->str)); + printf("consumed %s\n", cstr_str(&p->text)); } cco_final: puts("done consume"); diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c index 12c2c4a3..558df118 100644 --- a/misc/examples/coroutines/cotasks2.c +++ b/misc/examples/coroutines/cotasks2.c @@ -35,26 +35,26 @@ void print_time() cco_task_struct (produce_items, struct next_value next; - cstr str; + cstr text; ); int produce_items(struct produce_items* p, cco_runtime* rt) { cco_routine (p) { - p->str = cstr_init(); + p->text = cstr_init(); p->next.cco_func = next_value; while (true) { // await for next CCO_YIELD (or CCO_DONE) in next_value cco_await_task(&p->next, rt, CCO_YIELD); - cstr_printf(&p->str, "item %d", p->next.val); + cstr_printf(&p->text, "item %d", p->next.val); print_time(); - printf("produced %s\n", cstr_str(&p->str)); + printf("produced %s\n", cstr_str(&p->text)); cco_yield(); } cco_final: - cstr_drop(&p->str); + cstr_drop(&p->text); puts("done produce"); } return 0; @@ -77,7 +77,7 @@ int consume_items(struct consume_items* c, cco_runtime* rt) printf("consume #%d\n", c->i); cco_await_task(&c->produce, rt, CCO_YIELD); print_time(); - printf("consumed %s\n", cstr_str(&c->produce.str)); + printf("consumed %s\n", cstr_str(&c->produce.text)); } cco_final: diff --git a/misc/examples/regularexpressions/regex_match.c b/misc/examples/regularexpressions/regex_match.c index 11426d2d..9106ffbd 100644 --- a/misc/examples/regularexpressions/regex_match.c +++ b/misc/examples/regularexpressions/regex_match.c @@ -22,7 +22,7 @@ int main(void) // extract and convert all numbers in str to floats c_formatch (i, &re, str) - cstack_float_push(&vec, (float)atof(i.match[0].str)); + cstack_float_push(&vec, (float)atof(i.match[0].buf)); c_foreach (i, cstack_float, vec) printf(" %g\n", (double)*i.ref); diff --git a/misc/examples/regularexpressions/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c index f1ea2711..087387d7 100644 --- a/misc/examples/regularexpressions/regex_replace.c +++ b/misc/examples/regularexpressions/regex_replace.c @@ -5,7 +5,7 @@ bool add_10_years(int i, csview match, cstr* out) { if (i == 1) { // group 1 matches year int year; - sscanf(match.str, "%4d", &year); // scan 4 chars only + sscanf(match.buf, "%4d", &year); // scan 4 chars only cstr_printf(out, "%04d", year + 10); return true; } diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 4e192de6..a83b7593 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -4,7 +4,7 @@ #include #include "ctest.h" -#define M_START(m) ((m).str - inp) +#define M_START(m) ((m).buf - inp) #define M_END(m) (M_START(m) + (m).size) @@ -238,7 +238,7 @@ CTEST(cregex, captures_cap) static bool add_10_years(int i, csview match, cstr* out) { if (i == 1) { // group 1 matches year int year; - sscanf(match.str, "%4d", &year); // scan 4 chars only + sscanf(match.buf, "%4d", &year); // scan 4 chars only cstr_printf(out, "%04d", year + 10); return true; } diff --git a/src/cregex.c b/src/cregex.c index 551cb6f6..7907ddd9 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -264,8 +264,8 @@ _renewmatch(_Resub *mp, int ms, _Resublist *sp, int nsubids) { if (mp==NULL || ms==0) return; - if (mp[0].str == NULL || sp->m[0].str < mp[0].str || - (sp->m[0].str == mp[0].str && sp->m[0].size > mp[0].size)) { + if (mp[0].buf == NULL || sp->m[0].buf < mp[0].buf || + (sp->m[0].buf == mp[0].buf && sp->m[0].size > mp[0].size)) { for (int i=0; im[i]; } @@ -286,7 +286,7 @@ _renewthread(_Relist *lp, /* _relist to add to */ for (p=lp; p->inst; p++) { if (p->inst == ip) { - if (sep->m[0].str < p->se.m[0].str) { + if (sep->m[0].buf < p->se.m[0].buf) { if (ms > 1) p->se = *sep; else @@ -318,10 +318,10 @@ _renewemptythread(_Relist *lp, /* _relist to add to */ for (p=lp; p->inst; p++) { if (p->inst == ip) { - if (sp < p->se.m[0].str) { + if (sp < p->se.m[0].buf) { if (ms > 1) memset(&p->se, 0, sizeof(p->se)); - p->se.m[0].str = sp; + p->se.m[0].buf = sp; } return 0; } @@ -329,7 +329,7 @@ _renewemptythread(_Relist *lp, /* _relist to add to */ p->inst = ip; if (ms > 1) memset(&p->se, 0, sizeof(p->se)); - p->se.m[0].str = sp; + p->se.m[0].buf = sp; (++p)->inst = NULL; return p; } @@ -1005,7 +1005,7 @@ _regexec1(const _Reprog *progp, /* program to run */ checkstart = j->starttype; if (mp) for (i=0; irelist[0][0].inst = NULL; @@ -1066,10 +1066,10 @@ _regexec1(const _Reprog *progp, /* program to run */ icase = inst->type == TOK_ICASE; continue; case TOK_LBRA: - tlp->se.m[inst->r.subid].str = s; + tlp->se.m[inst->r.subid].buf = s; continue; case TOK_RBRA: - tlp->se.m[inst->r.subid].size = (s - tlp->se.m[inst->r.subid].str); + tlp->se.m[inst->r.subid].size = (s - tlp->se.m[inst->r.subid].buf); continue; case TOK_ANY: ok = (r != '\n'); @@ -1118,8 +1118,8 @@ _regexec1(const _Reprog *progp, /* program to run */ case TOK_END: /* Match! */ match = !(mflags & CREG_FULLMATCH) || ((s == j->eol || r == 0 || r == '\n') && - (tlp->se.m[0].str == bol || tlp->se.m[0].str[-1] == '\n')); - tlp->se.m[0].size = (s - tlp->se.m[0].str); + (tlp->se.m[0].buf == bol || tlp->se.m[0].buf[-1] == '\n')); + tlp->se.m[0].size = (s - tlp->se.m[0].buf); if (mp != NULL) _renewmatch(mp, ms, &tlp->se, progp->nsubids); break; @@ -1185,9 +1185,9 @@ _regexec(const _Reprog *progp, /* program to run */ if (mp && mp[0].size) { if (mflags & CREG_STARTEND) - j.starts = mp[0].str, j.eol = mp[0].str + mp[0].size; + j.starts = mp[0].buf, j.eol = mp[0].buf + mp[0].size; else if (mflags & CREG_NEXT) - j.starts = mp[0].str + mp[0].size; + j.starts = mp[0].buf + mp[0].size; } j.starttype = 0; @@ -1237,7 +1237,7 @@ _build_subst(const char* replace, int nmatch, const csview match[], if (len + m.size > cap) dst = cstr_reserve(subst, cap += cap/2 + m.size); for (int i = 0; i < m.size; ++i) - dst[len++] = m.str[i]; + dst[len++] = m.buf[i]; } ++replace; case '\0': @@ -1302,10 +1302,10 @@ cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int cou while (count-- && cregex_find_sv(re, input, match) == CREG_OK) { _build_subst(replace, nmatch, match, mfun, &subst); - const intptr_t mpos = (match[0].str - input.str); - if (copy & (mpos > 0)) cstr_append_n(&out, input.str, mpos); + const intptr_t mpos = (match[0].buf - input.buf); + if (copy & (mpos > 0)) cstr_append_n(&out, input.buf, mpos); cstr_append_s(&out, subst); - input.str = match[0].str + match[0].size; + input.buf = match[0].buf + match[0].size; input.size -= mpos + match[0].size; } if (copy) cstr_append_sv(&out, input); diff --git a/src/utf8code.c b/src/utf8code.c index 4abf10ea..e326e6b9 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -105,10 +105,10 @@ int utf8_icmp_sv(const csview s1, const csview s2) { utf8_decode_t d1 = {.state=0}, d2 = {.state=0}; intptr_t j1 = 0, j2 = 0; while ((j1 < s1.size) & (j2 < s2.size)) { - do { utf8_decode(&d1, (uint8_t)s1.str[j1++]); } while (d1.state); - do { utf8_decode(&d2, (uint8_t)s2.str[j2++]); } while (d2.state); + do { utf8_decode(&d1, (uint8_t)s1.buf[j1++]); } while (d1.state); + do { utf8_decode(&d2, (uint8_t)s2.buf[j2++]); } while (d2.state); int32_t c = (int32_t)utf8_casefold(d1.codep) - (int32_t)utf8_casefold(d2.codep); - if (c || !s2.str[j2 - 1]) // OK if s1.size and s2.size are npos + if (c || !s2.buf[j2 - 1]) // OK if s1.size and s2.size are npos return (int)c; } return (int)(s1.size - s2.size); -- cgit v1.2.3 From 311f12d7005351ca245aa1df77889d8db4899862 Mon Sep 17 00:00:00 2001 From: tylov Date: Thu, 17 Aug 2023 09:54:16 +0200 Subject: Simplified access to utf8 character .chr in cstr / csview / crawstr iterators. Backward compatibility kept, but deprecated. --- docs/crawstr_api.md | 2 +- docs/csview_api.md | 2 +- include/stc/crawstr.h | 11 ++++++----- include/stc/cstr.h | 6 +++--- include/stc/csview.h | 6 +++--- include/stc/forward.h | 7 +++++-- misc/examples/strings/utf8replace_c.c | 2 +- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/docs/crawstr_api.md b/docs/crawstr_api.md index 97804e23..7d663a04 100644 --- a/docs/crawstr_api.md +++ b/docs/crawstr_api.md @@ -85,7 +85,7 @@ int main(void) printf("%s\n", rs.str); c_foreach (i, crawstr, rs) - printf("%.*s ", c_SV(i.u8.chr)); + printf("%.*s ", c_SV(i.chr)); puts(""); cstr str = cstr_toupper_sv(crawstr_sv(rs)); diff --git a/docs/csview_api.md b/docs/csview_api.md index 5202d6f5..1d58d73c 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -149,7 +149,7 @@ int main(void) printf("%s\n", cstr_str(&s1)); c_foreach (i, cstr, s1) - printf("%.*s,", c_SV(i.u8.chr)); + printf("%.*s,", c_SV(i.chr)); cstr_drop(&s1); } diff --git a/include/stc/crawstr.h b/include/stc/crawstr.h index 3b836222..0395c8c6 100644 --- a/include/stc/crawstr.h +++ b/include/stc/crawstr.h @@ -27,12 +27,13 @@ #define CRAWSTR_H_INCLUDED #define crawstr_init() c_rs("") -#define crawstr_drop(p) c_default_drop(p) #define crawstr_clone(rs) c_default_clone(rs) +#define crawstr_drop(self) c_default_drop(self) +#define crawstr_toraw(self) (self)->str STC_INLINE crawstr crawstr_from(const char* str) { return c_rs_2(str, c_strlen(str)); } -STC_INLINE void crawstr_clear(crawstr* self) { *self = crawstr_init(); } +STC_INLINE void crawstr_clear(crawstr* self) { *self = c_rs(""); } STC_INLINE csview crawstr_sv(crawstr rs) { return c_sv_2(rs.str, rs.size); } STC_INLINE intptr_t crawstr_size(crawstr rs) { return rs.size; } @@ -70,15 +71,15 @@ STC_INLINE crawstr_iter crawstr_end(const crawstr* self) { (void)self; return c_LITERAL(crawstr_iter){.ref = NULL}; } STC_INLINE void crawstr_next(crawstr_iter* it) { - it->ref += it->u8.chr.size; - it->u8.chr.size = utf8_chr_size(it->ref); + it->ref += it->chr.size; + it->chr.size = utf8_chr_size(it->ref); if (!*it->ref) it->ref = NULL; } STC_INLINE crawstr_iter crawstr_advance(crawstr_iter it, intptr_t pos) { int inc = -1; if (pos > 0) pos = -pos, inc = 1; while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); + it.chr.size = utf8_chr_size(it.ref); if (!*it.ref) it.ref = NULL; return it; } diff --git a/include/stc/cstr.h b/include/stc/cstr.h index eeb65c39..f0974865 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -217,15 +217,15 @@ STC_INLINE cstr_iter cstr_end(const cstr* self) { (void)self; return c_LITERAL(cstr_iter){NULL}; } STC_INLINE void cstr_next(cstr_iter* it) { - it->ref += it->u8.chr.size; - it->u8.chr.size = utf8_chr_size(it->ref); + it->ref += it->chr.size; + it->chr.size = utf8_chr_size(it->ref); if (!*it->ref) it->ref = NULL; } STC_INLINE cstr_iter cstr_advance(cstr_iter it, intptr_t pos) { int inc = -1; if (pos > 0) pos = -pos, inc = 1; while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); + it.chr.size = utf8_chr_size(it.ref); if (!*it.ref) it.ref = NULL; return it; } diff --git a/include/stc/csview.h b/include/stc/csview.h index 5aba6926..a2d1e9f0 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -89,8 +89,8 @@ STC_INLINE csview_iter csview_end(const csview* self) { return c_LITERAL(csview_iter){.u8 = {{NULL}, self->buf + self->size}}; } STC_INLINE void csview_next(csview_iter* it) { - it->ref += it->u8.chr.size; - it->u8.chr.size = utf8_chr_size(it->ref); + it->ref += it->chr.size; + it->chr.size = utf8_chr_size(it->ref); if (it->ref == it->u8.end) it->ref = NULL; } @@ -159,7 +159,7 @@ STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { int inc = -1; if (pos > 0) pos = -pos, inc = 1; while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); + it.chr.size = utf8_chr_size(it.ref); if (it.ref == it.u8.end) it.ref = NULL; return it; } diff --git a/include/stc/forward.h b/include/stc/forward.h index 9f7a0063..2372a618 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -48,6 +48,7 @@ typedef struct csview { typedef union { csview_value* ref; + csview chr; struct { csview chr; csview_value* end; } u8; } csview_iter; @@ -61,7 +62,8 @@ typedef struct crawstr { typedef union { crawstr_value* ref; - struct { csview chr; } u8; + csview chr; + struct { csview chr; } u8; // [deprecated] } crawstr_iter; @@ -75,7 +77,8 @@ typedef union cstr { typedef union { cstr_value* ref; - struct { csview chr; } u8; + csview chr; + struct { csview chr; } u8; // [deprecated] } cstr_iter; diff --git a/misc/examples/strings/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c index 1d54486f..317313b0 100644 --- a/misc/examples/strings/utf8replace_c.c +++ b/misc/examples/strings/utf8replace_c.c @@ -15,7 +15,7 @@ int main(void) printf("%s\n", cstr_str(&hello)); c_foreach (c, cstr, hello) - printf("%.*s,", c_SV(c.u8.chr)); + printf("%.*s,", c_SV(c.chr)); cstr str = cstr_lit("scooby, dooby doo"); cstr_replace(&str, "oo", "00"); -- cgit v1.2.3 From 032bf0a0dfe8b5d368118d4da5862323a021b626 Mon Sep 17 00:00:00 2001 From: tylov Date: Thu, 17 Aug 2023 11:40:58 +0200 Subject: Corrected/updated string types in docs. --- docs/crawstr_api.md | 10 +++++----- docs/cstr_api.md | 2 +- docs/csview_api.md | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/crawstr_api.md b/docs/crawstr_api.md index 7d663a04..b63e532f 100644 --- a/docs/crawstr_api.md +++ b/docs/crawstr_api.md @@ -67,11 +67,11 @@ uint32_t utf8_peek_off(const char* s, int offset); // codep ## Types -| Type name | Type definition | Used to represent... | -|:----------------|:-------------------------------------------|:-------------------------| -| `crawstr` | `struct { const char *str; intptr_t size; }` | Raw string view type | -| `crawstr_value` | `char` | Raw string element type | -| `crawstr_iter` | `struct { crawstr_value *ref; }` | UTF8 iterator | +| Type name | Type definition | Used to represent... | +|:----------------|:---------------------------------------------|:-------------------------| +| `crawstr` | `struct { const char *str; intptr_t size; }` | The string view type | +| `crawstr_value` | `const char` | The element type | +| `crawstr_iter` | `union { crawstr_value *ref; csview chr; }` | UTF8 iterator | ## Example: UTF8 iteration and case conversion ```c diff --git a/docs/cstr_api.md b/docs/cstr_api.md index bcb0d172..5f6ce9e4 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -152,7 +152,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr |:----------------|:---------------------------------------------|:---------------------| | `cstr` | `struct { ... }` | The string type | | `cstr_value` | `char` | String element type | -| `csview` | `struct { const char *str; intptr_t size; }` | String view type | +| `cstr_iter` | `union { cstr_value *ref; csview chr; }` | String iterator | | `cstr_buf` | `struct { char *data; intptr_t size, cap; }` | String buffer type | ## Constants and macros diff --git a/docs/csview_api.md b/docs/csview_api.md index 1d58d73c..76a803a8 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -96,8 +96,8 @@ uint64_t csview_hash(const csview* x); | Type name | Type definition | Used to represent... | |:----------------|:-------------------------------------------|:-------------------------| | `csview` | `struct { const char *buf; intptr_t size; }` | The string view type | -| `csview_value` | `char` | The string element type | -| `csview_iter` | `struct { csview_value *ref; }` | UTF8 iterator | +| `csview_value` | `const char` | The string element type | +| `csview_iter` | `union { csview_value *ref; csview chr; }` | UTF8 iterator | ## Constants and macros -- cgit v1.2.3 From 18a0648d8a9f7dcaf3ce145d8d671679bd46d388 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sat, 19 Aug 2023 08:41:35 +0200 Subject: Improved cspan_next function. --- include/stc/cspan.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index f806ed8f..cca5486a 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -97,11 +97,9 @@ int demo2() { return it; \ } \ STC_INLINE void Self##_next(Self##_iter* it) { \ - static const struct { int8_t i, j, inc; } t[2] = {{RANK - 1, 0, -1}, {0, RANK - 1, 1}}; \ - const int order = (it->_s->stride.d[0] < it->_s->stride.d[RANK - 1]); /* 0='C', 1='F' */ \ - it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, t[order].i, t[order].inc); \ - if (it->pos[t[order].j] == it->_s->shape[t[order].j]) \ - it->ref = NULL; \ + int done; \ + it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, &done); \ + if (done) it->ref = NULL; \ } \ struct stc_nostruct @@ -225,16 +223,19 @@ STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t s return off; } -STC_INLINE intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc) { +STC_INLINE intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done) { + int i, inc; + if (stride[0] < stride[rank - 1]) i = rank - 1, inc = -1; else i = 0, inc = 1; intptr_t off = stride[i]; ++pos[i]; for (; --rank && pos[i] == shape[i]; i += inc) { pos[i] = 0; ++pos[i + inc]; off += stride[i + inc] - stride[i]*shape[i]; } + *done = pos[i] == shape[i]; return off; } -#define _cspan_next1(pos, shape, stride, rank, i, inc) (++pos[0], stride[0]) +#define _cspan_next1(pos, shape, stride, rank, done) (*done = ++pos[0]==shape[0], stride[0]) #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 -- cgit v1.2.3 From e51376c9b72448dad947c3cd3760ab013ca8e4a5 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sat, 19 Aug 2023 08:57:53 +0200 Subject: Moved cspan_next() to shared implementation (if chosen). --- include/stc/cspan.h | 26 ++++++++++++++------------ misc/examples/spans/matmult.c | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index cca5486a..b8b191f1 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -223,18 +223,7 @@ STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t s return off; } -STC_INLINE intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done) { - int i, inc; - if (stride[0] < stride[rank - 1]) i = rank - 1, inc = -1; else i = 0, inc = 1; - intptr_t off = stride[i]; - ++pos[i]; - for (; --rank && pos[i] == shape[i]; i += inc) { - pos[i] = 0; ++pos[i + inc]; - off += stride[i + inc] - stride[i]*shape[i]; - } - *done = pos[i] == shape[i]; - return off; -} +STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done); #define _cspan_next1(pos, shape, stride, rank, done) (*done = ++pos[0]==shape[0], stride[0]) #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 @@ -253,6 +242,19 @@ STC_API int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank); /* --------------------- IMPLEMENTATION --------------------- */ #if defined(i_implement) || defined(i_static) +STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done) { + int i, inc; + if (stride[0] < stride[rank - 1]) i = rank - 1, inc = -1; else i = 0, inc = 1; + intptr_t off = stride[i]; + ++pos[i]; + for (; --rank && pos[i] == shape[i]; i += inc) { + pos[i] = 0; ++pos[i + inc]; + off += stride[i + inc] - stride[i]*shape[i]; + } + *done = pos[i] == shape[i]; + return off; +} + STC_DEF int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank) { int32_t k = 1, i, j, inc, s1, s2; if (order == 'F') i = 0, j = rank, inc = 1; diff --git a/misc/examples/spans/matmult.c b/misc/examples/spans/matmult.c index b28e6459..35dad7a9 100644 --- a/misc/examples/spans/matmult.c +++ b/misc/examples/spans/matmult.c @@ -41,7 +41,7 @@ void recursive_matrix_product(Mat2 A, Mat2 B, OutMat C) if (C.shape[0] <= recursion_threshold || C.shape[1] <= recursion_threshold) { base_case_matrix_product(A, B, C); } else { - Partition c = partition(C), + Partition c = partition(C), a = partition(A), b = partition(B); recursive_matrix_product(a.m00, b.m00, c.m00); -- cgit v1.2.3 From ac7afe963527eb66a12962c638242f0426b39575 Mon Sep 17 00:00:00 2001 From: tylov Date: Sat, 19 Aug 2023 18:55:41 +0200 Subject: Polishing cspan.h. Updated multidim.c cspan example. --- docs/cstr_api.md | 6 ++-- include/stc/cspan.h | 19 +++++++---- misc/examples/spans/multidim.c | 75 ++++++++++++++++++++++-------------------- 3 files changed, 55 insertions(+), 45 deletions(-) diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 5f6ce9e4..397634ec 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -120,14 +120,14 @@ cstr_iter cstr_advance(cstr_iter it, intptr_t n); // utf8 functions requires linking with src/utf8code.c symbols: bool cstr_valid_utf8(const cstr* self); // check if str is valid utf8 -cstr cstr_casefold_sv(csview sv); // returns new casefolded utf8 cstr +cstr cstr_casefold_sv(csview sv); // returns new casefolded utf8 cstr cstr cstr_tolower(const char* str); // returns new lowercase utf8 cstr -cstr cstr_tolower_sv(csview sv); // returns new lowercase utf8 cstr +cstr cstr_tolower_sv(csview sv); // returns new lowercase utf8 cstr void cstr_lowercase(cstr* self); // transform cstr to lowercase utf8 cstr cstr_toupper(const char* str); // returns new uppercase utf8 cstr -cstr cstr_toupper_sv(csview sv); // returns new uppercase utf8 cstr +cstr cstr_toupper_sv(csview sv); // returns new uppercase utf8 cstr void cstr_uppercase(cstr* self); // transform cstr to uppercase utf8 int cstr_icmp(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison diff --git a/include/stc/cspan.h b/include/stc/cspan.h index b8b191f1..32921390 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -244,24 +244,29 @@ STC_API int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank); STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done) { int i, inc; - if (stride[0] < stride[rank - 1]) i = rank - 1, inc = -1; else i = 0, inc = 1; + if (stride[0] < stride[rank - 1]) i = rank - 1, inc = -1; + else /* order 'C' */ i = 0, inc = 1; + intptr_t off = stride[i]; ++pos[i]; - for (; --rank && pos[i] == shape[i]; i += inc) { + while (--rank && pos[i] == shape[i]) { pos[i] = 0; ++pos[i + inc]; off += stride[i + inc] - stride[i]*shape[i]; + i += inc; } *done = pos[i] == shape[i]; return off; } STC_DEF int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank) { - int32_t k = 1, i, j, inc, s1, s2; - if (order == 'F') i = 0, j = rank, inc = 1; - else /* 'C' */ i = rank - 1, j = -1, inc = -1; - s1 = shape[i]; shape[i] = 1; + int i, inc; + if (order == 'F') i = 0, inc = 1; + else i = rank - 1, inc = -1; + int32_t k = 1, s1 = shape[i], s2; - for (i += inc; i != j; i += inc) { + shape[i] = 1; + while (--rank) { + i += inc; s2 = shape[i]; shape[i] = (k *= s1); s1 = s2; diff --git a/misc/examples/spans/multidim.c b/misc/examples/spans/multidim.c index 798a1126..ebc05a70 100644 --- a/misc/examples/spans/multidim.c +++ b/misc/examples/spans/multidim.c @@ -1,66 +1,71 @@ // Example based on https://en.cppreference.com/w/cpp/container/mdspan #define i_val int #include +#define i_implement #include #include using_cspan3(ispan, int); +void print2d(ispan2 ms2) { + for (int i=0; i < ms2.shape[0]; i++) { + for (int j=0; j < ms2.shape[1]; j++) + printf(" %3d", *cspan_at(&ms2, i, j)); + puts(""); + } +} + +void print3d(ispan3 ms3) { + for (int i=0; i < ms3.shape[0]; i++) { + for (int j=0; j < ms3.shape[1]; j++) { + for (int k=0; k < ms3.shape[2]; k++) + printf(" %3d", *cspan_at(&ms3, i, j, k)); + puts(""); + } + puts(""); + } +} + int main(void) { cstack_int v = c_init(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}); - // View data as contiguous memory representing 24 ints + // Create 1d span from a compatibel container ispan ms1 = cspan_from(&v); - // View the same data as a 3D array 2 x 3 x 4 + // Create a 3D mdspan 2 x 3 x 4 ispan3 ms3 = cspan_md(v.data, 2, 3, 4); puts("ms3:"); - for (int i=0; i != ms3.shape[0]; i++) { - for (int j=0; j != ms3.shape[1]; j++) { - for (int k=0; k != ms3.shape[2]; k++) { - printf(" %2d", *cspan_at(&ms3, i, j, k)); - } - puts(""); - } - puts(""); - } - puts("ss3 = ms3[:, 1:3, 1:3]"); - ispan3 ss3 = ms3; - ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3}); + print3d(ms3); - for (int i=0; i != ss3.shape[0]; i++) { - for (int j=0; j != ss3.shape[1]; j++) { - for (int k=0; k != ss3.shape[2]; k++) { - printf(" %2d", *cspan_at(&ss3, i, j, k)); - } - puts(""); - } - puts(""); - } + // Take a slice of md3 + ispan3 ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3}); + puts("ss3 = ms3[:, 1:3, 1:3]"); + print3d(ss3); puts("Iterate ss3 flat:"); - c_foreach (i, ispan3, ss3) - printf(" %d", *i.ref); + c_foreach (i, ispan3, ss3) printf(" %d", *i.ref); puts(""); - ispan2 ms2 = cspan_submd3(&ms3, 0); + // submd3 span reduces rank depending on number of arguments + ispan2 ms2 = cspan_submd3(&ms3, 1); - // write data using 2D view + // Change data on the 2d subspan for (int i=0; i != ms2.shape[0]; i++) for (int j=0; j != ms2.shape[1]; j++) - *cspan_at(&ms2, i, j) = i*1000 + j; + *cspan_at(&ms2, i, j) = (i + 1)*100 + j; + + puts("\nms2 = ms3[1] with updated data:"); + print2d(ms2); + puts(""); - puts("\nview data as 1D view:"); - for (int i=0; i != cspan_size(&ms1); i++) - printf(" %d", *cspan_at(&ms1, i)); + puts("\nOriginal s1 span with updated data:"); + c_foreach (i, ispan, ms1) printf(" %d", *i.ref); puts(""); - puts("iterate subspan ms3[1]:"); - ispan2 sub = cspan_submd3(&ms3, 1); - c_foreach (i, ispan2, sub) - printf(" %d", *i.ref); + puts("\nOriginal ms3 span with updated data:"); + print3d(ms3); puts(""); cstack_int_drop(&v); -- cgit v1.2.3 From 7ae6e4d155e9c4835d2dbf80f6e27873b7c7439a Mon Sep 17 00:00:00 2001 From: tylov Date: Sat, 19 Aug 2023 21:46:52 +0200 Subject: Optimized cspan_next(): awesome speedup on gcc. --- include/stc/cspan.h | 15 ++++++--------- misc/benchmarks/various/cspan_bench.c | 5 ++--- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 32921390..6f8de8ec 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -97,8 +97,9 @@ int demo2() { return it; \ } \ STC_INLINE void Self##_next(Self##_iter* it) { \ - int done; \ - it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, &done); \ + int i, inc, done; \ + if (it->_s->stride.d[0] < it->_s->stride.d[RANK - 1]) i=0, inc=1; else i=RANK-1, inc=-1; \ + it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, i, inc, &done); \ if (done) it->ref = NULL; \ } \ struct stc_nostruct @@ -223,8 +224,8 @@ STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t s return off; } -STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done); -#define _cspan_next1(pos, shape, stride, rank, done) (*done = ++pos[0]==shape[0], stride[0]) +STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc, int* done); +#define _cspan_next1(pos, shape, stride, rank, i, inc, done) (*done = ++pos[0]==shape[0], stride[0]) #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 @@ -242,11 +243,7 @@ STC_API int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank); /* --------------------- IMPLEMENTATION --------------------- */ #if defined(i_implement) || defined(i_static) -STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done) { - int i, inc; - if (stride[0] < stride[rank - 1]) i = rank - 1, inc = -1; - else /* order 'C' */ i = 0, inc = 1; - +STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc, int* done) { intptr_t off = stride[i]; ++pos[i]; while (--rank && pos[i] == shape[i]) { diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c index f4b067f8..b5caca83 100644 --- a/misc/benchmarks/various/cspan_bench.c +++ b/misc/benchmarks/various/cspan_bench.c @@ -49,9 +49,8 @@ static void TraditionalForLoop(intptr_t n) for (int x = lx; x < hx; ++x) { for (int y = ly; y < hy; ++y) { for (int z = lz; z < hz; ++z) { - int i = nz*(ny*x + y) + z; - double d = Vin[i]; - Vout[i] += d; + double d = Vin[nz*(ny*x + y) + z]; + Vout[nz*(ny*x + y) + z] += d; sum += d; } } -- cgit v1.2.3 From 7cf924a174a509bee2162169adc5c82d011c7116 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Mon, 21 Aug 2023 08:58:24 +0200 Subject: Added kokkos submdspan example (did not make it to c++23). --- misc/examples/spans/submdspan.c | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 misc/examples/spans/submdspan.c diff --git a/misc/examples/spans/submdspan.c b/misc/examples/spans/submdspan.c new file mode 100644 index 00000000..fa0d5762 --- /dev/null +++ b/misc/examples/spans/submdspan.c @@ -0,0 +1,44 @@ +// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2630r0.html +// C99: +#include +#include + +using_cspan3(span, double); // define span, span2, span3 + +// Set all elements of a rank-2 mdspan to zero. +void zero_2d(span2 grid2d) { + c_static_assert(cspan_rank(&grid2d) == 2); + for (int i = 0; i < grid2d.shape[0]; ++i) { + for (int j = 0; j < grid2d.shape[1]; ++j) { + *cspan_at(&grid2d, i,j) = 0; + } + } +} + +void zero_surface(span3 grid3d) { + c_static_assert(cspan_rank(&grid3d) == 3); + zero_2d(cspan_slice(span2, &grid3d, {0}, {c_ALL}, {c_ALL})); + zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {0}, {c_ALL})); + zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {c_ALL}, {0})); + zero_2d(cspan_slice(span2, &grid3d, {grid3d.shape[0]-1}, {c_ALL}, {c_ALL})); + zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {grid3d.shape[1]-1}, {c_ALL})); + zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {c_ALL}, {grid3d.shape[2]-1})); +} + +int main() { + double arr[3*4*5]; + for (int i=0; i Date: Mon, 21 Aug 2023 18:26:59 +0200 Subject: Some cleanups. --- include/stc/forward.h | 20 ++++++++-------- misc/benchmarks/various/cspan_bench.c | 43 ++++++++--------------------------- misc/examples/spans/submdspan.c | 8 +++---- 3 files changed, 24 insertions(+), 47 deletions(-) diff --git a/include/stc/forward.h b/include/stc/forward.h index 2372a618..2fbff034 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -41,13 +41,13 @@ // csview : non-null terminated string view typedef const char csview_value; -typedef struct csview { - csview_value* buf; +typedef struct csview { + csview_value* buf; intptr_t size; } csview; -typedef union { - csview_value* ref; +typedef union { + csview_value* ref; csview chr; struct { csview chr; csview_value* end; } u8; } csview_iter; @@ -55,13 +55,13 @@ typedef union { // crawstr : null-terminated string view typedef csview_value crawstr_value; -typedef struct crawstr { - crawstr_value* str; +typedef struct crawstr { + crawstr_value* str; intptr_t size; } crawstr; -typedef union { - crawstr_value* ref; +typedef union { + crawstr_value* ref; csview chr; struct { csview chr; } u8; // [deprecated] } crawstr_iter; @@ -75,8 +75,8 @@ typedef union cstr { struct { cstr_value* data; size_t size, ncap; } lon; } cstr; -typedef union { - cstr_value* ref; +typedef union { + cstr_value* ref; csview chr; struct { csview chr; } u8; // [deprecated] } cstr_iter; diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c index b5caca83..3b1c3132 100644 --- a/misc/benchmarks/various/cspan_bench.c +++ b/misc/benchmarks/various/cspan_bench.c @@ -1,3 +1,4 @@ +// ref: https://stackoverflow.com/questions/74382366/why-is-iterating-over-stdrangesviewsjoin-so-slow #define NDEBUG #include #include @@ -11,6 +12,7 @@ enum { ny = 64, nz = 64 }; +// subspan 15x5x10: int lx = 15, ly = 10, lz = 5; int hx = 30, hy = 15, hz = 15; @@ -20,27 +22,7 @@ double Vin[nx * ny * nz]; //, 1.23; // define some slice indices for each dimension -static void MDRanges_setup(intptr_t n) -{ - double sum = 0; - clock_t t = clock(); - - for (intptr_t s = 0; s < n; ++s) - { - MD3 r_in = cspan_md(Vin, nx, ny, nz); - MD3 r_out = cspan_md(Vout, nx, ny, nz); - - r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); - r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); - MD3_iter i = MD3_begin(&r_in); // can be iterated "flat". - MD3_iter o = MD3_begin(&r_out); - sum += Vin[s % nx]; - } - t = clock() - t; - printf("setup: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); -} - -static void TraditionalForLoop(intptr_t n) +static void Traditional_for_loop(intptr_t n) { clock_t t = clock(); double sum = 0; @@ -57,7 +39,7 @@ static void TraditionalForLoop(intptr_t n) } } t = clock() - t; - printf("forloop: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); + printf("forloop : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); } static void MDRanges_nested_loop(intptr_t n) @@ -67,8 +49,6 @@ static void MDRanges_nested_loop(intptr_t n) MD3 r_out = cspan_md(Vout, nx, ny, nz); r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); - - // C++23: for (auto [o, i] : std::views::zip(flat(r_out), flat(r_in))) { o = i; } double sum = 0; for (intptr_t s = 0; s < n; ++s) { @@ -76,27 +56,25 @@ static void MDRanges_nested_loop(intptr_t n) for (int y = 0; y < r_in.shape[1]; ++y) { for (int z = 0; z < r_in.shape[2]; ++z) { - double d = *cspan_at(&r_in, x, y, z); - *cspan_at(&r_out, x, y, z) += d; + double d = *cspan_at(&r_in, x,y,z); + *cspan_at(&r_out, x,y,z) += d; sum += d; } } } } t = clock() - t; - printf("nested: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); + printf("nested : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); } static void MDRanges_loop_over_joined(intptr_t n) { + clock_t t = clock(); MD3 r_in = cspan_md(Vin, nx, ny, nz); MD3 r_out = cspan_md(Vout, nx, ny, nz); r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); - - // C++23: for (auto [o, i] : std::views::zip(flat(r_out), flat(r_in))) { o = i; } double sum = 0; - clock_t t = clock(); for (intptr_t s = 0; s < n; ++s) { MD3_iter i = MD3_begin(&r_in); @@ -109,7 +87,7 @@ static void MDRanges_loop_over_joined(intptr_t n) } } t = clock() - t; - printf("joined: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); + printf("joined : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); } int main(void) @@ -118,8 +96,7 @@ int main(void) for (int i = 0; i < nx * ny * nz; ++i) Vin[i] = i + 1.23; - MDRanges_setup(n); - TraditionalForLoop(n); + Traditional_for_loop(n); MDRanges_nested_loop(n); MDRanges_loop_over_joined(n); } diff --git a/misc/examples/spans/submdspan.c b/misc/examples/spans/submdspan.c index fa0d5762..0752dfa1 100644 --- a/misc/examples/spans/submdspan.c +++ b/misc/examples/spans/submdspan.c @@ -3,11 +3,11 @@ #include #include -using_cspan3(span, double); // define span, span2, span3 +using_cspan3(span, double); // shorthand for defining span, span2, span3 // Set all elements of a rank-2 mdspan to zero. void zero_2d(span2 grid2d) { - c_static_assert(cspan_rank(&grid2d) == 2); + (void)c_static_assert(cspan_rank(&grid2d) == 2); for (int i = 0; i < grid2d.shape[0]; ++i) { for (int j = 0; j < grid2d.shape[1]; ++j) { *cspan_at(&grid2d, i,j) = 0; @@ -16,7 +16,7 @@ void zero_2d(span2 grid2d) { } void zero_surface(span3 grid3d) { - c_static_assert(cspan_rank(&grid3d) == 3); + (void)c_static_assert(cspan_rank(&grid3d) == 3); zero_2d(cspan_slice(span2, &grid3d, {0}, {c_ALL}, {c_ALL})); zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {0}, {c_ALL})); zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {c_ALL}, {0})); @@ -41,4 +41,4 @@ int main() { } puts(""); } -} \ No newline at end of file +} -- cgit v1.2.3 From 2d33308d36063f3726f3652b0b0cbe3668b8bc68 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 21 Aug 2023 18:31:49 +0200 Subject: Changed 'order' to 'layout' in cspan md. Neigher the 'C' / 'F' convension from python, nor left / right from std::mdspan are great names => changed to c_ROWMAJOR / c_COLMAJOR like in matlab. --- docs/cspan_api.md | 18 +++++++++++------- include/stc/cspan.h | 23 ++++++++++++++--------- misc/examples/spans/matmult.c | 4 ++-- misc/examples/spans/mdspan.c | 2 +- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 39b97473..c3556dc3 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -44,12 +44,15 @@ SpanTypeN_iter SpanType_begin(const SpanTypeN* self); SpanTypeN_iter SpanType_end(const SpanTypeN* self); void SpanType_next(SpanTypeN_iter* it); -SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // make a multi-dim cspan, row-major order. -SpanTypeN cspan_md_order(char order, ValueType* data, d1, d2, ...); // order='C': row-major, 'F': column-major (FORTRAN). + // make a multi-dim cspan +SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // row-major +SpanTypeN cspan_md_layout(cspan_layout layout, ValueType* data, d1, d2, ...); - // transpose a md span (inverse axes). No changes to the underlying array. + // transpose a md span. Inverses layout and axes only. void cspan_transpose(const SpanTypeN* self); -bool cspan_is_order_F(const SpanTypeN* self); +cspan_layout cspan_get_layout(const SpanTypeN* self); +bool cspan_is_rowmajor(const SpanTypeN* self); +bool cspan_is_colmajor(const SpanTypeN* self); // create a subspan of input span rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); SpanType cspan_subspan(const SpanType* span, intptr_t offset, intptr_t count); @@ -70,8 +73,9 @@ OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeM* parent, {x0,x1}, {y0 |:------------------|:----------------------------------------------------|:---------------------| | SpanTypeN | `struct { ValueType *data; uint32_t shape[N]; .. }` | SpanType with rank N | | SpanTypeN`_value` | `ValueType` | The ValueType | -| `c_ALL` | Use with `cspan_slice()`. | Full extent | -| `c_END` | " | End of extent | +| `c_ALL` | `cspan_slice(&md, {1,3}, {c_ALL})` | Full extent | +| `c_END` | `cspan_slice(&md, {1,c_END}, {2,c_END})` | End of extent | +| `cspan_layout` | `enum { c_ROWMAJOR, c_COLMAJOR }` | Multi-dim layout | ## Example 1 @@ -182,7 +186,7 @@ void print_span(myspan2 ms) { int main(void) { int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; - myspan3 ms3 = cspan_md_order('C', arr, 2, 3, 4); // row-major ('F' column-major) + myspan3 ms3 = cspan_md(arr, 2, 3, 4); // row-major layout myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {0,3}, {2,c_END}); myspan2 a = cspan_submd3(&ss3, 1); myspan2 b = a; diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 6f8de8ec..f9f3b02a 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -98,7 +98,7 @@ int demo2() { } \ STC_INLINE void Self##_next(Self##_iter* it) { \ int i, inc, done; \ - if (it->_s->stride.d[0] < it->_s->stride.d[RANK - 1]) i=0, inc=1; else i=RANK-1, inc=-1; \ + if (cspan_is_colmajor(it->_s)) i=0, inc=1; else i=RANK-1, inc=-1; \ it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, i, inc, &done); \ if (done) it->ref = NULL; \ } \ @@ -115,6 +115,7 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define c_END -1 #define c_ALL 0,c_END +typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout; /* Use cspan_init() for static initialization only. c_init() for non-static init. */ #define cspan_init(SpanType, ...) \ @@ -132,7 +133,9 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) #define cspan_rank(self) c_arraylen((self)->shape) -#define cspan_is_order_F(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) +#define cspan_is_colmajor(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) +#define cspan_is_rowmajor(self) (!cspan_is_colmajor(self)) +#define cspan_get_layout(self) (cspan_is_colmajor(self) ? c_COLMAJOR : c_ROWMAJOR) #define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) #define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__)) #define cspan_front(self) ((self)->data) @@ -165,10 +168,10 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define cspan_submd4_4(self, x, y, z) \ {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}, .stride=(cspan_tuple1){.d={(self)->stride.d[3]}}} -#define cspan_md(array, ...) cspan_md_order('C', array, __VA_ARGS__) -#define cspan_md_order(order, array, ...) /* order='C' or 'F' */ \ +#define cspan_md(array, ...) cspan_md_layout(c_ROWMAJOR, array, __VA_ARGS__) +#define cspan_md_layout(layout, array, ...) \ {.data=array, .shape={__VA_ARGS__}, \ - .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(order, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} + .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(layout, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} #define cspan_transpose(self) \ _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self)) @@ -225,7 +228,7 @@ STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t s } STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc, int* done); -#define _cspan_next1(pos, shape, stride, rank, i, inc, done) (*done = ++pos[0]==shape[0], stride[0]) +#define _cspan_next1(pos, shape, stride, rank, i, inc, done) (*done = ++pos[0]==shape[0], (void)(i|inc), stride[0]) #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 @@ -237,7 +240,7 @@ STC_API intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, const int32_t shape[], const int32_t stride[], int rank, const int32_t a[][2]); -STC_API int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank); +STC_API int32_t* _cspan_shape2stride(cspan_layout layout, int32_t shape[], int rank); #endif // STC_CSPAN_H_INCLUDED /* --------------------- IMPLEMENTATION --------------------- */ @@ -246,6 +249,7 @@ STC_API int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank); STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc, int* done) { intptr_t off = stride[i]; ++pos[i]; + while (--rank && pos[i] == shape[i]) { pos[i] = 0; ++pos[i + inc]; off += stride[i + inc] - stride[i]*shape[i]; @@ -255,9 +259,9 @@ STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_ return off; } -STC_DEF int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank) { +STC_DEF int32_t* _cspan_shape2stride(cspan_layout layout, int32_t shape[], int rank) { int i, inc; - if (order == 'F') i = 0, inc = 1; + if (layout == c_COLMAJOR) i = 0, inc = 1; else i = rank - 1, inc = -1; int32_t k = 1, s1 = shape[i], s2; @@ -277,6 +281,7 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, intptr_t off = 0; int i = 0, oi = 0; int32_t end; + for (; i < rank; ++i) { off += stride[i]*a[i][0]; switch (a[i][1]) { diff --git a/misc/examples/spans/matmult.c b/misc/examples/spans/matmult.c index 35dad7a9..266fa121 100644 --- a/misc/examples/spans/matmult.c +++ b/misc/examples/spans/matmult.c @@ -70,8 +70,8 @@ int main(void) Values_push(&values, (crandf() - 0.5)*4.0); double out[D1*D2]; - Mat3 data = cspan_md_order('C', values.data, N, D1, D2); - OutMat c = cspan_md_order('C', out, D1, D2); + Mat3 data = cspan_md_layout(c_ROWMAJOR, values.data, N, D1, D2); + OutMat c = cspan_md_layout(c_ROWMAJOR, out, D1, D2); Mat2 a = cspan_submd3(&data, 0); double sum = 0.0; clock_t t = clock(); diff --git a/misc/examples/spans/mdspan.c b/misc/examples/spans/mdspan.c index db601850..630ffddb 100644 --- a/misc/examples/spans/mdspan.c +++ b/misc/examples/spans/mdspan.c @@ -9,7 +9,7 @@ int main(void) { double* data = c_new_n(double, nx*ny*nz); printf("\nMultidim span ms[5, 4, 3], fortran ordered"); - DSpan3 ms = cspan_md_order('F', data, nx, ny, nz); // Fortran, not 'C' + DSpan3 ms = cspan_md_layout(c_COLMAJOR, data, nx, ny, nz); int idx = 0; for (int i = 0; i < ms.shape[0]; ++i) -- cgit v1.2.3 From 8dc7500322d6109e856fa64b1a121078b86635f1 Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 21 Aug 2023 21:31:22 +0200 Subject: cspan flat-iterator now prints c_COLMAJOR matrices as in Python. Simpler code, although it now doesn't print column-major spans in column-by-column order, but rather in row-by-row, like row-major spans. --- docs/cspan_api.md | 2 -- include/stc/cspan.h | 24 +++++++++++------------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/docs/cspan_api.md b/docs/cspan_api.md index c3556dc3..0f345a7e 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -147,7 +147,6 @@ if __name__ == '__main__': for i in a.flat: print(" {}".format(i), end='') print('') - # prints row-wise for i in b.flat: print(" {}".format(i), end='') ''' 13 14 15 16 @@ -198,7 +197,6 @@ int main(void) { c_foreach (i, myspan2, a) printf(" %d", *i.ref); puts(""); - // prints in storage order, same as a. c_foreach (i, myspan2, b) printf(" %d", *i.ref); } ``` diff --git a/include/stc/cspan.h b/include/stc/cspan.h index f9f3b02a..8a422dad 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -97,9 +97,8 @@ int demo2() { return it; \ } \ STC_INLINE void Self##_next(Self##_iter* it) { \ - int i, inc, done; \ - if (cspan_is_colmajor(it->_s)) i=0, inc=1; else i=RANK-1, inc=-1; \ - it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, i, inc, &done); \ + int done; \ + it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, &done); \ if (done) it->ref = NULL; \ } \ struct stc_nostruct @@ -227,8 +226,8 @@ STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t s return off; } -STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc, int* done); -#define _cspan_next1(pos, shape, stride, rank, i, inc, done) (*done = ++pos[0]==shape[0], (void)(i|inc), stride[0]) +STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done); +#define _cspan_next1(pos, shape, stride, rank, done) (*done = ++pos[0]==shape[0], stride[0]) #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 @@ -246,16 +245,15 @@ STC_API int32_t* _cspan_shape2stride(cspan_layout layout, int32_t shape[], int r /* --------------------- IMPLEMENTATION --------------------- */ #if defined(i_implement) || defined(i_static) -STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc, int* done) { - intptr_t off = stride[i]; - ++pos[i]; +STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int r, int* done) { + intptr_t off = stride[--r]; + ++pos[r]; - while (--rank && pos[i] == shape[i]) { - pos[i] = 0; ++pos[i + inc]; - off += stride[i + inc] - stride[i]*shape[i]; - i += inc; + for (; r && pos[r] == shape[r]; --r) { + pos[r] = 0; ++pos[r - 1]; + off += stride[r - 1] - stride[r]*shape[r]; } - *done = pos[i] == shape[i]; + *done = pos[r] == shape[r]; return off; } -- cgit v1.2.3 From 775e507b301621ce4e608efe1d23f52abe0f1aab Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 21 Aug 2023 23:21:30 +0200 Subject: Small change of policy for i_eq: don't use two i_less functions to derive i_eq, only from i_cmp directly, or use native ==. --- include/stc/priv/template.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 65dee203..38097a35 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -209,7 +209,7 @@ #endif // i_eq, i_less, i_cmp -#if !defined i_eq && (defined i_cmp || defined i_less) +#if !defined i_eq && defined i_cmp #define i_eq(x, y) !(i_cmp(x, y)) #elif !defined i_eq #define i_eq(x, y) *x == *y -- cgit v1.2.3 From 5f56f59c6ea7a731efd4eefc1211352f40a8b33f Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Tue, 22 Aug 2023 10:43:22 +0200 Subject: Added c_forint and c_for macros as additions to c_forrange. --- include/stc/ccommon.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 5c5e87e6..70e225f0 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -198,13 +198,15 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { ; _.it.ref && (_.key = &_.it.ref->first, _.val = &_.it.ref->second) \ ; C##_next(&_.it)) -#define c_forrange(...) c_MACRO_OVERLOAD(c_forrange, __VA_ARGS__) -#define c_forrange_1(stop) c_forrange_3(_c_i, 0, stop) -#define c_forrange_2(i, stop) c_forrange_3(i, 0, stop) -#define c_forrange_3(i, start, stop) \ - for (_llong i=start, _end=(_llong)(stop); i < _end; ++i) -#define c_forrange_4(i, start, stop, step) \ - for (_llong i=start, _inc=step, _end=(_llong)(stop) - (_inc > 0) \ +#define c_forint(...) c_for(int, __VA_ARGS__) +#define c_forrange(...) c_for(_llong, __VA_ARGS__) +#define c_for(...) c_MACRO_OVERLOAD(c_for, __VA_ARGS__) +#define c_for_2(T, stop) c_for_4(T, _c_i, 0, stop) +#define c_for_3(T, i, stop) c_for_4(T, i, 0, stop) +#define c_for_4(T, i, start, stop) \ + for (T i=start, _end=stop; i < _end; ++i) +#define c_for_5(T, i, start, stop, step) \ + for (T i=start, _inc=step, _end=(T)(stop) - (_inc > 0) \ ; (_inc > 0) ^ (i > _end); i += _inc) #ifndef __cplusplus -- cgit v1.2.3 From 31cdd30a4ed87087bf19f14f4a643e39735a1420 Mon Sep 17 00:00:00 2001 From: tylov Date: Wed, 23 Aug 2023 00:24:43 +0200 Subject: Removed the last committed c_forint macro. --- include/stc/ccommon.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 70e225f0..6e90f75a 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -198,8 +198,7 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { ; _.it.ref && (_.key = &_.it.ref->first, _.val = &_.it.ref->second) \ ; C##_next(&_.it)) -#define c_forint(...) c_for(int, __VA_ARGS__) -#define c_forrange(...) c_for(_llong, __VA_ARGS__) +#define c_forrange(...) c_for(long long, __VA_ARGS__) #define c_for(...) c_MACRO_OVERLOAD(c_for, __VA_ARGS__) #define c_for_2(T, stop) c_for_4(T, _c_i, 0, stop) #define c_for_3(T, i, stop) c_for_4(T, i, 0, stop) -- cgit v1.2.3 From 263dbab626e6a99f7959a4c1716f0496906ee638 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Wed, 30 Aug 2023 08:24:54 +0200 Subject: Some simplifications. Added i_ndebug macro flag to disable assertions in cspan. --- include/stc/ccommon.h | 6 ++---- include/stc/cspan.h | 42 +++++++++++++++--------------------------- misc/examples/spans/multidim.c | 4 ++++ 3 files changed, 21 insertions(+), 31 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 6e90f75a..ad92212a 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -69,16 +69,14 @@ typedef long long _llong; #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T))) #define c_LITERAL(T) (T) #endif -#define c_new_n(T, n) ((T*)malloc(sizeof(T)*(size_t)(n))) +#define c_new_n(T, n) ((T*)malloc(sizeof(T)*c_i2u(n))) #define c_malloc(sz) malloc(c_i2u(sz)) #define c_calloc(n, sz) calloc(c_i2u(n), c_i2u(sz)) #define c_realloc(p, sz) realloc(p, c_i2u(sz)) #define c_free(p) free(p) #define c_delete(T, ptr) do { T *_tp = ptr; T##_drop(_tp); free(_tp); } while (0) -#define c_static_assert(...) c_MACRO_OVERLOAD(c_static_assert, __VA_ARGS__) -#define c_static_assert_1(b) ((int)(0*sizeof(int[(b) ? 1 : -1]))) -#define c_static_assert_2(b, m) c_static_assert_1(b) +#define c_static_assert(expr) (1 ? 0 : (int)sizeof(int[(expr) ? 1 : -1])) #if defined STC_NDEBUG || defined NDEBUG #define c_assert(expr) ((void)0) #else diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 8a422dad..3f2b300f 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -63,6 +63,12 @@ int demo2() { #include "priv/linkage.h" #include "ccommon.h" +#ifdef i_ndebug + #define cspan_assert(x) ((void)0) +#else + #define cspan_assert(x) c_assert(x) +#endif + #define using_cspan(...) c_MACRO_OVERLOAD(using_cspan, __VA_ARGS__) #define using_cspan_2(Self, T) \ using_cspan_3(Self, T, 1); \ @@ -85,7 +91,7 @@ int demo2() { const int rank, const int32_t a[][2]) { \ Self s; int outrank; \ s.data = d + _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ - c_assert(outrank == RANK); \ + cspan_assert(outrank == RANK); \ return s; \ } \ STC_INLINE Self##_iter Self##_begin(const Self* self) { \ @@ -135,10 +141,12 @@ typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout; #define cspan_is_colmajor(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) #define cspan_is_rowmajor(self) (!cspan_is_colmajor(self)) #define cspan_get_layout(self) (cspan_is_colmajor(self) ? c_COLMAJOR : c_ROWMAJOR) -#define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) #define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__)) #define cspan_front(self) ((self)->data) #define cspan_back(self) ((self)->data + cspan_size(self) - 1) +#define cspan_index(self, ...) \ + (_cspan_index(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \ + c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general // cspan_subspanX: (X <= 3) optimized. Similar to cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); #define cspan_subspan(self, offset, count) \ @@ -183,17 +191,6 @@ typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout; /* ------------------- PRIVAT DEFINITIONS ------------------- */ -// cspan_index() helpers: -#define cspan_idx_1 cspan_idx_3 -#define cspan_idx_2 cspan_idx_3 -#define cspan_idx_3(self, ...) \ - c_PASTE(_cspan_idx, c_NUMARGS(__VA_ARGS__))((self)->shape, (self)->stride, __VA_ARGS__) // small/fast -#define cspan_idx_4(self, ...) \ - (_cspan_idxN(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \ - c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general -#define cspan_idx_5 cspan_idx_4 -#define cspan_idx_6 cspan_idx_4 - STC_INLINE intptr_t _cspan_size(const int32_t shape[], int rank) { intptr_t sz = shape[0]; while (--rank > 0) sz *= shape[rank]; @@ -207,20 +204,10 @@ STC_INLINE void _cspan_transpose(int32_t shape[], int32_t stride[], int rank) { } } -STC_INLINE intptr_t _cspan_idx1(const int32_t shape[1], const cspan_tuple1 stri, int32_t x) - { c_assert(c_LTu(x, shape[0])); return (intptr_t)stri.d[0]*x; } - -STC_INLINE intptr_t _cspan_idx2(const int32_t shape[2], const cspan_tuple2 stri, int32_t x, int32_t y) - { c_assert(c_LTu(x, shape[0]) && c_LTu(y, shape[1])); return (intptr_t)stri.d[0]*x + stri.d[1]*y; } - -STC_INLINE intptr_t _cspan_idx3(const int32_t shape[3], const cspan_tuple3 stri, int32_t x, int32_t y, int32_t z) { - c_assert(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2])); - return (intptr_t)stri.d[0]*x + stri.d[1]*y + stri.d[2]*z; -} -STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stride[], const int32_t a[]) { +STC_INLINE intptr_t _cspan_index(int rank, const int32_t shape[], const int32_t stride[], const int32_t a[]) { intptr_t off = 0; while (rank--) { - c_assert(c_LTu(a[rank], shape[rank])); + cspan_assert(c_LTu(a[rank], shape[rank])); off += stride[rank]*a[rank]; } return off; @@ -283,13 +270,13 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, for (; i < rank; ++i) { off += stride[i]*a[i][0]; switch (a[i][1]) { - case 0: c_assert(c_LTu(a[i][0], shape[i])); continue; + case 0: cspan_assert(c_LTu(a[i][0], shape[i])); continue; case -1: end = shape[i]; break; default: end = a[i][1]; } oshape[oi] = end - a[i][0]; ostride[oi] = stride[i]; - c_assert(c_LTu(0, oshape[oi]) & !c_LTu(shape[i], end)); + cspan_assert(c_LTu(0, oshape[oi]) & !c_LTu(shape[i], end)); ++oi; } *orank = oi; @@ -297,6 +284,7 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, } #endif +#undef i_ndebug #undef i_opt #undef i_header #undef i_implement diff --git a/misc/examples/spans/multidim.c b/misc/examples/spans/multidim.c index ebc05a70..70fda7e2 100644 --- a/misc/examples/spans/multidim.c +++ b/misc/examples/spans/multidim.c @@ -66,6 +66,10 @@ int main(void) puts("\nOriginal ms3 span with updated data:"); print3d(ms3); + + puts("col = ms3[1, :, 2]"); + ispan col = cspan_slice(ispan, &ms3, {1}, {c_ALL}, {2}); + c_foreach (i, ispan, col) printf(" %d", *i.ref); puts(""); cstack_int_drop(&v); -- cgit v1.2.3 From 80cd2adc2cd008aeee9f799f2dd5042f42b4ec82 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 30 Aug 2023 17:16:03 +0200 Subject: Smaller updates. --- include/stc/cspan.h | 20 ++++++---------- misc/benchmarks/various/cspan_bench.c | 43 ++++++++++++++++++----------------- misc/examples/spans/matmult.c | 22 +++++++++--------- src/libstc.c | 5 ++-- 4 files changed, 42 insertions(+), 48 deletions(-) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 3f2b300f..e72bb97a 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -63,12 +63,6 @@ int demo2() { #include "priv/linkage.h" #include "ccommon.h" -#ifdef i_ndebug - #define cspan_assert(x) ((void)0) -#else - #define cspan_assert(x) c_assert(x) -#endif - #define using_cspan(...) c_MACRO_OVERLOAD(using_cspan, __VA_ARGS__) #define using_cspan_2(Self, T) \ using_cspan_3(Self, T, 1); \ @@ -91,7 +85,7 @@ int demo2() { const int rank, const int32_t a[][2]) { \ Self s; int outrank; \ s.data = d + _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ - cspan_assert(outrank == RANK); \ + c_assert(outrank == RANK); \ return s; \ } \ STC_INLINE Self##_iter Self##_begin(const Self* self) { \ @@ -193,7 +187,7 @@ typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout; STC_INLINE intptr_t _cspan_size(const int32_t shape[], int rank) { intptr_t sz = shape[0]; - while (--rank > 0) sz *= shape[rank]; + while (--rank) sz *= shape[rank]; return sz; } @@ -207,14 +201,15 @@ STC_INLINE void _cspan_transpose(int32_t shape[], int32_t stride[], int rank) { STC_INLINE intptr_t _cspan_index(int rank, const int32_t shape[], const int32_t stride[], const int32_t a[]) { intptr_t off = 0; while (rank--) { - cspan_assert(c_LTu(a[rank], shape[rank])); + c_assert(c_LTu(a[rank], shape[rank])); off += stride[rank]*a[rank]; } return off; } -STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done); #define _cspan_next1(pos, shape, stride, rank, done) (*done = ++pos[0]==shape[0], stride[0]) +STC_API intptr_t + _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done); #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 @@ -270,13 +265,13 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, for (; i < rank; ++i) { off += stride[i]*a[i][0]; switch (a[i][1]) { - case 0: cspan_assert(c_LTu(a[i][0], shape[i])); continue; + case 0: c_assert(c_LTu(a[i][0], shape[i])); continue; case -1: end = shape[i]; break; default: end = a[i][1]; } oshape[oi] = end - a[i][0]; ostride[oi] = stride[i]; - cspan_assert(c_LTu(0, oshape[oi]) & !c_LTu(shape[i], end)); + c_assert((oshape[oi] > 0) & !c_LTu(shape[i], end)); ++oi; } *orank = oi; @@ -284,7 +279,6 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, } #endif -#undef i_ndebug #undef i_opt #undef i_header #undef i_implement diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c index 3b1c3132..bfc0ead3 100644 --- a/misc/benchmarks/various/cspan_bench.c +++ b/misc/benchmarks/various/cspan_bench.c @@ -42,7 +42,7 @@ static void Traditional_for_loop(intptr_t n) printf("forloop : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); } -static void MDRanges_nested_loop(intptr_t n) +static void MDRanges_loop_over_joined(intptr_t n) { clock_t t = clock(); MD3 r_in = cspan_md(Vin, nx, ny, nz); @@ -52,22 +52,20 @@ static void MDRanges_nested_loop(intptr_t n) double sum = 0; for (intptr_t s = 0; s < n; ++s) { - for (int x = 0; x < r_in.shape[0]; ++x) { - for (int y = 0; y < r_in.shape[1]; ++y) { - for (int z = 0; z < r_in.shape[2]; ++z) - { - double d = *cspan_at(&r_in, x,y,z); - *cspan_at(&r_out, x,y,z) += d; - sum += d; - } - } + MD3_iter i = MD3_begin(&r_in); + MD3_iter o = MD3_begin(&r_out); + + for (; i.ref; MD3_next(&i), MD3_next(&o)) + { + *o.ref += *i.ref; + sum += *i.ref; } } t = clock() - t; - printf("nested : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); + printf("joined : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); } -static void MDRanges_loop_over_joined(intptr_t n) +static void MDRanges_nested_loop(intptr_t n) { clock_t t = clock(); MD3 r_in = cspan_md(Vin, nx, ny, nz); @@ -77,19 +75,22 @@ static void MDRanges_loop_over_joined(intptr_t n) double sum = 0; for (intptr_t s = 0; s < n; ++s) { - MD3_iter i = MD3_begin(&r_in); - MD3_iter o = MD3_begin(&r_out); - - for (; i.ref; MD3_next(&i), MD3_next(&o)) - { - *o.ref += *i.ref; - sum += *i.ref; + for (int x = 0; x < r_in.shape[0]; ++x) { + for (int y = 0; y < r_in.shape[1]; ++y) { + for (int z = 0; z < r_in.shape[2]; ++z) + { + double d = *cspan_at(&r_in, x,y,z); + *cspan_at(&r_out, x,y,z) += d; + sum += d; + } + } } } t = clock() - t; - printf("joined : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); + printf("nested : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum); } + int main(void) { intptr_t n = 100000; @@ -97,6 +98,6 @@ int main(void) Vin[i] = i + 1.23; Traditional_for_loop(n); - MDRanges_nested_loop(n); MDRanges_loop_over_joined(n); + MDRanges_nested_loop(n); } diff --git a/misc/examples/spans/matmult.c b/misc/examples/spans/matmult.c index 266fa121..ec992ff9 100644 --- a/misc/examples/spans/matmult.c +++ b/misc/examples/spans/matmult.c @@ -37,7 +37,7 @@ void base_case_matrix_product(Mat2 A, Mat2 B, OutMat C) void recursive_matrix_product(Mat2 A, Mat2 B, OutMat C) { // Some hardware-dependent constant - enum {recursion_threshold = 16}; + enum {recursion_threshold = 32}; if (C.shape[0] <= recursion_threshold || C.shape[1] <= recursion_threshold) { base_case_matrix_product(A, B, C); } else { @@ -63,28 +63,28 @@ void recursive_matrix_product(Mat2 A, Mat2 B, OutMat C) int main(void) { - enum {N = 10, D1 = 256, D2 = D1}; + enum {N = 10, D = 256}; Values values = {0}; - for (int i=0; i < N*D1*D2; ++i) + for (int i=0; i < N*D*D; ++i) Values_push(&values, (crandf() - 0.5)*4.0); - double out[D1*D2]; - Mat3 data = cspan_md_layout(c_ROWMAJOR, values.data, N, D1, D2); - OutMat c = cspan_md_layout(c_ROWMAJOR, out, D1, D2); + double out[D*D]; + Mat3 data = cspan_md_layout(c_ROWMAJOR, values.data, N, D, D); + OutMat c = cspan_md_layout(c_COLMAJOR, out, D, D); Mat2 a = cspan_submd3(&data, 0); - double sum = 0.0; - clock_t t = clock(); + clock_t t = clock(); for (int i=1; i= 201112L -# define i_implement # include "../include/c11/fmt.h" #endif -- cgit v1.2.3 From 8e9af18b3943bf9b000be42eb55d76f922a0e6ce Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 30 Aug 2023 17:44:45 +0200 Subject: Fixed overflows in offset calculations for large md spans. --- include/stc/cspan.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index e72bb97a..86aefdc0 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -202,7 +202,7 @@ STC_INLINE intptr_t _cspan_index(int rank, const int32_t shape[], const int32_t intptr_t off = 0; while (rank--) { c_assert(c_LTu(a[rank], shape[rank])); - off += stride[rank]*a[rank]; + off += (intptr_t)stride[rank]*a[rank]; } return off; } @@ -233,7 +233,7 @@ STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_ for (; r && pos[r] == shape[r]; --r) { pos[r] = 0; ++pos[r - 1]; - off += stride[r - 1] - stride[r]*shape[r]; + off += stride[r - 1] - (intptr_t)stride[r]*shape[r]; } *done = pos[r] == shape[r]; return off; @@ -263,7 +263,7 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, int32_t end; for (; i < rank; ++i) { - off += stride[i]*a[i][0]; + off += (intptr_t)stride[i]*a[i][0]; switch (a[i][1]) { case 0: c_assert(c_LTu(a[i][0], shape[i])); continue; case -1: end = shape[i]; break; -- cgit v1.2.3 From 5e38c27f35d8916770a5e1f9a586c7d73e27bad1 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 1 Sep 2023 09:45:58 +0200 Subject: cspan: can now span over a intptr_t size array, but each dimension is still limited to int32_t sizes. --- docs/cspan_api.md | 40 +++++++++++++++++++++++----------------- include/stc/cspan.h | 46 +++++++++++++++++++++++----------------------- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 0f345a7e..4875e021 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -1,9 +1,14 @@ # STC [cspan](../include/stc/cspan.h): Multi-dimensional Array View ![Array](pics/array.jpg) -The **cspan** is templated non-owning *single* and *multi-dimensional* view of an array. It has similarities -with Python's numpy array slicing and C++ [std::span](https://en.cppreference.com/w/cpp/container/span) / -[std::mdspan](https://en.cppreference.com/w/cpp/container/mdspan), and others. +The **cspan** types are templated non-owning *single* and *multi-dimensional* views of an array. +It supports both row-major and column-major layout efficiently, in a addition to slicing +capabilities similar to [python's numpy arrays](https://numpy.org/doc/stable/user/basics.indexing.html). +Note that each dimension is currently limited to int32_t sizes and 8 dimensions (can be extended). + +See also C++ +[std::span](https://en.cppreference.com/w/cpp/container/span) / +[std::mdspan](https://en.cppreference.com/w/cpp/container/mdspan) for similar functionality. ## Header file and declaration **cspan** types are defined by the *using_cspan()* macro after the header is included. @@ -29,14 +34,14 @@ by default (define `STC_NDEBUG` or `NDEBUG` to disable). ```c SpanType cspan_init(TYPE SpanType, {v1, v2, ...}); // make a 1-d cspan from values SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from a cvec, cstack, cpque (heap) -SpanType cspan_from_n(ValueType* ptr, intptr_t n); // make a 1-d cspan from a pointer and length +SpanType cspan_from_n(ValueType* ptr, int32_t n); // make a 1-d cspan from a pointer and length SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from a C array intptr_t cspan_size(const SpanTypeN* self); // return number of elements intptr_t cspan_rank(const SpanTypeN* self); // dimensions; compile time constant -intptr_t cspan_index(const SpanTypeN* self, intptr_t x, ..); // index of element +intptr_t cspan_index(const SpanTypeN* self, int32_t x, ..); // offset index at i, j, .. -ValueType* cspan_at(const SpanTypeN* self, intptr_t x, ...); // #args must match input span rank +ValueType* cspan_at(const SpanTypeN* self, int32_t x, ...); // num args is compile-time checked ValueType* cspan_front(const SpanTypeN* self); ValueType* cspan_back(const SpanTypeN* self); @@ -45,8 +50,8 @@ SpanTypeN_iter SpanType_end(const SpanTypeN* self); void SpanType_next(SpanTypeN_iter* it); // make a multi-dim cspan -SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // row-major -SpanTypeN cspan_md_layout(cspan_layout layout, ValueType* data, d1, d2, ...); +SpanTypeN cspan_md(ValueType* data, int32_t d1, int32_t d2, ...); // row-major layout +SpanTypeN cspan_md_layout(cspan_layout layout, ValueType* data, int32_t d1, d2, ...); // transpose a md span. Inverses layout and axes only. void cspan_transpose(const SpanTypeN* self); @@ -55,14 +60,14 @@ bool cspan_is_rowmajor(const SpanTypeN* self); bool cspan_is_colmajor(const SpanTypeN* self); // create a subspan of input span rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); -SpanType cspan_subspan(const SpanType* span, intptr_t offset, intptr_t count); -SpanType2 cspan_subspan2(const SpanType2* span, intptr_t offset, intptr_t count); -SpanType3 cspan_subspan3(const SpanType3* span, intptr_t offset, intptr_t count); +SpanType cspan_subspan(const SpanType* span, int32_t offset, int32_t count); +SpanType2 cspan_subspan2(const SpanType2* span, int32_t offset, int32_t count); +SpanType3 cspan_subspan3(const SpanType3* span, int32_t offset, int32_t count); // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); -OutSpan cspan_submd2(const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span. -OutSpanN cspan_submd3(const SpanType3* parent, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span. -OutSpanN cspan_submd4(const SpanType4* parent, intptr_t x, ...); // number of args decides rank of output span. +OutSpan cspan_submd2(const SpanType2* parent, int32_t x); // return a 1d subspan from a 2d span. +OutSpanN cspan_submd3(const SpanType3* parent, int32_t x, ...); // return a 1d or 2d subspan from a 3d span. +OutSpanN cspan_submd4(const SpanType4* parent, int32_t x, ...); // number of args decides rank of output span. // general slicing of an md span. // {i}: reduce rank. {i,c_END}: slice to end. {c_ALL}: use full extent. @@ -71,11 +76,12 @@ OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeM* parent, {x0,x1}, {y0 ## Types | Type name | Type definition / usage | Used to represent... | |:------------------|:----------------------------------------------------|:---------------------| -| SpanTypeN | `struct { ValueType *data; uint32_t shape[N]; .. }` | SpanType with rank N | -| SpanTypeN`_value` | `ValueType` | The ValueType | +| SpanTypeN_value | `ValueType` | The ValueType | +| SpanTypeN | `struct { ValueType *data; int32_t shape[N]; .. }` | SpanType with rank N | +| `cspan_tupleN` | `struct { intptr_t d[N]; }` | Strides for each rank | +| `cspan_layout` | `enum { c_ROWMAJOR, c_COLMAJOR }` | Multi-dim layout | | `c_ALL` | `cspan_slice(&md, {1,3}, {c_ALL})` | Full extent | | `c_END` | `cspan_slice(&md, {1,c_END}, {2,c_END})` | End of extent | -| `cspan_layout` | `enum { c_ROWMAJOR, c_COLMAJOR }` | Multi-dim layout | ## Example 1 diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 86aefdc0..e058c0e8 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -81,7 +81,7 @@ int demo2() { \ typedef struct { Self##_value *ref; int32_t pos[RANK]; const Self *_s; } Self##_iter; \ \ - STC_INLINE Self Self##_slice_(Self##_value* d, const int32_t shape[], const int32_t stri[], \ + STC_INLINE Self Self##_slice_(Self##_value* d, const int32_t shape[], const intptr_t stri[], \ const int rank, const int32_t a[][2]) { \ Self s; int outrank; \ s.data = d + _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ @@ -106,7 +106,7 @@ int demo2() { #define using_cspan2(Self, T) using_cspan_2(Self, T); using_cspan_3(Self##2, T, 2) #define using_cspan3(Self, T) using_cspan2(Self, T); using_cspan_3(Self##3, T, 3) #define using_cspan4(Self, T) using_cspan3(Self, T); using_cspan_3(Self##4, T, 4) -#define using_cspan_tuple(N) typedef struct { int32_t d[N]; } cspan_tuple##N +#define using_cspan_tuple(N) typedef struct { intptr_t d[N]; } cspan_tuple##N using_cspan_tuple(1); using_cspan_tuple(2); using_cspan_tuple(3); using_cspan_tuple(4); using_cspan_tuple(5); using_cspan_tuple(6); @@ -139,7 +139,7 @@ typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout; #define cspan_front(self) ((self)->data) #define cspan_back(self) ((self)->data + cspan_size(self) - 1) #define cspan_index(self, ...) \ - (_cspan_index(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \ + (_cspan_index(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (const int32_t[]){__VA_ARGS__}) + \ c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general // cspan_subspanX: (X <= 3) optimized. Similar to cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); @@ -172,7 +172,7 @@ typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout; #define cspan_md(array, ...) cspan_md_layout(c_ROWMAJOR, array, __VA_ARGS__) #define cspan_md_layout(layout, array, ...) \ {.data=array, .shape={__VA_ARGS__}, \ - .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(layout, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} + .stride=*(c_PASTE(cspan_tuple,c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(layout, ((intptr_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} #define cspan_transpose(self) \ _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self)) @@ -191,25 +191,25 @@ STC_INLINE intptr_t _cspan_size(const int32_t shape[], int rank) { return sz; } -STC_INLINE void _cspan_transpose(int32_t shape[], int32_t stride[], int rank) { +STC_INLINE void _cspan_transpose(int32_t shape[], intptr_t stride[], int rank) { for (int i = 0; i < --rank; ++i) { c_swap(int32_t, shape + i, shape + rank); - c_swap(int32_t, stride + i, stride + rank); + c_swap(intptr_t, stride + i, stride + rank); } } -STC_INLINE intptr_t _cspan_index(int rank, const int32_t shape[], const int32_t stride[], const int32_t a[]) { +STC_INLINE intptr_t _cspan_index(int rank, const int32_t shape[], const intptr_t stride[], const int32_t a[]) { intptr_t off = 0; while (rank--) { c_assert(c_LTu(a[rank], shape[rank])); - off += (intptr_t)stride[rank]*a[rank]; + off += stride[rank]*a[rank]; } return off; } #define _cspan_next1(pos, shape, stride, rank, done) (*done = ++pos[0]==shape[0], stride[0]) STC_API intptr_t - _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int* done); + _cspan_next2(int32_t pos[], const int32_t shape[], const intptr_t stride[], int rank, int* done); #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 @@ -217,53 +217,53 @@ STC_API intptr_t #define _cspan_next7 _cspan_next2 #define _cspan_next8 _cspan_next2 -STC_API intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, - const int32_t shape[], const int32_t stride[], +STC_API intptr_t _cspan_slice(int32_t oshape[], intptr_t ostride[], int* orank, + const int32_t shape[], const intptr_t stride[], int rank, const int32_t a[][2]); -STC_API int32_t* _cspan_shape2stride(cspan_layout layout, int32_t shape[], int rank); +STC_API intptr_t* _cspan_shape2stride(cspan_layout layout, intptr_t shape[], int rank); #endif // STC_CSPAN_H_INCLUDED /* --------------------- IMPLEMENTATION --------------------- */ #if defined(i_implement) || defined(i_static) -STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int r, int* done) { +STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const intptr_t stride[], int r, int* done) { intptr_t off = stride[--r]; ++pos[r]; for (; r && pos[r] == shape[r]; --r) { pos[r] = 0; ++pos[r - 1]; - off += stride[r - 1] - (intptr_t)stride[r]*shape[r]; + off += stride[r - 1] - stride[r]*shape[r]; } *done = pos[r] == shape[r]; return off; } -STC_DEF int32_t* _cspan_shape2stride(cspan_layout layout, int32_t shape[], int rank) { +STC_DEF intptr_t* _cspan_shape2stride(cspan_layout layout, intptr_t stride[], int rank) { int i, inc; if (layout == c_COLMAJOR) i = 0, inc = 1; else i = rank - 1, inc = -1; - int32_t k = 1, s1 = shape[i], s2; + intptr_t k = 1, s1 = stride[i], s2; - shape[i] = 1; + stride[i] = 1; while (--rank) { i += inc; - s2 = shape[i]; - shape[i] = (k *= s1); + s2 = stride[i]; + stride[i] = (k *= s1); s1 = s2; } - return shape; + return stride; } -STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, - const int32_t shape[], const int32_t stride[], +STC_DEF intptr_t _cspan_slice(int32_t oshape[], intptr_t ostride[], int* orank, + const int32_t shape[], const intptr_t stride[], int rank, const int32_t a[][2]) { intptr_t off = 0; int i = 0, oi = 0; int32_t end; for (; i < rank; ++i) { - off += (intptr_t)stride[i]*a[i][0]; + off += stride[i]*a[i][0]; switch (a[i][1]) { case 0: c_assert(c_LTu(a[i][0], shape[i])); continue; case -1: end = shape[i]; break; -- cgit v1.2.3 From 3628e4389ef9455960c42466487385fc228566c3 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 5 Sep 2023 13:01:50 +0200 Subject: Renamed (half) internal function cfasthash() => cbytehash(). Fixed missing parameter in call of i_hash(). --- docs/cmap_api.md | 4 ++-- include/stc/carc.h | 2 +- include/stc/cbox.h | 2 +- include/stc/ccommon.h | 6 +++--- include/stc/crawstr.h | 2 +- include/stc/cstr.h | 2 +- include/stc/csview.h | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 65777221..0fbd9b7a 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -88,9 +88,9 @@ cmap_X_raw cmap_X_value_toraw(cmap_X_value* pval); ``` Helpers: ```c -uint64_t c_default_hash(const X *obj); // macro, calls cfasthash(obj, sizeof *obj) +uint64_t cbytehash(const void *data, intptr_t len); // base hash function uint64_t cstrhash(const char *str); // string hash funcion, uses strlen() -uint64_t cfasthash(const void *data, intptr_t len); // base hash function +uint64_t c_default_hash(const X *obj); // macro, calls cbytehash(obj, sizeof *obj) // equalto template parameter functions: bool c_default_eq(const i_keyraw* a, const i_keyraw* b); // *a == *b diff --git a/include/stc/carc.h b/include/stc/carc.h index 1b1c22eb..b617e1ca 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -200,7 +200,7 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { { return i_hash(rx); } STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } + { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } #endif // i_no_hash #else diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 37daa69e..55ce9711 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -180,7 +180,7 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) { { return i_hash(rx); } STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } + { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } #endif // i_no_hash #else diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index ad92212a..8363fbe5 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -103,7 +103,7 @@ typedef long long _llong; #define c_default_less(x, y) (*(x) < *(y)) #define c_default_eq(x, y) (*(x) == *(y)) #define c_memcmp_eq(x, y) (memcmp(x, y, sizeof *(x)) == 0) -#define c_default_hash(x) cfasthash(x, c_sizeof(*(x))) +#define c_default_hash(x) cbytehash(x, c_sizeof(*(x))) #define c_default_clone(v) (v) #define c_default_toraw(vp) (*(vp)) @@ -138,7 +138,7 @@ typedef const char* ccharptr; #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) -STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { +STC_INLINE uint64_t cbytehash(const void* key, intptr_t len) { uint32_t u4; uint64_t u8; switch (len) { case 8: memcpy(&u8, key, 8); return u8*0xc6a4a7935bd1e99d; @@ -157,7 +157,7 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { } STC_INLINE uint64_t cstrhash(const char *str) - { return cfasthash(str, c_strlen(str)); } + { return cbytehash(str, c_strlen(str)); } STC_INLINE char* cstrnstrn(const char *str, const char *needle, intptr_t slen, const intptr_t nlen) { diff --git a/include/stc/crawstr.h b/include/stc/crawstr.h index 0395c8c6..a244397d 100644 --- a/include/stc/crawstr.h +++ b/include/stc/crawstr.h @@ -98,7 +98,7 @@ STC_INLINE bool crawstr_eq(const crawstr* x, const crawstr* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } STC_INLINE uint64_t crawstr_hash(const crawstr *self) - { return cfasthash(self->str, self->size); } + { return cbytehash(self->str, self->size); } #endif // CRAWSTR_H_INCLUDED #undef i_static diff --git a/include/stc/cstr.h b/include/stc/cstr.h index f0974865..51519d82 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -450,7 +450,7 @@ bool cstr_valid_utf8(const cstr* self) STC_DEF uint64_t cstr_hash(const cstr *self) { csview sv = cstr_sv(self); - return cfasthash(sv.buf, sv.size); + return cbytehash(sv.buf, sv.size); } STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { diff --git a/include/stc/csview.h b/include/stc/csview.h index a2d1e9f0..005f27de 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -170,7 +170,7 @@ STC_DEF intptr_t csview_find_sv(csview sv, csview search) { } STC_DEF uint64_t csview_hash(const csview *self) - { return cfasthash(self->buf, self->size); } + { return cbytehash(self->buf, self->size); } STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { if (pos < 0) { -- cgit v1.2.3 From 493c34e9c2de0587f38681340db8f2735e72d7dd Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 5 Sep 2023 18:10:14 +0200 Subject: Renamed (half)internal functions: cfasthash() => stc_hash() cstrhash() => stc_strhash() cnextpow2() => stc_nextpow2() --- docs/cmap_api.md | 15 ++++++++------- docs/cstr_api.md | 5 +++-- include/stc/ccommon.h | 16 ++++++++-------- include/stc/cmap.h | 2 +- include/stc/crawstr.h | 4 ++-- include/stc/cstr.h | 6 +++--- include/stc/csview.h | 6 +++--- include/stc/priv/cqueue_imp.h | 2 +- misc/examples/hashmaps/vikings.c | 2 +- 9 files changed, 30 insertions(+), 28 deletions(-) diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 0fbd9b7a..8e29efe1 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -72,7 +72,7 @@ cmap_X_result cmap_X_push(cmap_X* self, cmap_X_value entry); cmap_X_result cmap_X_emplace(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update mapped -cmap_X_result cmap_X_emplace_key(cmap_X* self, i_keyraw rkey); // see example 1. +cmap_X_result cmap_X_emplace_key(cmap_X* self, i_keyraw rkey); // see example 1. int cmap_X_erase(cmap_X* self, i_keyraw rkey); // return 0 or 1 cmap_X_iter cmap_X_erase_at(cmap_X* self, cmap_X_iter it); // return iter after it @@ -86,13 +86,14 @@ cmap_X_iter cmap_X_advance(cmap_X_iter it, cmap_X_ssize n); cmap_X_value cmap_X_value_clone(cmap_X_value val); cmap_X_raw cmap_X_value_toraw(cmap_X_value* pval); ``` -Helpers: +Free helper functions: ```c -uint64_t cbytehash(const void *data, intptr_t len); // base hash function -uint64_t cstrhash(const char *str); // string hash funcion, uses strlen() -uint64_t c_default_hash(const X *obj); // macro, calls cbytehash(obj, sizeof *obj) +uint64_t stc_hash(const void *data, intptr_t len); // base hash function +uint64_t stc_strhash(const char *str); // string hash funcion, uses strlen() +uint64_t stc_nextpow2(intptr_t i); // get next power of 2 >= i -// equalto template parameter functions: +// hash/equal template default functions: +uint64_t c_default_hash(const X *obj); // macro, calls stc_hash(obj, sizeof *obj) bool c_default_eq(const i_keyraw* a, const i_keyraw* b); // *a == *b bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // !memcmp(a, b, sizeof *a) ``` @@ -381,7 +382,7 @@ static inline RViking Viking_toraw(const Viking* vp) { #define i_keyraw RViking #define i_keyfrom Viking_from #define i_opt c_no_clone // disable map cloning -#define i_hash(rp) (cstrhash(rp->name) ^ cstrhash(rp->country)) +#define i_hash(rp) (stc_strhash(rp->name) ^ stc_strhash(rp->country)) #define i_val int #include diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 397634ec..69512a9e 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -142,8 +142,9 @@ Note that all methods with arguments `(..., const char* str, intptr_t n)`, `n` m ```c int cstr_cmp(const cstr* s1, const cstr* s2); bool cstr_eq(const cstr* s1, const cstr* s2); -bool cstr_hash(const cstr* self); -char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen); +uint64_t cstr_hash(const cstr* self); + +char* stc_strnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen); ``` ## Types diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 8363fbe5..d074701f 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -103,7 +103,7 @@ typedef long long _llong; #define c_default_less(x, y) (*(x) < *(y)) #define c_default_eq(x, y) (*(x) == *(y)) #define c_memcmp_eq(x, y) (memcmp(x, y, sizeof *(x)) == 0) -#define c_default_hash(x) cbytehash(x, c_sizeof(*(x))) +#define c_default_hash(x) stc_hash(x, c_sizeof(*(x))) #define c_default_clone(v) (v) #define c_default_toraw(vp) (*(vp)) @@ -124,7 +124,7 @@ typedef long long _llong; // Non-owning c-string "class" typedef const char* ccharptr; #define ccharptr_cmp(xp, yp) strcmp(*(xp), *(yp)) -#define ccharptr_hash(p) cstrhash(*(p)) +#define ccharptr_hash(p) stc_strhash(*(p)) #define ccharptr_clone(s) (s) #define ccharptr_drop(p) ((void)p) @@ -138,7 +138,7 @@ typedef const char* ccharptr; #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) -STC_INLINE uint64_t cbytehash(const void* key, intptr_t len) { +STC_INLINE uint64_t stc_hash(const void* key, intptr_t len) { uint32_t u4; uint64_t u8; switch (len) { case 8: memcpy(&u8, key, 8); return u8*0xc6a4a7935bd1e99d; @@ -156,11 +156,11 @@ STC_INLINE uint64_t cbytehash(const void* key, intptr_t len) { return h ^ c_ROTL(h, 26); } -STC_INLINE uint64_t cstrhash(const char *str) - { return cbytehash(str, c_strlen(str)); } +STC_INLINE uint64_t stc_strhash(const char *str) + { return stc_hash(str, c_strlen(str)); } -STC_INLINE char* cstrnstrn(const char *str, const char *needle, - intptr_t slen, const intptr_t nlen) { +STC_INLINE char* stc_strnstrn(const char *str, const char *needle, + intptr_t slen, const intptr_t nlen) { if (!nlen) return (char *)str; if (nlen > slen) return NULL; slen -= nlen; @@ -172,7 +172,7 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle, return NULL; } -STC_INLINE intptr_t cnextpow2(intptr_t n) { +STC_INLINE intptr_t stc_nextpow2(intptr_t n) { n--; n |= n >> 1, n |= n >> 2; n |= n >> 4, n |= n >> 8; diff --git a/include/stc/cmap.h b/include/stc/cmap.h index deee1f59..c069fbd8 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -414,7 +414,7 @@ _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) { if (_newcap != self->size && _newcap <= _oldbucks) return true; intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4; - _newbucks = cnextpow2(_newbucks); + _newbucks = stc_nextpow2(_newbucks); _cx_Self m = { (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), (struct chash_slot *)i_calloc(_newbucks + 1, c_sizeof(struct chash_slot)), diff --git a/include/stc/crawstr.h b/include/stc/crawstr.h index a244397d..9dbdb6f7 100644 --- a/include/stc/crawstr.h +++ b/include/stc/crawstr.h @@ -45,7 +45,7 @@ STC_INLINE bool crawstr_equals(crawstr rs, const char* str) { } STC_INLINE intptr_t crawstr_find(crawstr rs, const char* search) { - char* res = cstrnstrn(rs.str, search, rs.size, c_strlen(search)); + char* res = strstr(rs.str, search); return res ? (res - rs.str) : c_NPOS; } @@ -98,7 +98,7 @@ STC_INLINE bool crawstr_eq(const crawstr* x, const crawstr* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } STC_INLINE uint64_t crawstr_hash(const crawstr *self) - { return cbytehash(self->str, self->size); } + { return stc_hash(self->str, self->size); } #endif // CRAWSTR_H_INCLUDED #undef i_static diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 51519d82..d2faeb62 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -450,12 +450,12 @@ bool cstr_valid_utf8(const cstr* self) STC_DEF uint64_t cstr_hash(const cstr *self) { csview sv = cstr_sv(self); - return cbytehash(sv.buf, sv.size); + return stc_hash(sv.buf, sv.size); } STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { csview sv = cstr_sv(self); - char* res = cstrnstrn(sv.buf, search.buf, sv.size, search.size); + char* res = stc_strnstrn(sv.buf, search.buf, sv.size, search.size); return res ? (res - sv.buf) : c_NPOS; } @@ -588,7 +588,7 @@ STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t coun intptr_t from = 0; char* res; if (!count) count = INT32_MAX; if (search.size) - while (count-- && (res = cstrnstrn(in.buf + from, search.buf, in.size - from, search.size))) { + while (count-- && (res = stc_strnstrn(in.buf + from, search.buf, in.size - from, search.size))) { const intptr_t pos = (res - in.buf); cstr_append_n(&out, in.buf + from, pos - from); cstr_append_n(&out, repl.buf, repl.size); diff --git a/include/stc/csview.h b/include/stc/csview.h index 005f27de..f41acf4f 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -165,12 +165,12 @@ STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { } STC_DEF intptr_t csview_find_sv(csview sv, csview search) { - char* res = cstrnstrn(sv.buf, search.buf, sv.size, search.size); + char* res = stc_strnstrn(sv.buf, search.buf, sv.size, search.size); return res ? (res - sv.buf) : c_NPOS; } STC_DEF uint64_t csview_hash(const csview *self) - { return cbytehash(self->buf, self->size); } + { return stc_hash(self->buf, self->size); } STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { if (pos < 0) { @@ -197,7 +197,7 @@ STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { intptr_t sep_size = c_strlen(sep); csview slice = {sv.buf + *start, sv.size - *start}; - const char* res = cstrnstrn(slice.buf, sep, slice.size, sep_size); + const char* res = stc_strnstrn(slice.buf, sep, slice.size, sep_size); csview tok = {slice.buf, res ? (res - slice.buf) : slice.size}; *start += tok.size + sep_size; return tok; diff --git a/include/stc/priv/cqueue_imp.h b/include/stc/priv/cqueue_imp.h index 2ad9c811..18c1bb15 100644 --- a/include/stc/priv/cqueue_imp.h +++ b/include/stc/priv/cqueue_imp.h @@ -54,7 +54,7 @@ STC_DEF bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n) { if (n <= self->capmask) return true; - intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1); + intptr_t oldcap = self->capmask + 1, newcap = stc_nextpow2(n + 1); _cx_value* d = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data); if (!d) return false; diff --git a/misc/examples/hashmaps/vikings.c b/misc/examples/hashmaps/vikings.c index d6125854..cef17a04 100644 --- a/misc/examples/hashmaps/vikings.c +++ b/misc/examples/hashmaps/vikings.c @@ -37,7 +37,7 @@ static inline RViking Viking_toraw(const Viking* vp) { #define i_rawclass RViking // lookup type #define i_keyfrom Viking_from #define i_opt c_no_clone -#define i_hash(rp) cstrhash(rp->name) ^ cstrhash(rp->country) +#define i_hash(rp) stc_strhash(rp->name) ^ stc_strhash(rp->country) #define i_val int // mapped type #include -- cgit v1.2.3 From a0a75ac1c324ac52931c9df37ce13cb4213ab711 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 5 Sep 2023 18:21:53 +0200 Subject: Swapped two parameters in newly renamed "internal" function stc_strnstrn(). --- docs/cstr_api.md | 2 +- include/stc/ccommon.h | 4 ++-- include/stc/cstr.h | 4 ++-- include/stc/csview.h | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 69512a9e..29dfe464 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -144,7 +144,7 @@ int cstr_cmp(const cstr* s1, const cstr* s2); bool cstr_eq(const cstr* s1, const cstr* s2); uint64_t cstr_hash(const cstr* self); -char* stc_strnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen); +char* stc_strnstrn(const char* str, intptr_t slen, const char* needle, intptr_t nlen); ``` ## Types diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index d074701f..80cbc5e4 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -159,8 +159,8 @@ STC_INLINE uint64_t stc_hash(const void* key, intptr_t len) { STC_INLINE uint64_t stc_strhash(const char *str) { return stc_hash(str, c_strlen(str)); } -STC_INLINE char* stc_strnstrn(const char *str, const char *needle, - intptr_t slen, const intptr_t nlen) { +STC_INLINE char* stc_strnstrn(const char *str, intptr_t slen, + const char *needle, intptr_t nlen) { if (!nlen) return (char *)str; if (nlen > slen) return NULL; slen -= nlen; diff --git a/include/stc/cstr.h b/include/stc/cstr.h index d2faeb62..f7e7b8ad 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -455,7 +455,7 @@ STC_DEF uint64_t cstr_hash(const cstr *self) { STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { csview sv = cstr_sv(self); - char* res = stc_strnstrn(sv.buf, search.buf, sv.size, search.size); + char* res = stc_strnstrn(sv.buf, sv.size, search.buf, search.size); return res ? (res - sv.buf) : c_NPOS; } @@ -588,7 +588,7 @@ STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t coun intptr_t from = 0; char* res; if (!count) count = INT32_MAX; if (search.size) - while (count-- && (res = stc_strnstrn(in.buf + from, search.buf, in.size - from, search.size))) { + while (count-- && (res = stc_strnstrn(in.buf + from, in.size - from, search.buf, search.size))) { const intptr_t pos = (res - in.buf); cstr_append_n(&out, in.buf + from, pos - from); cstr_append_n(&out, repl.buf, repl.size); diff --git a/include/stc/csview.h b/include/stc/csview.h index f41acf4f..11e42c97 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -165,7 +165,7 @@ STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { } STC_DEF intptr_t csview_find_sv(csview sv, csview search) { - char* res = stc_strnstrn(sv.buf, search.buf, sv.size, search.size); + char* res = stc_strnstrn(sv.buf, sv.size, search.buf, search.size); return res ? (res - sv.buf) : c_NPOS; } @@ -197,7 +197,7 @@ STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { intptr_t sep_size = c_strlen(sep); csview slice = {sv.buf + *start, sv.size - *start}; - const char* res = stc_strnstrn(slice.buf, sep, slice.size, sep_size); + const char* res = stc_strnstrn(slice.buf, slice.size, sep, sep_size); csview tok = {slice.buf, res ? (res - slice.buf) : slice.size}; *start += tok.size + sep_size; return tok; -- cgit v1.2.3 From 0da4c619e8e8134d1776097a9e102ed48d54b9a5 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 6 Sep 2023 09:49:47 +0200 Subject: Renamed c_LTu(a, b) => c_less_unsigned(a, b) Renamed c_u2i(i) => c_u2i_size(u) Renamed c_i2u(i) => c_i2u_size(i) --- include/stc/ccommon.h | 26 +++++++++++++------------- include/stc/cspan.h | 6 +++--- include/stc/priv/cqueue_imp.h | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 80cbc5e4..0a8c439a 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -69,10 +69,10 @@ typedef long long _llong; #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T))) #define c_LITERAL(T) (T) #endif -#define c_new_n(T, n) ((T*)malloc(sizeof(T)*c_i2u(n))) -#define c_malloc(sz) malloc(c_i2u(sz)) -#define c_calloc(n, sz) calloc(c_i2u(n), c_i2u(sz)) -#define c_realloc(p, sz) realloc(p, c_i2u(sz)) +#define c_new_n(T, n) ((T*)malloc(sizeof(T)*c_i2u_size(n))) +#define c_malloc(sz) malloc(c_i2u_size(sz)) +#define c_calloc(n, sz) calloc(c_i2u_size(n), c_i2u_size(sz)) +#define c_realloc(p, sz) realloc(p, c_i2u_size(sz)) #define c_free(p) free(p) #define c_delete(T, ptr) do { T *_tp = ptr; T##_drop(_tp); free(_tp); } while (0) @@ -86,17 +86,17 @@ typedef long long _llong; #define c_const_cast(T, p) ((T)(1 ? (p) : (T)0)) #define c_swap(T, xp, yp) do { T *_xp = xp, *_yp = yp, \ _tv = *_xp; *_xp = *_yp; *_yp = _tv; } while (0) -// use with gcc -Wsign-conversion +// use with gcc -Wconversion #define c_sizeof (intptr_t)sizeof #define c_strlen(s) (intptr_t)strlen(s) -#define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u(ilen)) -#define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u(ilen)) -#define c_memmove(d, s, ilen) memmove(d, s, c_i2u(ilen)) -#define c_memset(d, val, ilen) memset(d, val, c_i2u(ilen)) -#define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u(ilen)) -#define c_u2i(u) (intptr_t)(1 ? (u) : (size_t)1) -#define c_i2u(i) (size_t)(1 ? (i) : -1) -#define c_LTu(a, b) ((size_t)(a) < (size_t)(b)) +#define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u_size(ilen)) +#define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u_size(ilen)) +#define c_memmove(d, s, ilen) memmove(d, s, c_i2u_size(ilen)) +#define c_memset(d, val, ilen) memset(d, val, c_i2u_size(ilen)) +#define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u_size(ilen)) +#define c_u2i_size(u) (intptr_t)(1 ? (u) : (size_t)1) +#define c_i2u_size(i) (size_t)(1 ? (i) : -1) +#define c_less_unsigned(a, b) ((size_t)(a) < (size_t)(b)) // x and y are i_keyraw* type, defaults to i_key*: #define c_default_cmp(x, y) (c_default_less(y, x) - c_default_less(x, y)) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index e058c0e8..1bc57e2b 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -201,7 +201,7 @@ STC_INLINE void _cspan_transpose(int32_t shape[], intptr_t stride[], int rank) { STC_INLINE intptr_t _cspan_index(int rank, const int32_t shape[], const intptr_t stride[], const int32_t a[]) { intptr_t off = 0; while (rank--) { - c_assert(c_LTu(a[rank], shape[rank])); + c_assert(c_less_unsigned(a[rank], shape[rank])); off += stride[rank]*a[rank]; } return off; @@ -265,13 +265,13 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], intptr_t ostride[], int* orank, for (; i < rank; ++i) { off += stride[i]*a[i][0]; switch (a[i][1]) { - case 0: c_assert(c_LTu(a[i][0], shape[i])); continue; + case 0: c_assert(c_less_unsigned(a[i][0], shape[i])); continue; case -1: end = shape[i]; break; default: end = a[i][1]; } oshape[oi] = end - a[i][0]; ostride[oi] = stride[i]; - c_assert((oshape[oi] > 0) & !c_LTu(shape[i], end)); + c_assert((oshape[oi] > 0) & !c_less_unsigned(shape[i], end)); ++oi; } *orank = oi; diff --git a/include/stc/priv/cqueue_imp.h b/include/stc/priv/cqueue_imp.h index 18c1bb15..65711fc0 100644 --- a/include/stc/priv/cqueue_imp.h +++ b/include/stc/priv/cqueue_imp.h @@ -26,7 +26,7 @@ STC_DEF _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n) { intptr_t pos = it.pos, idx = _cdeq_toidx(it._s, pos); it.pos = (pos + n) & it._s->capmask; it.ref += it.pos - pos; - if (!c_LTu(idx + n, len)) it.ref = NULL; + if (!c_less_unsigned(idx + n, len)) it.ref = NULL; return it; } -- cgit v1.2.3 From 1a72205fe05c2375cfd380dd8381a8460d9ed8d1 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 8 Sep 2023 00:34:05 +0200 Subject: Added optional "step" in cspan_slice() function. --- include/stc/cspan.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 1bc57e2b..0875ed92 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -82,7 +82,7 @@ int demo2() { typedef struct { Self##_value *ref; int32_t pos[RANK]; const Self *_s; } Self##_iter; \ \ STC_INLINE Self Self##_slice_(Self##_value* d, const int32_t shape[], const intptr_t stri[], \ - const int rank, const int32_t a[][2]) { \ + const int rank, const int32_t a[][3]) { \ Self s; int outrank; \ s.data = d + _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ c_assert(outrank == RANK); \ @@ -180,8 +180,8 @@ typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout; // General slicing function; #define cspan_slice(OutSpan, parent, ...) \ OutSpan##_slice_((parent)->data, (parent)->shape, (parent)->stride.d, cspan_rank(parent) + \ - c_static_assert(cspan_rank(parent) == sizeof((int32_t[][2]){__VA_ARGS__})/sizeof(int32_t[2])), \ - (const int32_t[][2]){__VA_ARGS__}) + c_static_assert(cspan_rank(parent) == sizeof((int32_t[][3]){__VA_ARGS__})/sizeof(int32_t[3])), \ + (const int32_t[][3]){__VA_ARGS__}) /* ------------------- PRIVAT DEFINITIONS ------------------- */ @@ -219,7 +219,7 @@ STC_API intptr_t STC_API intptr_t _cspan_slice(int32_t oshape[], intptr_t ostride[], int* orank, const int32_t shape[], const intptr_t stride[], - int rank, const int32_t a[][2]); + int rank, const int32_t a[][3]); STC_API intptr_t* _cspan_shape2stride(cspan_layout layout, intptr_t shape[], int rank); #endif // STC_CSPAN_H_INCLUDED @@ -257,7 +257,7 @@ STC_DEF intptr_t* _cspan_shape2stride(cspan_layout layout, intptr_t stride[], in STC_DEF intptr_t _cspan_slice(int32_t oshape[], intptr_t ostride[], int* orank, const int32_t shape[], const intptr_t stride[], - int rank, const int32_t a[][2]) { + int rank, const int32_t a[][3]) { intptr_t off = 0; int i = 0, oi = 0; int32_t end; @@ -272,6 +272,10 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], intptr_t ostride[], int* orank, oshape[oi] = end - a[i][0]; ostride[oi] = stride[i]; c_assert((oshape[oi] > 0) & !c_less_unsigned(shape[i], end)); + if (a[i][2]) { + ostride[oi] *= a[i][2]; + oshape[oi] = (oshape[oi] - 1)/a[i][2] + 1; + } ++oi; } *orank = oi; -- cgit v1.2.3