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 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 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