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 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'README.md') 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 -- 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 (limited to 'README.md') 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 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 (limited to 'README.md') 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 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(-) (limited to 'README.md') 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 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(-) (limited to 'README.md') 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 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(-) (limited to 'README.md') 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 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(-) (limited to 'README.md') 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 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(-) (limited to 'README.md') 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 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(-) (limited to 'README.md') 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(-) (limited to 'README.md') 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 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(-) (limited to 'README.md') 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(-) (limited to 'README.md') 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 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(-) (limited to 'README.md') 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 313c1d7bb9b92e75801429c1f7f132589860292e Mon Sep 17 00:00:00 2001 From: tylov Date: Tue, 18 Jul 2023 01:36:51 +0200 Subject: Renamed i_native_cmp => i_cmp_native Added c_all_of(), c_any_of(), c_none_of() to algo/filter.h --- README.md | 4 ++-- docs/carc_api.md | 24 +++++++++++++-------- docs/cbox_api.md | 29 +++++++++++++++----------- docs/cdeq_api.md | 23 +++++++++++---------- docs/clist_api.md | 21 ++++++++++--------- docs/cmap_api.md | 39 +++++++++++++++++------------------ docs/cpque_api.md | 18 ++++++++-------- docs/cqueue_api.md | 16 +++++++------- docs/cset_api.md | 26 +++++++++++------------ docs/csmap_api.md | 36 ++++++++++++++++---------------- docs/csset_api.md | 18 ++++++++-------- docs/cstack_api.md | 16 +++++++------- docs/cvec_api.md | 23 +++++++++++---------- include/stc/algo/coroutine.h | 13 ++++++++---- include/stc/algo/filter.h | 16 +++++++++++++- include/stc/priv/template.h | 8 +++---- include/stc/priv/template2.h | 2 +- misc/benchmarks/various/csort_bench.c | 2 +- misc/examples/arc_demo.c | 2 +- misc/examples/arcvec_erase.c | 2 +- misc/examples/demos.c | 2 +- misc/examples/intrusive.c | 2 +- misc/examples/list.c | 2 +- misc/examples/lower_bound.c | 2 +- misc/examples/new_list.c | 2 +- misc/examples/new_sptr.c | 2 +- 26 files changed, 191 insertions(+), 159 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index b7e06790..6bbe50ee 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ struct Point { float x, y; }; #include // cvec_pnt: vector of struct Point #define i_key int -#define i_native_cmp // enable sort/search. Use native `<` and `==` operators +#define i_cmp_native // enable sort/search. Use native `<` and `==` operators #include // clist_int: singly linked list #define i_key int @@ -619,7 +619,7 @@ STC is generally very memory efficient. Memory usage for the different container - cspan: Support for column-major (fortran order) multidim spans and transposed views. - Removed default comparison for clist, cvec and cdeq (as with cstack and cqueue). - Using i_key_str, i_keyclass, i_keyboxed still expects comparisons defined. - - Define i_native_cmp to enable built-in i_key types comparisons (<, ==). + - Define i_cmp_native to enable built-in i_key types comparisons (<, ==). - cstr and csview are now shared linked by default. Static linking by defining i_static. - New cdeq and cqueue implementation(s), using circular buffer. - Renamed i_extern => i_import. diff --git a/docs/carc_api.md b/docs/carc_api.md index 8b7b67a1..fb79019a 100644 --- a/docs/carc_api.md +++ b/docs/carc_api.md @@ -20,15 +20,21 @@ See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory ## Header file and declaration ```c -#define i_type // full typename of the carc -#define i_key // element type: REQUIRED - -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. -#define i_keyfrom // convertion func i_keyraw => i_key - -#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc. -#define i_tag // alternative typename: carc_{i_tag}. i_tag defaults to i_key +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // carc container type name +#define i_cmp // three-way compareison. REQUIRED IF i_key is a non-integral type + // Note that containers of carcs will "inherit" i_cmp + // when using carc in containers with i_valboxed MyArc - ie. the i_type. +#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_keydrop // destroy element func - defaults to empty destruct +#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. + +#define i_keyraw // convertion type (lookup): default to {i_key} +#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. +#define i_keyfrom // from-raw func. + +#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc. +#define i_tag // alternative typename: carc_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cbox_api.md b/docs/cbox_api.md index b6c76d2f..0e6fca64 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -14,18 +14,23 @@ See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory ## Header file and declaration ```c -#define i_type // full typename of the cbox -#define i_key // element type: REQUIRED -#define i_cmp // three-way compare two i_key* : REQUIRED IF i_key is a non-integral type -#define i_keydrop // destroy element func - defaults to empty destruct -#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. - -#define i_keyraw // convertion type (lookup): default to {i_key} -#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. -#define i_keyfrom // from-raw func. - -#define i_keyclass // alt. to i_key: REQUIRES that {i_key}_clone, {i_key}_drop, {i_keyraw}_cmp exist. -#define i_tag // alternative typename: cbox_{i_tag}. i_tag defaults to i_key +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // cbox container type name +#define i_cmp // three-way compareison. REQUIRED IF i_key is a non-integral type + // Note that containers of carcs will "inherit" i_cmp + // when using carc in containers with i_valboxed MyArc - ie. the i_type. +#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_keydrop // destroy element func - defaults to empty destruct +#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. + +#define i_keyraw // convertion type (lookup): default to {i_key} +#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined. +#define i_keyfrom // from-raw func. + +#define i_tag // alternative typename: cbox_{i_tag}. i_tag defaults to i_key +#define i_keyclass // Use instead of i_key when functions {i_key}_clone, + // {i_key}_drop and {i_keyraw}_cmp exist. +#define i_keyboxed // Use instead of i_key when key is a carc- or a cbox-type. #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index c6de6cd6..38de7f66 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -10,17 +10,18 @@ See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque ## Header file and declaration ```c -#define i_type // full typename of the container -#define i_key // value: REQUIRED -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw - -#define i_tag // alternative typename: cdeq_{i_tag}. i_tag defaults to i_key +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // cdeq container type name +#define i_cmp // three-way compare of two i_keyraw*. +#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop is defined + +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw + +#define i_tag // alternative typename: cdeq_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/clist_api.md b/docs/clist_api.md index 3d785789..d8d614c2 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -22,16 +22,17 @@ See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list) ## Header file and declaration ```c -#define i_type // container type name (default: clist_{i_key}) -#define i_key // value: REQUIRED -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // convertion "raw" type (default: {i_key}) -#define i_keyto // convertion func i_key* => i_keyraw -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // clist container type name +#define i_cmp // three-way compare two i_keyraw* +#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined + +#define i_keyraw // convertion "raw" type (default: {i_key}) +#define i_keyto // convertion func i_key* => i_keyraw +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key #include ``` diff --git a/docs/cmap_api.md b/docs/cmap_api.md index eca350b4..17f27662 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -17,26 +17,25 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain ## Header file and declaration ```c -#define i_type // container type name (default: cmap_{i_key}) -#define i_key // hash key: REQUIRED -#define i_val // map value: REQUIRED -#define i_hash // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type -#define i_eq // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a - // non-integral type. Three-way i_cmp may alternatively be specified. -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw - -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined -#define i_valraw // convertion "raw" type - defaults to i_val -#define i_valfrom // convertion func i_valraw => i_val -#define i_valto // convertion func i_val* => i_valraw - -#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val -#define i_expandby // default 1. If 2, table expand 2x (else 1.5x) +#define i_key // key type: REQUIRED. +#define i_val // mapped value type: REQUIRED. +#define i_type // container type name (default: cmap_{i_key}) +#define i_hash // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type +#define i_eq // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a + // non-integral type. Three-way i_cmp may alternatively be specified. +#define i_keydrop // destroy key func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw + +#define i_valdrop // destroy value func - defaults to empty destruct +#define i_valclone // REQUIRED IF i_valdrop defined +#define i_valraw // convertion "raw" type - defaults to i_val +#define i_valfrom // convertion func i_valraw => i_val +#define i_valto // convertion func i_val* => i_valraw + +#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cpque_api.md b/docs/cpque_api.md index 5b63dfd1..4cde927b 100644 --- a/docs/cpque_api.md +++ b/docs/cpque_api.md @@ -8,17 +8,17 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai ## Header file and declaration ```c -#define i_type // define type name of the container (default cpque_{i_key}) -#define i_key // value: REQUIRED -#define i_less // compare two i_key* : REQUIRED IF i_key/i_keyraw is a non-integral type -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // cpque container type name +#define i_less // compare two i_key* : REQUIRED IF i_key/i_keyraw is a non-integral type +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // convertion type -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw. +#define i_keyraw // convertion type +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw. -#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key +#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md index b324e5fc..1834baf9 100644 --- a/docs/cqueue_api.md +++ b/docs/cqueue_api.md @@ -7,16 +7,16 @@ See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue ## Header file and declaration ```c -#define i_type // container type name (default: cqueue_{i_key}) -#define i_key // value: REQUIRED -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // cqueue container type name +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw -#define i_tag // alternative typename: cqueue_{i_tag}. i_tag defaults to i_key +#define i_tag // alternative typename: cqueue_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cset_api.md b/docs/cset_api.md index e894ad4f..928d63a8 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -7,19 +7,19 @@ A **cset** is an associative container that contains a set of unique objects of ## Header file and declaration ```c -#define i_type // container type name (default: cset_{i_key}) -#define i_key // hash key: REQUIRED. -#define i_hash // hash func: REQUIRED IF i_keyraw is a non-pod type. -#define i_eq // equality comparison two i_keyraw*: !i_cmp is used if not defined. -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy -#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy - -#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_key -#define i_expandby // default 1. If 2, table expand 2x (else 1.5x) +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // container type name +#define i_hash // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type +#define i_eq // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a + // non-integral type. Three-way i_cmp may alternatively be specified. +#define i_keydrop // destroy key func: defaults to empty destruct +#define i_keyclone // clone func: REQUIRED IF i_keydrop defined + +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy +#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy + +#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 099d7dfc..afaf49f3 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -15,24 +15,24 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo ## Header file and declaration ```c -#define i_type // container type name (default: cmap_{i_key}) -#define i_key // key: REQUIRED -#define i_val // value: REQUIRED -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type - -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_valdrop defined -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw - -#define i_valdrop // destroy value func - defaults to empty destruct -#define i_valclone // REQUIRED IF i_valdrop defined -#define i_valraw // convertion "raw" type - defaults to i_val -#define i_valfrom // convertion func i_valraw => i_val -#define i_valto // convertion func i_val* => i_valraw - -#define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val +#define i_key // key type: REQUIRED. +#define i_val // mapped value type: REQUIRED. +#define i_type // container type name (default: cmap_{i_key}) +#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type + +#define i_keydrop // destroy key func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_valdrop defined +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw + +#define i_valdrop // destroy value func - defaults to empty destruct +#define i_valclone // REQUIRED IF i_valdrop defined +#define i_valraw // convertion "raw" type - defaults to i_val +#define i_valfrom // convertion func i_valraw => i_val +#define i_valto // convertion func i_val* => i_valraw + +#define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/csset_api.md b/docs/csset_api.md index aef3af3c..21e38f61 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -8,17 +8,17 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo ## Header file and declaration ```c -#define i_type // full typename of the container -#define i_key // key: REQUIRED -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type -#define i_keydrop // destroy key func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // container type name +#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type +#define i_keydrop // destroy key func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy -#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy +#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy -#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_key +#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cstack_api.md b/docs/cstack_api.md index e799b152..fb629392 100644 --- a/docs/cstack_api.md +++ b/docs/cstack_api.md @@ -8,16 +8,16 @@ See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack ## Header file and declaration ```c -#define i_type // full typename of the container -#define i_key // value: REQUIRED -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_type // container type name +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw -#define i_tag // alternative typename: cstack_{i_tag}. i_tag defaults to i_key +#define i_tag // alternative typename: cstack_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cvec_api.md b/docs/cvec_api.md index d38ef23f..9cba74b5 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -12,17 +12,18 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect ## Header file and declaration ```c -#define i_type // full typename of the container -#define i_key // value: REQUIRED -#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type -#define i_keydrop // destroy value func - defaults to empty destruct -#define i_keyclone // REQUIRED IF i_keydrop defined - -#define i_keyraw // convertion "raw" type - defaults to i_key -#define i_keyfrom // convertion func i_keyraw => i_key -#define i_keyto // convertion func i_key* => i_keyraw - -#define i_tag // alternative typename: cvec_{i_tag}. i_tag defaults to i_key +#define i_type // container type name +#define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. +#define i_cmp // three-way compare two i_keyraw* +#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_keydrop // destroy value func - defaults to empty destruct +#define i_keyclone // REQUIRED IF i_keydrop defined + +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key +#define i_keyto // convertion func i_key* => i_keyraw + +#define i_tag // alternative typename: cvec_{i_tag}. i_tag defaults to i_key #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 3a5382f3..e4c0915c 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -178,17 +178,22 @@ typedef struct { intptr_t count; } cco_sem; #ifdef _WIN32 #ifdef __cplusplus - #define _c_LINKC extern "C" __declspec(dllimport) + #define _c_LINKC extern "C" __declspec(dllimport) #else - #define _c_LINKC __declspec(dllimport) + #define _c_LINKC __declspec(dllimport) + #endif + #if _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__ + #define _c_getsystime GetSystemTimeAsFileTime + #else + #define _c_getsystime GetSystemTimePreciseAsFileTime #endif struct _FILETIME; - _c_LINKC void GetSystemTimePreciseAsFileTime(struct _FILETIME*); + _c_LINKC void _c_getsystime(struct _FILETIME*); _c_LINKC void Sleep(unsigned long); static inline double cco_time(void) { /* seconds since epoch */ unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */ - GetSystemTimePreciseAsFileTime((struct _FILETIME*)&quad); + _c_getsystime((struct _FILETIME*)&quad); return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */ } diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index 4a227927..1a62c3e1 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -85,6 +85,21 @@ int main(void) if (it.ref == _endref) it.ref = NULL; \ } while (0) +#define c_all_of(boolptr, it, C, cnt, pred) do { \ + C##_iter it; \ + c_find_if_4(it, C, cnt, !(pred)); \ + *(boolptr) = it.ref == NULL; \ +} while (0) +#define c_any_of(boolptr, it, C, cnt, pred) do { \ + C##_iter it; \ + c_find_if_4(it, C, cnt, pred); \ + *(boolptr) = it.ref != NULL; \ +} while (0) +#define c_none_of(boolptr, it, C, cnt, pred) do { \ + C##_iter it; \ + c_find_if_4(it, C, cnt, pred); \ + *(boolptr) = it.ref == NULL; \ +} while (0) // Use with: clist, cmap, cset, csmap, csset: #define c_erase_if(it, C, cnt, pred) do { \ @@ -95,7 +110,6 @@ int main(void) } \ } while (0) - // Use with: cstack, cvec, cdeq, cqueue: #define c_eraseremove_if(it, C, cnt, pred) do { \ C* _cnt = &cnt; \ diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 30ed5732..ccdce718 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -103,7 +103,7 @@ #define i_no_emplace #endif #if c_option(c_native_cmp) - #define i_native_cmp + #define i_cmp_native #endif #if c_option(c_no_clone) || defined _i_carc #define i_no_clone @@ -203,10 +203,10 @@ #endif #ifndef i_no_cmp - #if defined i_cmp || defined i_less || defined i_native_cmp + #if defined i_cmp || defined i_less || defined i_cmp_native #define _i_has_cmp #endif - #if defined i_eq || defined i_native_cmp + #if defined i_eq || defined i_cmp_native #define _i_has_eq #endif @@ -228,7 +228,7 @@ #endif #endif -#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_native_cmp) +#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_cmp_native) #define i_hash c_default_hash #endif diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index def5d01e..351defde 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -67,7 +67,7 @@ #undef i_realloc #undef i_free -#undef i_native_cmp +#undef i_cmp_native #undef i_no_cmp #undef i_no_hash #undef i_no_clone diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c index f6b7f1db..793a0503 100644 --- a/misc/benchmarks/various/csort_bench.c +++ b/misc/benchmarks/various/csort_bench.c @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) { Ints a = Ints_with_capacity(size); for (i = 0; i < size; i++) - *Ints_push(&a, romutrio(s) & (1U << 30) - 1); + Ints_push(&a, romutrio(s) & (1U << 30) - 1); testsort(&a, size, "random"); for (i = 0; i < 20; i++) printf(" %d", (int)*Ints_at(&a, i)); diff --git a/misc/examples/arc_demo.c b/misc/examples/arc_demo.c index 87d64e67..929a48a1 100644 --- a/misc/examples/arc_demo.c +++ b/misc/examples/arc_demo.c @@ -11,7 +11,7 @@ void int_drop(int* x) { #define i_type Arc // set type name to be defined (instead of 'carc_int') #define i_key int #define i_keydrop int_drop // optional, just to display the elements destroyed -#define i_native_cmp // use int comparison (x < y, x == y). +#define i_cmp_native // use int comparison (x < y, x == y). #include // Arc #define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements diff --git a/misc/examples/arcvec_erase.c b/misc/examples/arcvec_erase.c index addef8b7..ba54c1c7 100644 --- a/misc/examples/arcvec_erase.c +++ b/misc/examples/arcvec_erase.c @@ -5,7 +5,7 @@ void show_drop(int* x) { printf("drop: %d\n", *x); } #define i_type Arc #define i_key int #define i_keydrop show_drop -#define i_native_cmp // enable sort/search for int type +#define i_cmp_native // enable sort/search for int type #include // Shared pointer to int #define i_type Vec diff --git a/misc/examples/demos.c b/misc/examples/demos.c index ecc89f2e..1a604d9f 100644 --- a/misc/examples/demos.c +++ b/misc/examples/demos.c @@ -74,7 +74,7 @@ void vectordemo2(void) #define i_key int #define i_tag ix -#define i_native_cmp +#define i_cmp_native #include void listdemo1(void) diff --git a/misc/examples/intrusive.c b/misc/examples/intrusive.c index 4fca654b..c22ed260 100644 --- a/misc/examples/intrusive.c +++ b/misc/examples/intrusive.c @@ -4,7 +4,7 @@ #define i_type List #define i_key int -#define i_native_cmp +#define i_cmp_native #include void printList(List list) { diff --git a/misc/examples/list.c b/misc/examples/list.c index fa33305a..ad8bebb8 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -5,7 +5,7 @@ #define i_type DList #define i_key double -#define i_native_cmp +#define i_cmp_native #include int main(void) { diff --git a/misc/examples/lower_bound.c b/misc/examples/lower_bound.c index e5d816e9..bea828f2 100644 --- a/misc/examples/lower_bound.c +++ b/misc/examples/lower_bound.c @@ -1,7 +1,7 @@ #include #define i_key int -#define i_native_cmp +#define i_cmp_native #include #define i_key int diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index 9676e7b4..2112bf1f 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -27,7 +27,7 @@ int point_cmp(const Point* a, const Point* b) { #include #define i_key float -#define i_native_cmp // use < and == operators for comparison +#define i_cmp_native // use < and == operators for comparison #include void MyStruct_drop(MyStruct* s); diff --git a/misc/examples/new_sptr.c b/misc/examples/new_sptr.c index 7fef5d1f..3c6fa16c 100644 --- a/misc/examples/new_sptr.c +++ b/misc/examples/new_sptr.c @@ -15,7 +15,7 @@ uint64_t Person_hash(const Person* p); #define i_type IPtr #define i_key int #define i_keydrop(x) printf("drop: %d\n", *x) -#define i_native_cmp +#define i_cmp_native #include #define i_type IPStack -- cgit v1.2.3 From f3794f2b86b6f7f85096a0c2e9ca5720aed53300 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 21 Jul 2023 11:22:48 +0200 Subject: Removed c_foreach_rv() - only worked for cvec, so not general. --- README.md | 1 - docs/ccommon_api.md | 3 +-- include/stc/ccommon.h | 4 ---- misc/examples/algorithms/forloops.c | 4 ---- misc/examples/linkedlists/list.c | 4 ++-- 5 files changed, 3 insertions(+), 13 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 6bbe50ee..b49214d4 100644 --- a/README.md +++ b/README.md @@ -640,7 +640,6 @@ STC is generally very memory efficient. Memory usage for the different container - Added new crand.h API & header. Old crandom.h is deprecated. - Added `c_const_cast()` typesafe macro. - Removed RAII macros usage from examples -- Renamed c_foreach_r => `c_foreach_rv` - Renamed c_flt_count(i) => `c_flt_counter(i)` - Renamed c_flt_last(i) => `c_flt_getcount(i)` - Renamed c_ARRAYLEN() => c_arraylen() diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 0752beb5..11d425e5 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -3,13 +3,12 @@ --- ## Ranged for-loops -### c_foreach, c_foreach_rv, c_forpair +### c_foreach, c_forpair | Usage | Description | |:-----------------------------------------|:------------------------------------------| | `c_foreach (it, ctype, container)` | Iteratate all elements | | `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | -| `c_foreach_rv (it, ctype, container)` | Iteratate in reverse (cstack, cvec, cdeq) | | `c_forpair (key, val, ctype, container)` | Iterate with structured binding | ```c diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 316a8ee7..77f754fa 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -191,10 +191,6 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) { for (C##_iter it = start, *_endref = (C##_iter*)(finish).ref \ ; it.ref != (C##_value*)_endref; C##_next(&it)) -#define c_foreach_rv(it, C, cnt) \ - for (C##_iter it = {.ref=C##_end(&cnt).end - 1, .end=(cnt).data - 1} \ - ; it.ref != it.end; --it.ref) - #define c_forpair(key, val, C, cnt) /* structured binding */ \ for (struct {C##_iter it; const C##_key* key; C##_mapped* val;} _ = {.it=C##_begin(&cnt)} \ ; _.it.ref && (_.key = &_.it.ref->first, _.val = &_.it.ref->second) \ diff --git a/misc/examples/algorithms/forloops.c b/misc/examples/algorithms/forloops.c index 300eee18..a83d4a53 100644 --- a/misc/examples/algorithms/forloops.c +++ b/misc/examples/algorithms/forloops.c @@ -41,10 +41,6 @@ int main(void) c_foreach (i, IVec, vec) printf(" %d", *i.ref); - puts("\n\nc_foreach_r: reverse"); - c_foreach_rv (i, IVec, vec) - printf(" %d", *i.ref); - puts("\n\nc_foreach in map:"); c_foreach (i, IMap, map) printf(" (%d %d)", i.ref->first, i.ref->second); diff --git a/misc/examples/linkedlists/list.c b/misc/examples/linkedlists/list.c index 09591314..518cc09b 100644 --- a/misc/examples/linkedlists/list.c +++ b/misc/examples/linkedlists/list.c @@ -12,10 +12,10 @@ int main(void) { const int n = 3000000; DList list = {0}; - crand_t rng = crand_init(1234567); + csrand(1234567); int m = 0; c_forrange (n) - DList_push_back(&list, crand_f64(&rng)*n + 100), ++m; + DList_push_back(&list, crandf()*n + 100), ++m; double sum = 0.0; printf("sumarize %d:\n", m); -- cgit v1.2.3 From e8aed0431140fd0d202d302f19f756046858bad7 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 23 Jul 2023 23:48:00 +0200 Subject: Updated docs. --- README.md | 60 +++--- docs/algorithm_api.md | 434 +++++++++++++++++++++++++++++++++++++++ docs/ccommon_api.md | 557 -------------------------------------------------- docs/cspan_api.md | 11 +- 4 files changed, 470 insertions(+), 592 deletions(-) create mode 100644 docs/algorithm_api.md delete mode 100644 docs/ccommon_api.md (limited to 'README.md') diff --git a/README.md b/README.md index b49214d4..6351fc07 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ STC - Smart Template Containers =============================== -### [Version 4.3 RC3](#version-history) - +### [Version 4.3 Released](#version-history) +- See details for breaking changes. --- Description ----------- @@ -33,10 +33,10 @@ Containers Algorithms ---------- -- [***Ranged for-loops*** - c_foreach, c_forpair, c_forlist](docs/ccommon_api.md#ranged-for-loops) -- [***Range algorithms*** - c_forrange, crange, c_forfilter](docs/ccommon_api.md#range-algorithms) -- [***Generic algorithms*** - c_init, c_find_if, c_erase_if, csort, etc.](docs/ccommon_api.md#generic-algorithms) -- [***Coroutines*** - Simon Tatham's coroutines done right.](docs/ccommon_api.md#coroutines) +- [***Ranged for-loops*** - c_foreach, c_forpair, c_forlist](docs/algorithm_api.md#ranged-for-loops) +- [***Range algorithms*** - c_forrange, crange, c_forfilter](docs/algorithm_api.md#range-algorithms) +- [***Generic algorithms*** - c_init, c_find_if, c_erase_if, csort, etc.](docs/algorithm_api.md#generic-algorithms) +- [***Coroutines*** - ergonomic portable coroutines](docs/coroutine_api.md) - [***Regular expressions*** - Rob Pike's Plan 9 regexp modernized!](docs/cregex_api.md) - [***Random numbers*** - a very fast *PRNG* based on *SFC64*](docs/crandom_api.md) - [***Command line argument parser*** - similar to *getopt()*](docs/coption_api.md) @@ -61,12 +61,11 @@ List of contents --- ## Highlights -- **No boilerplate code** - Specify only the required template parameters, e.g. ***cmp***- and/or ***clone***-, ***drop***- functions, and leave the rest as defaults. +- **Minimal boilerplate code** - Specify only the required template parameters, and leave the rest as defaults. - **Fully type safe** - Because of templating, it avoids error-prone casting of container types and elements back and forth from the containers. -- **User friendly** - Just include the headers and you are good. The API and functionality is very close to c++ STL and is fully listed in the docs. -- **Unparalleled performance** - Maps and sets are much faster than the C++ STL containers, the remaining are similar in speed. +- **High performance** - Unordered maps and sets, queues and deques are significantly faster than the C++ STL containers, the remaining are similar or close to STL in speed (See graph below). - **Fully memory managed** - Containers destructs keys/values via default or user supplied drop function. They may be cloned if element types are clonable. Also, smart pointers are supported and can be stored in containers. See [***carc***](docs/carc_api.md) and [***cbox***](docs/cbox_api.md). -- **Uniform, easy-to-learn API** - Intuitive method/type names and uniform usage across the various containers. +- **Uniform, easy-to-learn API** - Just include the headers and you are good. The API and functionality resembles c++ STL and is fully listed in the docs. Intuitive method/type names and uniform usage across the various containers. - **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed for comparison and calculation is asking for trouble. STC only uses signed numbers in the API for this reason. - **Small footprint** - Small source code and generated executables. The executable from the example below using *four different* container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux. - **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section. @@ -95,17 +94,17 @@ So instead of calling e.g. `cvec_str_push(&vec, cstr_from("Hello"))`, you may ca same element access syntax. E.g.: - `c_foreach (it, MyInts, myints) *it.ref += 42;` works for any container defined as `MyInts` with `int` elements. - - `c_foreach (it, MyInts, it1, it2) *it.ref += 42;` iterates from `it1` up to `it2`. + - `c_foreach (it, MyInts, it1, it2) *it.ref += 42;` iterates from `it1` up to not including `it2`. --- ## Performance STC is a fast and memory efficient library, and code compiles fast: -![Benchmark](misc/benchmarks/pics/benchmark.gif) +![Benchmark](docs/pics/Figure_1.png) Benchmark notes: -- The barchart shows average test times over three platforms: Mingw64 10.30, Win-Clang 12, VC19. CPU: Ryzen 7 2700X CPU @4Ghz. +- The barchart shows average test times over three compilers: **Mingw64 13.1.0, Win-Clang 16.0.5, VC-19-36**. CPU: **Ryzen 7 5700X**. - Containers uses value types `uint64_t` and pairs of `uint64_t` for the maps. - Black bars indicates performance variation between various platforms/compilers. - Iterations are repeated 4 times over n elements. @@ -615,19 +614,20 @@ STC is generally very memory efficient. Memory usage for the different container ## Version 4.3 - Some breaking changes. -- coroutines: much improved with some new API and added features. -- cspan: Support for column-major (fortran order) multidim spans and transposed views. -- Removed default comparison for clist, cvec and cdeq (as with cstack and cqueue). - - Using i_key_str, i_keyclass, i_keyboxed still expects comparisons defined. - - Define i_cmp_native to enable built-in i_key types comparisons (<, ==). -- cstr and csview are now shared linked by default. Static linking by defining i_static. -- New cdeq and cqueue implementation(s), using circular buffer. -- Renamed i_extern => i_import. - - Define i_import before #include will also define utf8 case conversions. - - Define i_import before #include will also define cstr + utf8 tables. -- Renamed c_make() => c_init() macro for initialization lists. -- Renamed input enum flags for cregex functions. -- Removed deprecated crandom.h. Use crand.h with new API. +- **coroutines**: much improved with some new API and added features. +- **cspan**: Rewritten to add support for **column-major** order (fortran) multidim spans and transposed views. +- Removed default comparison for **clist**, **cvec** and **cdeq** (like cstack and cqueue). + - Define `i_cmp_native` to enable built-in i_key types comparisons (<, ==). + - Use of `i_keyclass` still expects comparison functions defined. + - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined. +- **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. +- All new faster and smaller **cqueue** and **cdeq** implementations, using a circular buffer. +- Renamed i_extern => `i_import`. + - Define `i_import` before `#include ` will also define utf8 case conversions. + - Define `i_import` before `#include ` will also define cstr + utf8 tables. +- Renamed c_make() => ***c_init()*** macro for initializing containers with element lists. +- Renamed input enum flags for ***cregex***-functions. +- Removed deprecated . Use `` with the new API. - Removed deprecated uppercase flow-control macro names. - Improved default string hash function. @@ -653,8 +653,8 @@ Major changes: - Customizable allocator [per templated container type](https://github.com/tylov/STC/discussions/44#discussioncomment-4891925). - Updates on **cregex** with several [new unicode character classes](docs/cregex_api.md#regex-cheatsheet). - Algorithms: - - [crange](docs/ccommon_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - - [c_forfilter](docs/ccommon_api.md#c_forfilter) - ranges-like view filtering. + - [crange](docs/algorithm_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. + - [c_forfilter](docs/algorithm_api.md#c_forfilter) - ranges-like view filtering. - [csort](include/stc/algo/sort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. - Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. - Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. @@ -715,10 +715,10 @@ Major changes: - Renamed: *csptr_X_make()* to `carc_X_from()`. - Renamed: *cstr_new()* to `cstr_lit(literal)`, and *cstr_assign_fmt()* to `cstr_printf()`. - Renamed: *c_default_fromraw()* to `c_default_from()`. -- Changed: the [**c_apply**](docs/ccommon_api.md) macros API. +- Changed: the [**c_apply**](docs/algorithm_api.md) macros API. - Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`. - Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly. - Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions. - Added: `i_opt` template parameter: compile-time options: `c_no_cmp`, `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` - Added: [**cbox**](docs/cbox_api.md) type: smart pointer, similar to [Rust Box](https://doc.rust-lang.org/rust-by-example/std/box.html) and [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr). -- Added: [**c_forpair**](docs/ccommon_api.md) macro: for-loop with "structured binding" +- Added: [**c_forpair**](docs/algorithm_api.md) macro: for-loop with "structured binding" diff --git a/docs/algorithm_api.md b/docs/algorithm_api.md new file mode 100644 index 00000000..490771b5 --- /dev/null +++ b/docs/algorithm_api.md @@ -0,0 +1,434 @@ +# STC Algorithms + +"No raw loops" - Sean Parent +## Ranged for-loops + +### c_foreach, c_forpair +```c +#include +``` + +| Usage | Description | +|:-----------------------------------------|:------------------------------------------| +| `c_foreach (it, ctype, container)` | Iteratate all elements | +| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | +| `c_forpair (key, val, ctype, container)` | Iterate with structured binding | + +```c +#define i_key int +#define i_val int +#define i_tag ii +#include +... +csmap_ii map = c_init(csmap_ii, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} }); + +c_foreach (i, csmap_ii, map) + printf(" %d", i.ref->first); +// 3 5 7 12 23 +// same without using c_foreach: +for (csmap_ii_iter i = csmap_ii_begin(&map); i.ref; csmap_ii_next(&i)) + printf(" %d", i.ref->first); + +csmap_ii_iter it = csmap_ii_find(&map, 7); +// iterate from it to end +c_foreach (i, csmap_ii, it, csmap_ii_end(&map)) + printf(" %d", i.ref->first); +// 7 12 23 + +// structured binding: +c_forpair (id, count, csmap_ii, map) + printf(" (%d %d)", *_.id, *_.count); +// (3 2) (5 4) (7 3) (12 5) (23 1) +``` + +### c_forlist +Iterate compound literal array elements. Additional to `i.ref`, you can access `i.size` and `i.index` for the input list/element. +```c +// apply multiple push_backs +c_forlist (i, int, {1, 2, 3}) + cvec_i_push_back(&vec, *i.ref); + +// insert in existing map +c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) + cmap_ii_insert(&map, i.ref->first, i.ref->second); + +// string literals pushed to a stack of cstr: +c_forlist (i, const char*, {"Hello", "crazy", "world"}) + cstack_str_emplace(&stk, *i.ref); +``` +--- + +## Integer range loops + +### c_forrange +Abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop. + +| Usage | Python equivalent | +|:---------------------------------------------|:-------------------------------------| +| `c_forrange (stop)` | `for _ in range(stop):` | +| `c_forrange (i, stop) // i type = long long` | `for i in range(stop):` | +| `c_forrange (i, start, stop)` | `for i in range(start, stop):` | +| `c_forrange (i, start, stop, step)` | `for i in range(start, stop, step):` | + +```c +c_forrange (5) printf("x"); +// xxxxx +c_forrange (i, 5) printf(" %lld", i); +// 0 1 2 3 4 +c_forrange (i, -3, 3) printf(" %lld", i); +// -3 -2 -1 0 1 2 +c_forrange (i, 30, 0, -5) printf(" %lld", i); +// 30 25 20 15 10 5 +``` + +### crange: Integer range generator object +A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: +```c +crange crange_init(stop); // will generate 0, 1, ..., stop-1 +crange crange_init(start, stop); // will generate start, start+1, ... stop-1 +crange crange_init(start, stop, step); // will generate start, start+step, ... upto-not-including stop + // note that step may be negative. +crange_iter crange_begin(crange* self); +crange_iter crange_end(crange* self); +void crange_next(crange_iter* it); + +// 1. All primes less than 32: +crange r1 = crange_init(3, 32, 2); +printf("2"); // first prime +c_forfilter (i, crange, r1, isPrime(*i.ref)) + printf(" %lld", *i.ref); +// 2 3 5 7 11 13 17 19 23 29 31 + +// 2. The first 11 primes: +printf("2"); +crange range = crange_init(3, INT64_MAX, 2); +c_forfilter (i, crange, range, + isPrime(*i.ref) && + c_flt_take(10) +){ + printf(" %lld", *i.ref); +} +// 2 3 5 7 11 13 17 19 23 29 31 +``` + +### c_forfilter +Iterate a container or a crange with chained `&&` filtering. + +| Usage | Description | +|:----------------------------------------------------|:---------------------------------------| +| `c_forfilter (it, ctype, container, filter)` | Filter out items in chain with && | +| `c_forfilter_it (it, ctype, startit, filter)` | Filter from startit iterator position | + +| Built-in filter | Description | +|:----------------------------------|:-------------------------------------------| +| `c_flt_skip(it, numItems)` | Skip numItems (inc count) | +| `c_flt_take(it, numItems)` | Take numItems (inc count) | +| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false | +| `c_flt_takewhile(it, predicate)` | Take items until predicate is false | +| `c_flt_counter(it)` | Increment current and return count | +| `c_flt_getcount(it)` | Number of items passed skip*/take*/counter | + +[ [Run this example](https://godbolt.org/z/n9aYrYPv8) ] +```c +#include +#include + +bool isPrime(long long i) { + for (long long j=2; j*j <= i; ++j) + if (i % j == 0) return false; + return true; +} + +int main(void) { + // Get 10 prime numbers starting from 1000. Skip the first 15 primes, + // then select every 25th prime (including the initial). + crange R = crange_init(1001, INT64_MAX, 2); // 1001, 1003, ... + + c_forfilter (i, crange, R, + isPrime(*i.ref) && + c_flt_skip(i, 15) && + c_flt_counter(i) % 25 == 1 && + c_flt_take(i, 10) + ){ + printf(" %lld", *i.ref); + } +} +// out: 1097 1289 1481 1637 1861 2039 2243 2417 2657 2803 +``` +Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false. + +--- +## Generic algorithms + +### c_init, c_drop + +Make any container from an initializer list: +```c +#define i_key_str // owned cstr string value type +#include + +#define i_key int +#define i_val int +#include +... +// Initializes with const char*, internally converted to cstr! +cset_str myset = c_init(cset_str, {"This", "is", "the", "story"}); + +int x = 7, y = 8; +cmap_int mymap = c_init(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); +``` +Drop multiple containers of the same type: +```c +c_drop(cset_str, &myset, &myset2); +``` + +### c_find_if, c_erase_if, c_eraseremove_if +Find or erase linearily in containers using a predicate +- For `c_find_if(iter, C, c, pred)`, ***iter*** is in/out and must be declared prior to call. +- Use `c_erase_if(iter, C, c, pred)` with **clist**, **cmap**, **cset**, **csmap**, and **csset**. +- Use `c_eraseremove_if(iter, C, c, pred)` with **cstack**, **cvec**, **cdeq**, and **cqueue**. +```c +// Search vec for first value > 2: +cvec_i_iter i; +c_find_if(i, cvec_i, vec, *i.ref > 2); +if (i.ref) printf("%d\n", *i.ref); + +// Erase all values > 2 in vec: +c_eraseremove_if(i, cvec_i, vec, *i.ref > 2); + +// Search map for a string containing "hello" and erase it: +cmap_str_iter it, it1 = ..., it2 = ...; +c_find_if(it, csmap_str, it1, it2, cstr_contains(it.ref, "hello")); +if (it.ref) cmap_str_erase_at(&map, it); + +// Erase all strings containing "hello" in a sorted map: +c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello")); +``` + +### sort_n_ - two times faster qsort + +The **sort_n**, **sort_ij** algorithm is about twice as fast as *qsort()*, and often simpler to use. +You may customize `i_tag` and the comparison function `i_cmp` or `i_less`. + +There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c). +```c +#define i_key int +#include +#include + +int main(void) { + int nums[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}; + ints_sort_n(nums, c_arraylen(nums)); // note: function name derived from i_key + c_forrange (i, c_arraylen(arr)) printf(" %d", arr[i]); +} +``` +Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is +possible and very fast. Note that `i_more` must be defined to retain specified template parameters for use by sort: +```c +#define i_type MyDeq +#define i_key int +#define i_more +#include // deque +#include +#include + +int main(void) { + MyDeq deq = c_init(MyDeq, {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}); + MyDeq_sort_n(&deq, MyDeq_size(&deq)); + c_foreach (i, MyDeq, deq) printf(" %d", *i.ref); + MyDeq_drop(&deq); +} +``` + +### c_new, c_delete + +- `c_new(Type, val)` - Allocate *and init* a new object on the heap +- `c_delete(Type, ptr)` - Drop *and free* an object allocated on the heap. NULL is OK. +```c +#include + +cstr *str_p = c_new(cstr, cstr_from("Hello")); +printf("%s\n", cstr_str(str_p)); +c_delete(cstr, str_p); +``` + +### c_malloc, c_calloc, c_realloc, c_free +Memory allocator wrappers that uses signed sizes. + +### c_arraylen +Return number of elements in an array. array must not be a pointer! +```c +int array[] = {1, 2, 3, 4}; +intptr_t n = c_arraylen(array); +``` + +### c_swap, c_const_cast +```c +// Safe macro for swapping internals of two objects of same type: +c_swap(cmap_int, &map1, &map2); + +// Type-safe casting a from const (pointer): +const char cs[] = "Hello"; +char* s = c_const_cast(char*, cs); // OK +int* ip = c_const_cast(int*, cs); // issues a warning! +``` + +### Predefined template parameter functions + +**crawstr** - Non-owned `const char*` "class" element type: `#define i_keyclass crawstr` +```c +typedef const char* crawstr; +int crawstr_cmp(const crawstr* x, const crawstr* y); +bool crawstr_eq(const crawstr* x, const crawstr* y); +uint64_t crawstr_hash(const crawstr* x); +``` +Default implementations +```c +int c_default_cmp(const Type*, const Type*); // <=> +bool c_default_less(const Type*, const Type*); // < +bool c_default_eq(const Type*, const Type*); // == +uint64_t c_default_hash(const Type*); +Type c_default_clone(Type val); // return val +Type c_default_toraw(const Type* p); // return *p +void c_default_drop(Type* p); // does nothing +``` +--- +## RAII scope macros +General ***defer*** mechanics for resource acquisition. These macros allows you to specify the +freeing of the resources at the point where the acquisition takes place. +The **checkauto** utility described below, ensures that the `c_auto*` macros are used correctly. + +| Usage | Description | +|:---------------------------------------|:----------------------------------------------------------| +| `c_defer (drop...)` | Defer `drop...` to end of scope | +| `c_scope (init, drop)` | Execute `init` and defer `drop` to end of scope | +| `c_scope (init, pred, drop)` | Adds a predicate in order to exit early if init failed | +| `c_with (Type var=init, drop)` | Declare `var`. Defer `drop...` to end of scope | +| `c_with (Type var=init, pred, drop)` | Adds a predicate in order to exit early if init failed | +| `c_auto (Type, var1,...,var4)` | `c_with (Type var1=Type_init(), Type_drop(&var1))` ... | +| `continue` | Exit a defer-block without resource leak | + +```c +#include // or +... +// `c_defer` executes the expression(s) when leaving scope. +// Note: does not require inclusion of "raii.h". +cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); +c_defer (cstr_drop(&s1), cstr_drop(&s2)) +{ + printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); +} + +// `c_scope` syntactically "binds" initialization and defer. +static pthread_mutex_t mut; +c_scope (pthread_mutex_lock(&mut), pthread_mutex_unlock(&mut)) +{ + /* Do syncronized work. */ +} + +// `c_with` is similar to python `with`: declare a variable and defer the drop call. +c_with (cstr str = cstr_lit("Hello"), cstr_drop(&str)) +{ + cstr_append(&str, " world"); + printf("%s\n", cstr_str(&str)); +} + +// `c_auto` automatically initialize and drops up to 4 variables: +c_auto (cstr, s1, s2) +{ + cstr_append(&s1, "Hello"); + cstr_append(&s1, " world"); + cstr_append(&s2, "Cool"); + cstr_append(&s2, " stuff"); + printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); +} +``` +**Example 1**: Use multiple **c_with** in sequence: +```c +bool ok = false; +c_with (uint8_t* buf = malloc(BUF_SIZE), buf != NULL, free(buf)) +c_with (FILE* fp = fopen(fname, "rb"), fp != NULL, fclose(fp)) +{ + int n = fread(buf, 1, BUF_SIZE, fp); + if (n <= 0) continue; // auto cleanup! NB do not break or return here. + ... + ok = true; +} +return ok; +``` +**Example 2**: Load each line of a text file into a vector of strings: +```c +#include +#define i_implement +#include + +#define i_key_str +#include + +// receiver should check errno variable +cvec_str readFile(const char* name) +{ + cvec_str vec = {0}; // returned + c_with (FILE* fp = fopen(name, "r"), fp != NULL, fclose(fp)) + c_with (cstr line = {0}, cstr_drop(&line)) + while (cstr_getline(&line, fp)) + cvec_str_emplace(&vec, cstr_str(&line)); + return vec; +} + +int main(void) +{ + c_with (cvec_str vec = readFile(__FILE__), cvec_str_drop(&vec)) + c_foreach (i, cvec_str, vec) + printf("| %s\n", cstr_str(i.ref)); +} +``` + +### The **checkauto** utility program (for RAII) +The **checkauto** program will check the source code for any misuses of the `c_auto*` macros which +may lead to resource leakages. The `c_auto*`- macros are implemented as one-time executed **for-loops**, +so any `return` or `break` appearing within such a block will lead to resource leaks, as it will disable +the cleanup/drop method to be called. A `break` may originally be intended to break a loop or switch +outside the `c_auto` scope. + +NOTE: One must always make sure to unwind temporary allocated resources before a `return` in C. However, by using `c_auto*`-macros, +- it is much easier to automatically detect misplaced return/break between resource acquisition and destruction. +- it prevents forgetting to call the destructor at the end. + +The **checkauto** utility will report any misusages. The following example shows how to correctly break/return +from a `c_auto` scope: +```c +int flag = 0; +for (int i = 0; i 0) break; + ... +} +``` diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md deleted file mode 100644 index 0e8d9719..00000000 --- a/docs/ccommon_api.md +++ /dev/null @@ -1,557 +0,0 @@ -# STC Algorithms - ---- -## Ranged for-loops - -### c_foreach, c_forpair - -| Usage | Description | -|:-----------------------------------------|:------------------------------------------| -| `c_foreach (it, ctype, container)` | Iteratate all elements | -| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | -| `c_forpair (key, val, ctype, container)` | Iterate with structured binding | - -```c -#define i_key int -#define i_val int -#define i_tag ii -#include -... -csmap_ii map = c_init(csmap_ii, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} }); - -c_foreach (i, csmap_ii, map) - printf(" %d", i.ref->first); -// 3 5 7 12 23 -// same without using c_foreach: -for (csmap_ii_iter i = csmap_ii_begin(&map); i.ref; csmap_ii_next(&i)) - printf(" %d", i.ref->first); - -csmap_ii_iter it = csmap_ii_find(&map, 7); -// iterate from it to end -c_foreach (i, csmap_ii, it, csmap_ii_end(&map)) - printf(" %d", i.ref->first); -// 7 12 23 - -// structured binding: -c_forpair (id, count, csmap_ii, map) - printf(" (%d %d)", *_.id, *_.count); -// (3 2) (5 4) (7 3) (12 5) (23 1) -``` - -### c_forlist -Iterate compound literal array elements. Additional to `i.ref`, you can access `i.size` and `i.index` for the input list/element. -```c -// apply multiple push_backs -c_forlist (i, int, {1, 2, 3}) - cvec_i_push_back(&vec, *i.ref); - -// insert in existing map -c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) - cmap_ii_insert(&map, i.ref->first, i.ref->second); - -// string literals pushed to a stack of cstr: -c_forlist (i, const char*, {"Hello", "crazy", "world"}) - cstack_str_emplace(&stk, *i.ref); -``` - ---- -## Range algorithms - -### c_forrange -Abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop. - -| Usage | Python equivalent | -|:---------------------------------------------|:-------------------------------------| -| `c_forrange (stop)` | `for _ in range(stop):` | -| `c_forrange (i, stop) // i type = long long` | `for i in range(stop):` | -| `c_forrange (i, start, stop)` | `for i in range(start, stop):` | -| `c_forrange (i, start, stop, step)` | `for i in range(start, stop, step):` | - -```c -c_forrange (5) printf("x"); -// xxxxx -c_forrange (i, 5) printf(" %lld", i); -// 0 1 2 3 4 -c_forrange (i, -3, 3) printf(" %lld", i); -// -3 -2 -1 0 1 2 -c_forrange (i, 30, 0, -5) printf(" %lld", i); -// 30 25 20 15 10 5 -``` - -### crange -A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: -```c -crange crange_init(stop); // will generate 0, 1, ..., stop-1 -crange crange_init(start, stop); // will generate start, start+1, ... stop-1 -crange crange_init(start, stop, step); // will generate start, start+step, ... upto-not-including stop - // note that step may be negative. -crange_iter crange_begin(crange* self); -crange_iter crange_end(crange* self); -void crange_next(crange_iter* it); - -// 1. All primes less than 32: -crange r1 = crange_init(3, 32, 2); -printf("2"); // first prime -c_forfilter (i, crange, r1, isPrime(*i.ref)) - printf(" %lld", *i.ref); -// 2 3 5 7 11 13 17 19 23 29 31 - -// 2. The first 11 primes: -printf("2"); -crange range = crange_init(3, INT64_MAX, 2); -c_forfilter (i, crange, range, - isPrime(*i.ref) && - c_flt_take(10) -){ - printf(" %lld", *i.ref); -} -// 2 3 5 7 11 13 17 19 23 29 31 -``` - -### c_forfilter -Iterate a container/range with chained range filtering. - -| Usage | Description | -|:----------------------------------------------------|:---------------------------------------| -| `c_forfilter (it, ctype, container, filter)` | Filter out items in chain with && | -| `c_forfilter_it (it, ctype, startit, filter)` | Filter from startit position | - -| Built-in filter | Description | -|:----------------------------------|:-------------------------------------------| -| `c_flt_skip(it, numItems)` | Skip numItems (inc count) | -| `c_flt_take(it, numItems)` | Take numItems (inc count) | -| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false | -| `c_flt_takewhile(it, predicate)` | Take items until predicate is false | -| `c_flt_counter(it)` | Increment current and return count | -| `c_flt_getcount(it)` | Number of items passed skip*/take*/counter | - -[ [Run this example](https://godbolt.org/z/n9aYrYPv8) ] -```c -#include -#include - -bool isPrime(long long i) { - for (long long j=2; j*j <= i; ++j) - if (i % j == 0) return false; - return true; -} - -int main(void) { - // Get 10 prime numbers starting from 1000. Skip the first 15 primes, - // then select every 25th prime (including the initial). - crange R = crange_init(1001, INT64_MAX, 2); // 1001, 1003, ... - - c_forfilter (i, crange, R, - isPrime(*i.ref) && - c_flt_skip(i, 15) && - c_flt_counter(i) % 25 == 1 && - c_flt_take(i, 10) - ){ - printf(" %lld", *i.ref); - } -} -// out: 1097 1289 1481 1637 1861 2039 2243 2417 2657 2803 -``` -Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false. - ---- -## Generic algorithms - -### c_init, c_drop - -Make any container from an initializer list: -```c -#define i_key_str // owned cstr string value type -#include - -#define i_key int -#define i_val int -#include -... -// Initializes with const char*, internally converted to cstr! -cset_str myset = c_init(cset_str, {"This", "is", "the", "story"}); - -int x = 7, y = 8; -cmap_int mymap = c_init(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); -``` -Drop multiple containers of the same type: -```c -c_drop(cset_str, &myset, &myset2); -``` - -### c_find_if, c_erase_if, c_eraseremove_if -Find or erase linearily in containers using a predicate -- For `c_find_if(iter, C, c, pred)`, ***iter*** is in/out and must be declared prior to call. -- Use `c_erase_if(iter, C, c, pred)` with **clist**, **cmap**, **cset**, **csmap**, and **csset**. -- Use `c_eraseremove_if(iter, C, c, pred)` with **cstack**, **cvec**, **cdeq**, and **cqueue**. -```c -// Search vec for first value > 2: -cvec_i_iter i; -c_find_if(i, cvec_i, vec, *i.ref > 2); -if (i.ref) printf("%d\n", *i.ref); - -// Erase all values > 2 in vec: -c_eraseremove_if(i, cvec_i, vec, *i.ref > 2); - -// Search map for a string containing "hello" and erase it: -cmap_str_iter it, it1 = ..., it2 = ...; -c_find_if(it, csmap_str, it1, it2, cstr_contains(it.ref, "hello")); -if (it.ref) cmap_str_erase_at(&map, it); - -// Erase all strings containing "hello" in a sorted map: -c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello")); -``` - -### sort_n_ - two times faster qsort - -The **sort_n**, **sort_ij** algorithm is about twice as fast as *qsort()*, and often simpler to use. -You may customize `i_tag` and the comparison function `i_cmp` or `i_less`. - -There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c). -```c -#define i_key int -#include -#include - -int main(void) { - int nums[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}; - intarray_sort_n(nums, c_arraylen(nums)); - c_forrange (i, c_arraylen(arr)) printf(" %d", arr[i]); -} -``` -Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is -possible and very fast. Note that `i_more` must be defined to retain specified template parameters for use by sort: -```c -#define i_type MyDeq -#define i_key int -#define i_more -#include // deque -#include -#include - -int main(void) { - MyDeq deq = c_init(MyDeq, {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}); - MyDeq_sort_n(&deq, MyDeq_size(&deq)); - c_foreach (i, MyDeq, deq) printf(" %d", *i.ref); - MyDeq_drop(&deq); -} -``` - -### c_new, c_delete - -- `c_new(Type, val)` - Allocate *and init* a new object on the heap -- `c_delete(Type, ptr)` - Drop *and free* an object allocated on the heap. NULL is OK. -```c -#include - -cstr *str_p = c_new(cstr, cstr_from("Hello")); -printf("%s\n", cstr_str(str_p)); -c_delete(cstr, str_p); -``` - -### c_malloc, c_calloc, c_realloc, c_free -Memory allocator wrappers that uses signed sizes. - -### c_arraylen -Return number of elements in an array. array must not be a pointer! -```c -int array[] = {1, 2, 3, 4}; -intptr_t n = c_arraylen(array); -``` - -### c_swap, c_const_cast -```c -// Safe macro for swapping internals of two objects of same type: -c_swap(cmap_int, &map1, &map2); - -// Type-safe casting a from const (pointer): -const char cs[] = "Hello"; -char* s = c_const_cast(char*, cs); // OK -int* ip = c_const_cast(int*, cs); // issues a warning! -``` - -### Predefined template parameter functions - -**crawstr** - Non-owned `const char*` "class" element type: `#define i_keyclass crawstr` -```c -typedef const char* crawstr; -int crawstr_cmp(const crawstr* x, const crawstr* y); -bool crawstr_eq(const crawstr* x, const crawstr* y); -uint64_t crawstr_hash(const crawstr* x); -``` -Default implementations -```c -int c_default_cmp(const Type*, const Type*); // <=> -bool c_default_less(const Type*, const Type*); // < -bool c_default_eq(const Type*, const Type*); // == -uint64_t c_default_hash(const Type*); -Type c_default_clone(Type val); // return val -Type c_default_toraw(const Type* p); // return *p -void c_default_drop(Type* p); // does nothing -``` - ---- -## Coroutines -This is a much improved implementation of -[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html), -which utilizes the *Duff's device* trick. Tatham's implementation is not typesafe, -and it always allocates the coroutine's internal state dynamically. But crucially, -it does not let the coroutine do self-cleanup on early finish - i.e. it -only frees the initial dynamically allocated memory. - -In this implementation, a coroutine may have any signature, but it should -take a struct pointer as parameter, which must contain the member `int cco_state;` -The struct should normally store all the *local* variables to be used in the -coroutine. It can also store input and output data if desired. - -The coroutine example below generates Pythagorian triples, but the calling loop -skips the triples which are upscaled version of smaller ones, by checking -the gcd() function. It also ensures that it stops when the diagonal size >= 100: - -[ [Run this code](https://godbolt.org/z/coqqrfbd5) ] -```c -#include -#include - -struct triples { - int n; // input: max number of triples to be generated. - int a, b, c; - int cco_state; // required member -}; - -int triples(struct triples* i) { // coroutine - cco_routine(i) { - for (i->c = 5; i->n; ++i->c) { - for (i->a = 1; i->a < i->c; ++i->a) { - for (i->b = i->a + 1; i->b < i->c; ++i->b) { - if ((int64_t)i->a*i->a + (int64_t)i->b*i->b == (int64_t)i->c*i->c) { - cco_yield(); - if (--i->n == 0) - cco_return; - } - } - } - } - cco_cleanup: - puts("done"); - } - return 0; -} - -int gcd(int a, int b) { // greatest common denominator - while (b) { - int t = a % b; - a = b; - b = t; - } - return a; -} - -int main(void) -{ - struct triples t = {.n=INT32_MAX}; - int n = 0; - - while (triples(&t)) { - // Skip triples with GCD(a,b) > 1 - if (gcd(t.a, t.b) > 1) - continue; - - // Stop when c >= 100 - if (t.c < 100) - printf("%d: [%d, %d, %d]\n", ++n, t.a, t.b, t.c); - else - cco_stop(&t); // cleanup in next coroutine call/resume - } -} -``` -### Coroutine API -To resume the coroutine from where it was suspended with *cco_yield()*: call the coroutine again. - -**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement from a -cco_routine scope; Use `if-else-if` constructs instead. - -| | Function / operator | Description | -|:----------|:-------------------------------------|:----------------------------------------| -|`cco_result` | `CCO_DONE`, `CCO_AWAIT`, `CCO_YIELD` | Default set of return values from coroutines | -| | `cco_cleanup:` | Label for cleanup position in coroutine | -| `bool` | `cco_done(co)` | Is coroutine done? | -| | `cco_routine(co) {}` | The coroutine scope | -| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)| -| | `cco_yield_v(ret);` | Yield/suspend execution (return ret) | -| | `cco_yield_final();` | Yield final suspend, enter cleanup-state | -| | `cco_yield_final(ret);` | Yield a final value | -| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| -| | `cco_call_await(cocall);` | Await for subcoro to finish (returns its ret value) | -| | `cco_call_await(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) | -| | `cco_return;` | Return from coroutine (inside cco_routine) | -| | Task objects: | | -| | `cco_task_struct(Name, ...);` | Define a coroutine task struct | -| | `cco_task_await(task, cco_runtime* rt);`| Await for task to finish | -| | `cco_task_await(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) | -|`cco_result`| `cco_task_resume(task, rt);` | Resume suspended task | -| | Semaphores: | | -| | `cco_sem` | Semaphore type | -| `cco_sem` | `cco_sem_from(long value)` | Create semaphore | -| | `cco_sem_set(sem, long value)` | Set semaphore value | -| | `cco_sem_await(sem)` | Await for the semaphore count > 0 | -| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | -| | Timers: | | -| | `cco_timer` | Timer type | -| | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)| -| | `cco_timer_start(tm, double sec)` | Start timer for secs duration | -| | `cco_timer_restart(tm)` | Restart timer with same duration | -| `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | -| `double` | `cco_timer_elapsed(tm)` | Return seconds elapsed | -| `double` | `cco_timer_remaining(tm)` | Return seconds remaining | -| | From caller side: | | -| `void` | `cco_stop(co)` | Next call of coroutine finalizes | -| `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_call_blocking(cocall) {}` | Run blocking until cocall is finished | -| `void` | `cco_call_blocking(cocall, int* outres) {}`| Run blocking until cocall is finished | -| | `cco_task_blocking(task) {}` | Run blocking until task is finished | -| | `cco_task_blocking(task, rt, STACKSZ) {}`| Run blocking until task is finished | -| | Time functions: | | -| `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | -| | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | - ---- -## RAII scope macros -General ***defer*** mechanics for resource acquisition. These macros allows you to specify the -freeing of the resources at the point where the acquisition takes place. -The **checkauto** utility described below, ensures that the `c_auto*` macros are used correctly. - -| Usage | Description | -|:---------------------------------------|:----------------------------------------------------------| -| `c_defer (drop...)` | Defer `drop...` to end of scope | -| `c_scope (init, drop)` | Execute `init` and defer `drop` to end of scope | -| `c_scope (init, pred, drop)` | Adds a predicate in order to exit early if init failed | -| `c_with (Type var=init, drop)` | Declare `var`. Defer `drop...` to end of scope | -| `c_with (Type var=init, pred, drop)` | Adds a predicate in order to exit early if init failed | -| `c_auto (Type, var1,...,var4)` | `c_with (Type var1=Type_init(), Type_drop(&var1))` ... | -| `continue` | Exit a defer-block without resource leak | - -```c -#include // or -... -// `c_defer` executes the expression(s) when leaving scope. -// Note: does not require inclusion of "raii.h". -cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); -c_defer (cstr_drop(&s1), cstr_drop(&s2)) -{ - printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); -} - -// `c_scope` syntactically "binds" initialization and defer. -static pthread_mutex_t mut; -c_scope (pthread_mutex_lock(&mut), pthread_mutex_unlock(&mut)) -{ - /* Do syncronized work. */ -} - -// `c_with` is similar to python `with`: declare a variable and defer the drop call. -c_with (cstr str = cstr_lit("Hello"), cstr_drop(&str)) -{ - cstr_append(&str, " world"); - printf("%s\n", cstr_str(&str)); -} - -// `c_auto` automatically initialize and drops up to 4 variables: -c_auto (cstr, s1, s2) -{ - cstr_append(&s1, "Hello"); - cstr_append(&s1, " world"); - cstr_append(&s2, "Cool"); - cstr_append(&s2, " stuff"); - printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); -} -``` -**Example 1**: Use multiple **c_with** in sequence: -```c -bool ok = false; -c_with (uint8_t* buf = malloc(BUF_SIZE), buf != NULL, free(buf)) -c_with (FILE* fp = fopen(fname, "rb"), fp != NULL, fclose(fp)) -{ - int n = fread(buf, 1, BUF_SIZE, fp); - if (n <= 0) continue; // auto cleanup! NB do not break or return here. - ... - ok = true; -} -return ok; -``` -**Example 2**: Load each line of a text file into a vector of strings: -```c -#include -#define i_implement -#include - -#define i_key_str -#include - -// receiver should check errno variable -cvec_str readFile(const char* name) -{ - cvec_str vec = {0}; // returned - c_with (FILE* fp = fopen(name, "r"), fp != NULL, fclose(fp)) - c_with (cstr line = {0}, cstr_drop(&line)) - while (cstr_getline(&line, fp)) - cvec_str_emplace(&vec, cstr_str(&line)); - return vec; -} - -int main(void) -{ - c_with (cvec_str vec = readFile(__FILE__), cvec_str_drop(&vec)) - c_foreach (i, cvec_str, vec) - printf("| %s\n", cstr_str(i.ref)); -} -``` - -### The **checkauto** utility program (for RAII) -The **checkauto** program will check the source code for any misuses of the `c_auto*` macros which -may lead to resource leakages. The `c_auto*`- macros are implemented as one-time executed **for-loops**, -so any `return` or `break` appearing within such a block will lead to resource leaks, as it will disable -the cleanup/drop method to be called. A `break` may originally be intended to break a loop or switch -outside the `c_auto` scope. - -NOTE: One must always make sure to unwind temporary allocated resources before a `return` in C. However, by using `c_auto*`-macros, -- it is much easier to automatically detect misplaced return/break between resource acquisition and destruction. -- it prevents forgetting to call the destructor at the end. - -The **checkauto** utility will report any misusages. The following example shows how to correctly break/return -from a `c_auto` scope: -```c -int flag = 0; -for (int i = 0; i 0) break; - ... -} -``` diff --git a/docs/cspan_api.md b/docs/cspan_api.md index e1c92bbf..1312ae6d 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -21,10 +21,11 @@ using_cspan4(S, ValueType); // define span types S, S2, S3, S4 with ``` ## Methods -All functions are type-safe. Note that the span argument itself is generally not side-effect safe, -i.e., it may be expanded multiple times. However, all index arguments are safe, e.g. -`cspan_at(&ms3, i++, j++, k++)` is allowed. If the number of arguments does not match the span rank, -a compile error is issued. Runtime bounds checks are enabled by default (define `STC_NDEBUG` or `NDEBUG` to disable). +All functions are type-safe. NOTE: the span argument itself is generally **not** side-effect safe - +it may be expanded multiple times. However, all index arguments are safe, e.g. +`cspan_at(&ms3, i++, j++, k++)` is safe, but `cspan_at(&spans[n++], i, j)` is an error! If the number +of arguments does not match the span rank, a compile error is issued. Runtime bounds checks are enabled +by default (define `STC_NDEBUG` or `NDEBUG` to disable). ```c SpanType cspan_init(TYPE SpanType, {v1, v2, ...}); // make a 1-d cspan from values SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from a cvec, cstack, cpque (heap) @@ -45,7 +46,7 @@ void SpanType_next(SpanTypeN_iter* it); SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // make a multi-dim cspan, row-major order. SpanTypeN cspan_md_order(char order, ValueType* data, d1, d2, ...); // order='C': row-major, 'F': column-major (FORTRAN). - // transpose a md span (inverse axes). no changes to the underlying array. + // transpose a md span (inverse axes). No changes to the underlying array. void cspan_transpose(const SpanTypeN* self); bool cspan_is_order_F(const SpanTypeN* self); -- cgit v1.2.3 From e4c169a66c3d55a4d0d3407f47102e54d289a3fb Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 24 Jul 2023 07:59:17 +0200 Subject: Updated godbolt links to working v4.3 examples. Added missing files. --- README.md | 2 +- docs/coroutine_api.md | 292 ++++++++++++++++++++++++++++++++++++ docs/csmap_api.md | 2 +- docs/pics/Figure_1.png | Bin 0 -> 58425 bytes docs/pics/coroutine.jpg | Bin 0 -> 81539 bytes misc/examples/coroutines/filetask.c | 80 ++++++++++ 6 files changed, 374 insertions(+), 2 deletions(-) create mode 100644 docs/coroutine_api.md create mode 100644 docs/pics/Figure_1.png create mode 100644 docs/pics/coroutine.jpg create mode 100644 misc/examples/coroutines/filetask.c (limited to 'README.md') diff --git a/README.md b/README.md index 6351fc07..55c77ca4 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,7 @@ int main(void) ``` This example uses four different container types: -[ [Run this code](https://godbolt.org/z/x5YKeMrEh) ] +[ [Run this code](https://godbolt.org/z/qor16Gf6j) ] ```c #include diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md new file mode 100644 index 00000000..30b85640 --- /dev/null +++ b/docs/coroutine_api.md @@ -0,0 +1,292 @@ +# STC [coroutine](../include/stc/coroutine.h): Coroutines +![Coroutine](pics/coroutine.jpg) + +An implementation of stackless coroutines, which are lightweight threads, providing a blocking +context cheaply using little memory per coroutine. + +Coroutines are used to accomplish a non-preempted form of concurrency known as cooperative multitasking and, therefore, do not incur context switching when yielding to another thread. Within a coroutine, **yield** and **await** is accomplished by utilizing Duff's device within a thread's function and an external variable used in within the switch statement. This allows jumping (resuming) from a yield upon another function call. In order to block threads, these yields may be guarded by a conditional so that successive calls to the same function will yield unless the guard conditional is true. + +Because these coroutines are stackless, local variables within the coroutine where usage crosses `cco_yield` or `cco_await` must be stored in a struct which is passed as pointer to the coroutine. This has the advantages that they become very lightweight and therefore useful on severely memory constrained systems like small microcontrollers where other solutions are impractical or less desirable. + +### Coroutine API + +NB! ***cco_yield\*()*** / ***cco_await\*()*** may not be called from within a `switch` statement in a +`cco_routine` scope; Use `if-else-if` constructs instead. + +| | Function / operator | Description | +|:----------|:-------------------------------------|:----------------------------------------| +|`cco_result` | `CCO_DONE`, `CCO_AWAIT`, `CCO_YIELD` | Default set of return values from coroutines | +| | `cco_cleanup:` | Label for cleanup position in coroutine | +| `bool` | `cco_done(co)` | Is coroutine done? | +| | `cco_routine(co) {}` | The coroutine scope | +| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)| +| | `cco_yield_v(ret);` | Yield/suspend execution (return ret) | +| | `cco_yield_final();` | Yield final suspend, enter cleanup-state | +| | `cco_yield_final(ret);` | Yield a final value | +| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| +| | `cco_call_await(cocall);` | Await for subcoro to finish (returns its ret value) | +| | `cco_call_await(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) | +| | `cco_return;` | Return from coroutine (inside cco_routine) | +| | Task objects: | | +| | `cco_task_struct(Name, ...);` | Define a coroutine task struct | +| | `cco_task_await(task, cco_runtime* rt);`| Await for task to finish | +| | `cco_task_await(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) | +|`cco_result`| `cco_task_resume(task, rt);` | Resume suspended task | +| | Semaphores: | | +| | `cco_sem` | Semaphore type | +| `cco_sem` | `cco_sem_from(long value)` | Create semaphore | +| | `cco_sem_set(sem, long value)` | Set semaphore value | +| | `cco_sem_await(sem)` | Await for the semaphore count > 0 | +| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | +| | Timers: | | +| | `cco_timer` | Timer type | +| | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)| +| | `cco_timer_start(tm, double sec)` | Start timer for secs duration | +| | `cco_timer_restart(tm)` | Restart timer with same duration | +| `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | +| `double` | `cco_timer_elapsed(tm)` | Return seconds elapsed | +| `double` | `cco_timer_remaining(tm)` | Return seconds remaining | +| | From caller side: | | +| `void` | `cco_stop(co)` | Next call of coroutine finalizes | +| `void` | `cco_reset(co)` | Reset state to initial (for reuse) | +| `void` | `cco_call_blocking(cocall) {}` | Run blocking until cocall is finished | +| `void` | `cco_call_blocking(cocall, int* outres) {}`| Run blocking until cocall is finished | +| | `cco_task_blocking(task) {}` | Run blocking until task is finished | +| | `cco_task_blocking(task, rt, STACKSZ) {}`| Run blocking until task is finished | +| | Time functions: | | +| `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | +| | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | + + +## Implementation and examples + +This small implementation of coroutines is inspired by +[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html) and +[Adam Dunkel's photothreads](https://dunkels.com/adam/pt), but provides big improvements regarding +ergonomics, features, and type-safety. Crucially, it also allows coroutines to self-cleanup when +cancelled (not resumed until they are done). + +A coroutine function may have almost any signature, but the implementation adds support for +coroutines which returns an int, indicating CCO_DONE, CCO_AWAIT, or CCO_YIELD. It should also +take a struct pointer as parameter which must contains the member `int cco_state`. The struct should +normally store all *local* variables to be used within the coroutine, along with *input* and *output* data +for the coroutine. + +Note that this implementation is not limited to support a certain set of coroutine types, +like generators. It can even operate like stackfull coroutines, i.e. you can efficiently +yield or await from a (deeply) nested coroutine call using cco_task objects described later. + +The first example is a generator of Pythagorian triples, and stops when diagonal size > max_c. + +[ [Run this code](https://godbolt.org/z/3Efn17cP6) ] +```c +#include +#include +#include +// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ + +struct triples { + int max_c; // input: max c. + int a, b, c; // output + int cco_state; // required member +}; + +int triples(struct triples* i) { + cco_routine(i) { // the coroutine scope! + for (i->c = 5;; ++i->c) { + for (i->a = 1; i->a < i->c; ++i->a) { + for (i->b = i->a + 1; i->b < i->c; ++i->b) { + if ((int64_t)i->a * i->a + + (int64_t)i->b * i->b == + (int64_t)i->c * i->c) + { + if (i->c > i->max_c) + cco_return; // "jump" to cco_cleanup if defined, else exit scope. + cco_yield(); + } + } + } + } + cco_cleanup: + puts("done"); + } + return 0; // CCO_DONE +} + +int main(void) { + struct triples co = {.max_c = 25}; + int n = 0; + + cco_call_blocking(triples(&co)) { + printf("%d: [%d, %d, %d]\n", ++n, co.a, co.b, co.c); + } +} +``` +The next variant skips the triples which are upscaled version of smaller ones by checking +the gcd() function. Note that the gcd1_triples struct contains the triples struct so that +both functions have separate call frames: + +[ [Run this code](https://godbolt.org/z/ndhMq1haj) ] +```c +int gcd(int a, int b) { // greatest common denominator + while (b) { + int t = a % b; + a = b; + b = t; + } + return a; +} + +struct gcd1_triples { + int max_n, max_c, count; // input: max_n, max_c limit #triples to be generated. + struct triples tri; // triples call frame + int cco_state; +}; + +int gcd1_triples(struct gcd1_triples* i) +{ + cco_routine(i) { + cco_reset(&i->tri); + i->tri.max_c = i->max_c; + + while (triples(&i->tri) != CCO_DONE) { + // Skip triples with GCD(a,b) > 1 + if (gcd(i->tri.a, i->tri.b) > 1) + continue; + + // Done when count > max_n + if (++i->count > i->max_n) + cco_return; + else + cco_yield(); + } + cco_cleanup: + cco_stop(&i->tri); // to cleanup state if still active + triples(&i->tri); // do cleanup (or no-op if done) + } + return 0; +} + +int main(void) { + struct gcd1_triples co = {.max_n = 100, .max_c = 100}; + int n = 0; + + cco_call_blocking(gcd1_triples(&co)) { + printf("%d: [%d, %d, %d]\n", ++n, co.tri.a, co.tri.b, co.tri.c); + } +} +``` +When using ***cco_call_blocking()***, the coroutine is continuously resumed after each yield suspension. +However, this means that it first calls ***gcd1_triples()***, which immediately jumps to after the `cco_yield` +-statement and calls ***triples()***, which again jumps and resumes after its `cco_yield`-statement. This +is efficient only when yielding or awaiting from the top- or second-level call like here, but naturally not +when couroutine calls are more deeply nested or recursive. + +The STC coroutine implementation therefore also contains task-objects (`cco_task`), which are base-coroutine +objects/enclosures. These can be executed using ***cco_task_blocking()*** instead of ***cco_call_blocking()***. +Inner coroutine calls are done by ***cco_task_await()***, where you may await for a certain return value, normally CCO_YIELD or just CCO_DONE. It uses a stack of pointers of task-enclosures to call the current +inner-level function directly. The task-objects have the added benefit that coroutines can be managed +by a scheduler, which is useful when dealing with large numbers of coroutines (like in many games and +simulations). + +Note that these two modes may be mixed, and that for short-lived coroutines (only a few suspends), +it is often beneficial to call the sub-coroutine directly rather than via ***cco_task_await()*** +(which pushes the task on top of the runtime stack and yields - then executed on next resume). + +The following example uses task-objects with 3-levels deep coroutine calls. It emulates an async generator +by awaiting a few seconds before producing a number, using a timer. +```c +// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/ +#include +#include +#define i_static +#include +#include + +cco_task_struct (next_value, + int val; + cco_timer tm; +); + +int next_value(struct next_value* co, cco_runtime* rt) +{ + cco_routine (co) { + while (true) { + cco_timer_await(&co->tm, 1 + rand() % 2); // suspend with CCO_AWAIT + co->val = rand(); + cco_yield(); // suspend with CCO_YIELD + } + } + return 0; +} + +void print_time() +{ + time_t now = time(NULL); + char mbstr[64]; + strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now)); + printf("%s ", mbstr); +} + +// PRODUCER +cco_task_struct (produce_items, + struct next_value next; + cstr str; +); + +int produce_items(struct produce_items* p, cco_runtime* rt) +{ + cco_routine (p) { + p->str = cstr_null; + p->next.cco_func = next_value; + while (true) + { + // await for CCO_YIELD (or CCO_DONE) + cco_task_await(&p->next, rt, CCO_YIELD); + cstr_printf(&p->str, "item %d", p->next.val); + print_time(); + printf("produced %s\n", cstr_str(&p->str)); + cco_yield(); + } + cco_cleanup: + cstr_drop(&p->str); + puts("done produce"); + } + return 0; +} + +// CONSUMER +cco_task_struct (consume_items, + int n, i; + struct produce_items produce; +); + +int consume_items(struct consume_items* c, cco_runtime* rt) +{ + cco_routine (c) { + c->produce.cco_func = produce_items; + + for (c->i = 1; c->i <= c->n; ++c->i) + { + printf("consume #%d\n", c->i); + cco_task_await(&c->produce, rt, CCO_YIELD); + print_time(); + printf("consumed %s\n", cstr_str(&c->produce.str)); + } + cco_cleanup: + cco_stop(&c->produce); + cco_task_resume(&c->produce, rt); + puts("done consume"); + } + return 0; +} + +int main(void) +{ + struct consume_items consume = { + .n = 5, + .cco_func = consume_items, + }; + cco_task_blocking(&consume); +} +``` \ No newline at end of file diff --git a/docs/csmap_api.md b/docs/csmap_api.md index afaf49f3..164b0f8a 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -148,7 +148,7 @@ Translate a [C++ example using *insert* and *emplace*](https://en.cppreference.com/w/cpp/container/map/try_emplace) to STC: -[ [Run this code](https://godbolt.org/z/9d1PP77Pa) ] +[ [Run this code](https://godbolt.org/z/b46W5Ezrb) ] ```c #define i_implement #include diff --git a/docs/pics/Figure_1.png b/docs/pics/Figure_1.png new file mode 100644 index 00000000..263303d2 Binary files /dev/null and b/docs/pics/Figure_1.png differ diff --git a/docs/pics/coroutine.jpg b/docs/pics/coroutine.jpg new file mode 100644 index 00000000..e5fceab3 Binary files /dev/null and b/docs/pics/coroutine.jpg differ diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c new file mode 100644 index 00000000..bfce7810 --- /dev/null +++ b/misc/examples/coroutines/filetask.c @@ -0,0 +1,80 @@ +// https://github.com/lewissbaker/cppcoro#taskt + +#include +#include +#define i_static +#include +#include + +cco_task_struct(file_read, + const char* path; + cstr line; + FILE* fp; + cco_timer tm; +); + +int file_read(struct file_read* co, cco_runtime* rt) +{ + cco_routine (co) { + co->fp = fopen(co->path, "r"); + co->line = cstr_null; + + while (true) { + // emulate async io: await 10ms per line + cco_timer_await(&co->tm, 0.003); + + if (!cstr_getline(&co->line, co->fp)) + break; + cco_yield(); + } + + cco_cleanup: + fclose(co->fp); + cstr_drop(&co->line); + puts("done file_read"); + } + return 0; +} + +cco_task_struct(count_line, + cstr path; + struct file_read reader; + int lineCount; +); + +int count_line(struct count_line* co, cco_runtime* rt) +{ + cco_routine (co) { + co->reader.cco_func = file_read; + co->reader.path = cstr_str(&co->path); + while (true) + { + // await for next CCO_YIELD (or CCO_DONE) in file_read() + cco_task_await(&co->reader, rt, CCO_YIELD); + if (rt->result == CCO_DONE) break; + co->lineCount += 1; + cco_yield(); + } + + cco_cleanup: + cstr_drop(&co->path); + puts("done count_line"); + } + return 0; +} + +int main(void) +{ + // Creates a new task + struct count_line countTask = { + .cco_func = count_line, + .path = cstr_from(__FILE__), + }; + + // Execute coroutine as top-level blocking + int loop = 0; + cco_task_blocking(&countTask) { ++loop; } + + printf("line count = %d\n", countTask.lineCount); + printf("exec count = %d\n", loop); +} -- cgit v1.2.3 From 4a37879119cd4d8b92c5dc578741052dd399f53f Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 24 Jul 2023 09:12:26 +0200 Subject: Updated docs, fix for issue #64. --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 55c77ca4..c28e5773 100644 --- a/README.md +++ b/README.md @@ -532,17 +532,22 @@ MyVec_push_back(&vec, 1); It is possible to forward declare containers. This is useful when a container is part of a struct, but still not expose or include the full implementation / API of the container. ```c -// Header file +// Dataset.h #include // only include data structures -forward_cstack(cstack_pnt, struct Point); // declare cstack_pnt (and cstack_pnt_value, cstack_pnt_iter); - // struct Point may be an incomplete type. + +// declare cstack_pnt; struct Point may be an incomplete type. +forward_cstack(cstack_pnt, struct Point); typedef struct Dataset { cstack_pnt vertices; cstack_pnt colors; } Dataset; -// Implementation -#define i_is_forward // flag that the container was forward declared. +... +// Dataset.c +#include "Dataset.h" + +struct Point { int x, y, z; }; // Point must be defined here. +#define i_is_forward // flag that the container was forward declared. #define i_key struct Point #define i_tag pnt #include -- cgit v1.2.3 From 5b54b0ca26540dd116880f316c6fa0291a7c96c7 Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 24 Jul 2023 23:44:53 +0200 Subject: Made it a pre-release 4.3 --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index c28e5773..9b6698e5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ STC - Smart Template Containers =============================== -### [Version 4.3 Released](#version-history) +### [Version 4.3 Pre-release](#version-history) - See details for breaking changes. --- Description @@ -107,8 +107,8 @@ Benchmark notes: - The barchart shows average test times over three compilers: **Mingw64 13.1.0, Win-Clang 16.0.5, VC-19-36**. CPU: **Ryzen 7 5700X**. - Containers uses value types `uint64_t` and pairs of `uint64_t` for the maps. - Black bars indicates performance variation between various platforms/compilers. -- Iterations are repeated 4 times over n elements. -- **find()**: not executed for *forward_list*, *deque*, and *vector* because these c++ containers does not have native *find()*. +- Iterations and access are repeated 4 times over n elements. +- access: no entryfor *forward_list*, *deque*, and *vector* because these c++ containers does not have native *find()*. - **deque**: *insert*: n/3 push_front(), n/3 push_back()+pop_front(), n/3 push_back(). - **map and unordered map**: *insert*: n/2 random numbers, n/2 sequential numbers. *erase*: n/2 keys in the map, n/2 random keys. @@ -537,6 +537,7 @@ but still not expose or include the full implementation / API of the container. // declare cstack_pnt; struct Point may be an incomplete type. forward_cstack(cstack_pnt, struct Point); + typedef struct Dataset { cstack_pnt vertices; cstack_pnt colors; -- cgit v1.2.3 From d7fba27af452de2d709767e615fa2e90d6b3a391 Mon Sep 17 00:00:00 2001 From: tylov Date: Wed, 26 Jul 2023 21:23:15 +0200 Subject: Added cmap_emplace_key() / csmap_emplace_key() More docs. --- README.md | 29 +++++----- docs/algorithm_api.md | 4 +- docs/cmap_api.md | 8 ++- docs/csmap_api.md | 1 + include/stc/algo/filter.h | 2 +- include/stc/cmap.h | 87 +++++++++++++++------------- include/stc/csmap.h | 30 ++++++---- include/stc/forward.h | 1 + misc/examples/smartpointers/arc_containers.c | 1 - misc/tests/cspan_test.c | 4 +- 10 files changed, 95 insertions(+), 72 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 9b6698e5..d66a7f1c 100644 --- a/README.md +++ b/README.md @@ -619,23 +619,24 @@ STC is generally very memory efficient. Memory usage for the different container # Version History ## Version 4.3 -- Some breaking changes. -- **coroutines**: much improved with some new API and added features. -- **cspan**: Rewritten to add support for **column-major** order (fortran) multidim spans and transposed views. -- Removed default comparison for **clist**, **cvec** and **cdeq** (like cstack and cqueue). - - Define `i_cmp_native` to enable built-in i_key types comparisons (<, ==). - - Use of `i_keyclass` still expects comparison functions defined. - - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined. -- **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. +- Some breaking changes: + - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. + - Changes in `coroutine.h`: much improved with some new API and added features. + - Renamed stc/calgo.h => `` + - Removed deprecated stc/crandom.h. Use `` with the new API. + - Removed default comparison for **clist**, **cvec** and **cdeq**: + - Define `i_cmp_native` to enable comparison for built-in i_key types (<, ==). + - Use of `i_keyclass` still expects comparison functions to be defined. + - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined. + - Renamed input enum flags for ***cregex***-functions. +- **cspan**: Changed representation of strides to add **column-major** order (fortran) multidimensional spans and transposed views. - All new faster and smaller **cqueue** and **cdeq** implementations, using a circular buffer. -- Renamed i_extern => `i_import`. - - Define `i_import` before `#include ` will also define utf8 case conversions. +- Renamed i_extern => `i_import` (i_extern deprecated). + - Define `i_import` before `#include ` will also define full utf8 case conversions. - Define `i_import` before `#include ` will also define cstr + utf8 tables. -- Renamed c_make() => ***c_init()*** macro for initializing containers with element lists. -- Renamed input enum flags for ***cregex***-functions. -- Removed deprecated . Use `` with the new API. +- Renamed c_make() => ***c_init()*** macro for initializing containers with element lists. c_make deprecated. - Removed deprecated uppercase flow-control macro names. -- Improved default string hash function. +- Other smaller additions, bug fixes and improved documentation. ## Version 4.2 - New home! And online single headers for https://godbolt.org diff --git a/docs/algorithm_api.md b/docs/algorithm_api.md index 490771b5..40ff32d6 100644 --- a/docs/algorithm_api.md +++ b/docs/algorithm_api.md @@ -130,7 +130,7 @@ Iterate a container or a crange with chained `&&` filtering. [ [Run this example](https://godbolt.org/z/n9aYrYPv8) ] ```c -#include +#include #include bool isPrime(long long i) { @@ -309,8 +309,6 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are | `continue` | Exit a defer-block without resource leak | ```c -#include // or -... // `c_defer` executes the expression(s) when leaving scope. // Note: does not require inclusion of "raii.h". cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 17f27662..4e6da57d 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -71,7 +71,8 @@ cmap_X_result cmap_X_insert_or_assign(cmap_X* self, i_key key, i_val map cmap_X_result cmap_X_push(cmap_X* self, cmap_X_value entry); // similar to insert cmap_X_result cmap_X_emplace(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map -cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update +cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update mapped +cmap_X_result cmap_X_emplace_key(cmap_X* self, i_keyraw rkey); // see example 1. int cmap_X_erase(cmap_X* self, i_keyraw rkey); // return 0 or 1 cmap_X_iter cmap_X_erase_at(cmap_X* self, cmap_X_iter it); // return iter after it @@ -138,6 +139,11 @@ int main(void) cmap_str_emplace(&umap, "BLACK", "#000000"); cmap_str_emplace(&umap, "WHITE", "#FFFFFF"); + // Insert only if "CYAN" is not in the map: create mapped value when needed only. + cmap_str_result res = cmap_str_emplace_key(&umap, "CYAN"); + if (res.inserted) + res.ref->second = cstr_from("#00FFFF"); // must assign second if key was inserted. + // Output values by key printf("The HEX of color RED is:[%s]\n", cstr_str(cmap_str_at(&umap, "RED"))); printf("The HEX of color BLACK is:[%s]\n", cstr_str(cmap_str_at(&umap, "BLACK"))); diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 164b0f8a..d739283b 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -72,6 +72,7 @@ csmap_X_result csmap_X_push(csmap_X* self, csmap_X_value entry); csmap_X_result csmap_X_emplace(csmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map csmap_X_result csmap_X_emplace_or_assign(csmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update rmapped +csmap_X_result csmap_X_emplace_key(csmap_X* self, i_keyraw rkey); // if key not in map, mapped is left unassigned int csmap_X_erase(csmap_X* self, i_keyraw rkey); csmap_X_iter csmap_X_erase_at(csmap_X* self, csmap_X_iter it); // returns iter after it diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index 1a62c3e1..320cd50d 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -24,7 +24,7 @@ #include #define i_val int #include -#include +#include int main(void) { diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 513a8b93..2dd8cbe6 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -55,7 +55,6 @@ int main(void) { #include #include struct chash_slot { uint8_t hashx; }; -typedef struct { intptr_t idx; uint8_t hashx, found; } chash_bucket; #endif // CMAP_H_INCLUDED #ifndef _i_prefix @@ -94,7 +93,7 @@ STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self map); STC_API void _cx_MEMB(_drop)(_cx_Self* self); STC_API void _cx_MEMB(_clear)(_cx_Self* self); STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t capacity); -STC_API chash_bucket _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr); +STC_API _cx_result _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr); STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey); STC_API void _cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* val); STC_API float _cx_MEMB(_max_load_factor)(const _cx_Self* self); @@ -106,9 +105,9 @@ STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* map) { return !map->siz STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* map) { return (intptr_t)map->size; } STC_INLINE intptr_t _cx_MEMB(_bucket_count)(_cx_Self* map) { return map->bucket_count; } STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey) - { return self->size && _cx_MEMB(_bucket_)(self, &rkey).found; } + { return self->size && !_cx_MEMB(_bucket_)(self, &rkey).inserted; } -#ifndef _i_isset +#ifdef _i_ismap STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped); #if !defined i_no_emplace STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped); @@ -116,14 +115,15 @@ STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rke STC_INLINE const _cx_mapped* _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) { - chash_bucket b = _cx_MEMB(_bucket_)(self, &rkey); - c_assert(b.found); - return &self->data[b.idx].second; + _cx_result b = _cx_MEMB(_bucket_)(self, &rkey); + c_assert(!b.inserted); + return &b.ref->second; } + STC_INLINE _cx_mapped* _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey) { return (_cx_mapped*)_cx_MEMB(_at)(self, rkey); } -#endif // !_i_isset +#endif // _i_ismap #if !defined i_no_clone STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { @@ -151,6 +151,16 @@ _cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe } return _res; } + +#ifdef _i_ismap + STC_INLINE _cx_result + _cx_MEMB(_emplace_key)(_cx_Self* self, _cx_keyraw rkey) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey); + if (_res.inserted) + _res.ref->first = i_keyfrom(rkey); + return _res; + } +#endif // _i_ismap #endif // !i_no_emplace STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) { @@ -215,19 +225,19 @@ STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) { STC_INLINE _cx_iter _cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey) { - chash_bucket b; - if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found) - return c_LITERAL(_cx_iter){self->data + b.idx, + _cx_result b; + if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted) + return c_LITERAL(_cx_iter){b.ref, self->data + self->bucket_count, - self->slot + b.idx}; + self->slot + (b.ref - self->data)}; return _cx_MEMB(_end)(self); } STC_INLINE const _cx_value* _cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey) { - chash_bucket b; - if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found) - return self->data + b.idx; + _cx_result b; + if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted) + return b.ref; return NULL; } @@ -237,10 +247,10 @@ _cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey) STC_INLINE int _cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) { - chash_bucket b = {0}; - if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found) - _cx_MEMB(_erase_entry)(self, self->data + b.idx); - return b.found; + _cx_result b; + if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted) + { _cx_MEMB(_erase_entry)(self, b.ref); return 1; } + return 0; } STC_INLINE _cx_iter @@ -313,7 +323,7 @@ STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) { c_memset(self->slot, 0, c_sizeof(chash_slot)*self->bucket_count); } -#ifndef _i_isset +#ifdef _i_ismap STC_DEF _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) { _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); @@ -340,42 +350,41 @@ STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) { return _res; } #endif // !i_no_emplace -#endif // !_i_isset +#endif // _i_ismap -STC_DEF chash_bucket +STC_DEF _cx_result _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); intptr_t _cap = self->bucket_count; - chash_bucket b = {fastrange_2(_hash, _cap), (uint8_t)(_hash | 0x80)}; + intptr_t _idx = fastrange_2(_hash, _cap); + _cx_result b = {NULL, true, (uint8_t)(_hash | 0x80)}; const chash_slot* s = self->slot; - while (s[b.idx].hashx) { - if (s[b.idx].hashx == b.hashx) { - const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + b.idx)); + while (s[_idx].hashx) { + if (s[_idx].hashx == b.hashx) { + const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + _idx)); if (i_eq((&_raw), rkeyptr)) { - b.found = true; + b.inserted = false; break; } } - if (++b.idx == _cap) b.idx = 0; + if (++_idx == _cap) _idx = 0; } + b.ref = self->data + _idx; return b; } STC_DEF _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { - _cx_result res = {NULL}; if (self->size >= (intptr_t)((float)self->bucket_count * (i_max_load_factor))) if (!_cx_MEMB(_reserve)(self, (intptr_t)(self->size*3/2 + 2))) - return res; + return c_LITERAL(_cx_result){NULL}; - chash_bucket b = _cx_MEMB(_bucket_)(self, &rkey); - res.ref = &self->data[b.idx]; - if (!b.found) { - self->slot[b.idx].hashx = b.hashx; - res.inserted = true; + _cx_result b = _cx_MEMB(_bucket_)(self, &rkey); + if (b.inserted) { + self->slot[b.ref - self->data].hashx = b.hashx; ++self->size; } - return res; + return b; } #if !defined i_no_clone @@ -417,9 +426,9 @@ _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) { const chash_slot* s = self->slot; for (intptr_t i = 0; i < _oldbucks; ++i, ++d) if ((s++)->hashx) { _cx_keyraw r = i_keyto(_i_keyref(d)); - chash_bucket b = _cx_MEMB(_bucket_)(&m, &r); - m.slot[b.idx].hashx = b.hashx; - m.data[b.idx] = *d; // move + _cx_result b = _cx_MEMB(_bucket_)(&m, &r); + m.slot[b.ref - m.data].hashx = b.hashx; + *b.ref = *d; // move } c_swap(_cx_Self, self, &m); } diff --git a/include/stc/csmap.h b/include/stc/csmap.h index f4d33a4d..d2e1d1fc 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -170,19 +170,29 @@ _cx_MEMB(_shrink_to_fit)(_cx_Self *self) { } #endif // !i_no_clone -#ifndef _i_isset +STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey); + +#ifdef _i_ismap STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped); #if !defined i_no_emplace STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped); - #endif + STC_INLINE _cx_result + _cx_MEMB(_emplace_key)(_cx_Self* self, _cx_keyraw rkey) { + _cx_result res = _cx_MEMB(_insert_entry_)(self, rkey); + if (res.inserted) + res.ref->first = i_keyfrom(rkey); + return res; + } + #endif STC_INLINE const _cx_mapped* _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; } + STC_INLINE _cx_mapped* _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey) { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; } -#endif // !_i_isset +#endif // _i_ismap STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) { @@ -209,8 +219,6 @@ _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { return true; } -static _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey); - STC_INLINE _cx_result _cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); @@ -326,7 +334,7 @@ _cx_MEMB(_new_node_)(_cx_Self* self, int level) { return tn; } -#ifndef _i_isset +#ifdef _i_ismap STC_DEF _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) { _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); @@ -353,7 +361,7 @@ _cx_MEMB(_new_node_)(_cx_Self* self, int level) { return _res; } #endif // !i_no_emplace -#endif // !_i_isset +#endif // !_i_ismap STC_DEF _cx_value* _cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out) { @@ -407,7 +415,7 @@ _cx_MEMB(_split_)(_cx_node *d, int32_t tn) { return tn; } -static int32_t +STC_DEF int32_t _cx_MEMB(_insert_entry_i_)(_cx_Self* self, int32_t tn, const _cx_keyraw* rkey, _cx_result* _res) { int32_t up[64], tx = tn; _cx_node* d = self->nodes; @@ -439,7 +447,7 @@ _cx_MEMB(_insert_entry_i_)(_cx_Self* self, int32_t tn, const _cx_keyraw* rkey, _ return up[0]; } -static _cx_result +STC_DEF _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { _cx_result res = {NULL}; int32_t tn = _cx_MEMB(_insert_entry_i_)(self, self->root, &rkey, &res); @@ -448,7 +456,7 @@ _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { return res; } -static int32_t +STC_DEF int32_t _cx_MEMB(_erase_r_)(_cx_Self *self, int32_t tn, const _cx_keyraw* rkey, int *erased) { _cx_node *d = self->nodes; if (tn == 0) @@ -533,7 +541,7 @@ _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) { } #if !defined i_no_clone -static int32_t +STC_DEF int32_t _cx_MEMB(_clone_r_)(_cx_Self* self, _cx_node* src, int32_t sn) { if (sn == 0) return 0; diff --git a/include/stc/forward.h b/include/stc/forward.h index 484a8b63..085205cf 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -120,6 +120,7 @@ typedef struct chash_slot chash_slot; typedef struct { \ SELF##_value *ref; \ bool inserted; \ + uint8_t hashx; \ } SELF##_result; \ \ typedef struct { \ diff --git a/misc/examples/smartpointers/arc_containers.c b/misc/examples/smartpointers/arc_containers.c index 2fb04c56..6209005d 100644 --- a/misc/examples/smartpointers/arc_containers.c +++ b/misc/examples/smartpointers/arc_containers.c @@ -2,7 +2,6 @@ // and demonstrate sharing and cloning of maps. #define i_implement #include -#include #define i_type Map #define i_key_str // strings #define i_val int diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index d7ca9b64..ce267b14 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -1,6 +1,5 @@ #include #include -#include #include "ctest.h" using_cspan3(intspan, int); @@ -48,7 +47,8 @@ CTEST(cspan, slice) { #include CTEST(cspan, slice2) { - c_auto (cstack_int, stack) + cstack_int stack = {0}; + c_defer (cstack_int_drop(&stack)) { c_forrange (i, 10*20*30) cstack_int_push(&stack, i); -- cgit v1.2.3 From 6354a597892e84baa6c3a99b98f2c7acaf33a99d Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 1 Aug 2023 16:31:40 +0200 Subject: Improve changelog for v4.3 --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index d66a7f1c..c333f5cd 100644 --- a/README.md +++ b/README.md @@ -619,17 +619,19 @@ STC is generally very memory efficient. Memory usage for the different container # Version History ## Version 4.3 -- Some breaking changes: +- Breaking changes: - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. - - Changes in `coroutine.h`: much improved with some new API and added features. - - Renamed stc/calgo.h => `` - - Removed deprecated stc/crandom.h. Use `` with the new API. + - Renamed => `` + - Moved => `` + - Much improved with some new API and added features. + - Removed deprecated . Use `` with the new API. + - Reverted names _unif and _norm back to `_uniform` and `_normal`. - Removed default comparison for **clist**, **cvec** and **cdeq**: - Define `i_cmp_native` to enable comparison for built-in i_key types (<, ==). - Use of `i_keyclass` still expects comparison functions to be defined. - - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined. + - Use of `i_keyboxed` compares stored pointers instead of pointed to values if comparison not defined. - Renamed input enum flags for ***cregex***-functions. -- **cspan**: Changed representation of strides to add **column-major** order (fortran) multidimensional spans and transposed views. +- **cspan**: Added **column-major** order (fortran) multidimensional spans and transposed views (changed representation of strides). - All new faster and smaller **cqueue** and **cdeq** implementations, using a circular buffer. - Renamed i_extern => `i_import` (i_extern deprecated). - Define `i_import` before `#include ` will also define full utf8 case conversions. -- cgit v1.2.3 From 3f50495eb4f465531000c33072005ab218fdfb11 Mon Sep 17 00:00:00 2001 From: tylov Date: Sat, 5 Aug 2023 12:57:14 +0200 Subject: Docs improvements in README.md --- README.md | 81 ++++++++++++++++++++++++++++++------- misc/examples/coroutines/filetask.c | 2 +- 2 files changed, 67 insertions(+), 16 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index c333f5cd..3ff00e52 100644 --- a/README.md +++ b/README.md @@ -521,39 +521,90 @@ Define `i_type` instead of `i_tag`: #define i_key int #include -myvec vec = MyVec_init(); -MyVec_push_back(&vec, 1); +MyVec vec = {0}; +MyVec_push(&vec, 42); ... ``` --- ## Forward declarations -It is possible to forward declare containers. This is useful when a container is part of a struct, -but still not expose or include the full implementation / API of the container. +There are two ways to pre-declare templated containers in header files: + +1. Include the templated container type instance as a header file. This also exposes all container +functions, which can be used by client code. It requires that the element type is complete. +2. Or, pre-declare the container type only. In this case, the container can be a "private" member of a +user struct (the container functions will not be available to the user). + +### 1. Include as a header file + +Create a dedicated header for the container type instance: +```c +#ifndef PointVec_H_ +#define PointVec_H_ +// Do not to include user defined headers here if they use templated containers themselves + +#define i_type PointVec +#define i_val struct Point // NB! Element type must be complete at this point! +#define i_header // Do not implement, only expose API +#include + +#endif +``` +Usage from e.g. other headers is trivial: +```c +#ifndef Dataset_H_ +#define Dataset_H_ +#include "Point.h" // include element type separately +#include "PointVec.h" + +typedef struct Dataset { + PointVec vertices; + PointVec colors; +} Dataset; +... +#endif +``` + +Implement PointVec in a c-file: +```c +#include "Point.h" +#define i_implement // define immediately before PointVec.h +#include "PointVec.h" +... +``` + +### 2. Forward declare only ```c // Dataset.h -#include // only include data structures +#ifndef Dataset_H_ +#define Dataset_H_ +#include // include various container data structure templates -// declare cstack_pnt; struct Point may be an incomplete type. -forward_cstack(cstack_pnt, struct Point); +// declare PointVec. Note: struct Point may be an incomplete/undeclared type. +forward_cvec(PointVec, struct Point); typedef struct Dataset { - cstack_pnt vertices; - cstack_pnt colors; + PointVec vertices; + PointVec colors; } Dataset; +void Dataset_drop(Dataset* self); ... +#endif +``` +Define and use the "private" container in the c-file: +```c // Dataset.c #include "Dataset.h" +#include "Point.h" // Point must be defined here. -struct Point { int x, y, z; }; // Point must be defined here. -#define i_is_forward // flag that the container was forward declared. -#define i_key struct Point -#define i_tag pnt -#include +#define i_is_forward // flag that the container was forward declared. +#define i_type PointVec +#define i_val struct Point +#include // Implements PointVec with static linking by default +... ``` - --- ## Per container-instance customization Sometimes it is useful to extend a container type to store extra data, e.g. a comparison diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c index 28292801..0607442d 100644 --- a/misc/examples/coroutines/filetask.c +++ b/misc/examples/coroutines/filetask.c @@ -21,7 +21,7 @@ int file_read(struct file_read* co, cco_runtime* rt) while (true) { // emulate async io: await 10ms per line - cco_await_timer(&co->tm, 0.003); + cco_await_timer(&co->tm, 0.010); if (!cstr_getline(&co->line, co->fp)) break; -- cgit v1.2.3 From f514c5128d62ad53623af4d45bd856b9564bce4f Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 6 Aug 2023 23:23:36 +0200 Subject: Improved Installation section in README.md --- README.md | 56 ++++++++++++++++++------------------------------------ include/stc/cstr.h | 2 +- src/libstc.c | 2 ++ 3 files changed, 21 insertions(+), 39 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 3ff00e52..69c51417 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ List of contents - **Uniform, easy-to-learn API** - Just include the headers and you are good. The API and functionality resembles c++ STL and is fully listed in the docs. Intuitive method/type names and uniform usage across the various containers. - **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed for comparison and calculation is asking for trouble. STC only uses signed numbers in the API for this reason. - **Small footprint** - Small source code and generated executables. The executable from the example below using *four different* container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux. -- **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section. +- **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the [installation section](#installation). - **No callback functions** - All passed template argument functions/macros are directly called from the implementation, no slow callbacks which requires storage. - **Compiles with C++ and C99** - C code can be compiled with C++ (container element types must be POD). - **Forward declaration** - Templated containers may be [forward declared](#forward-declarations) without including the full API/implementation. @@ -333,49 +333,29 @@ After erasing the elements found: --- ## Installation -*NEEDS REWRITE!* -Because it is headers-only, headers can simply be included in your program. By default, functions are static -(some inlined). You may add the *include* folder to the **CPATH** environment variable to -let GCC, Clang, and TinyC locate the headers. +STC is primarily a "headers-only" library, so most headers can simply be included in your program. By default, +all "templated" functions are static (many inlined). If you add the STC *include* folder to the **CPATH** +environment variable, GCC, Clang, and TinyC will locate the headers automatically. -If containers are used across several translation units with common instantiated container types, it is -recommended to build as a "library" with external linking to minimize executable size. To enable this, -specify `-DSTC_HEADER` as compiler option in your build environment. Next, place all the instantiations -of the containers used inside a single C-source file as in the example below, and `#define STC_IMPLEMENT` at top. -You may also cherry-pick shared linking mode on individual containers by `#define i_header` and -`#define i_implement`, or force static symbols by `#define i_static` before container includes. - -As a special case, there may be non-templated functions in templated containers that should be implemented only -once and if needed. Currently, define `i_import` before including **cregex** or **utf8** to implement them. - -It is possible to generate single headers by executing the python script `src/singleheader.py header-file > single`. - -Conveniently, `src\libstc.c` implements non-templated functions as shared symbols for **cstr**, **csview**, -**cbits** and **crand**. When building in shared mode (-DSTC_HEADER), you may include this file in your project, -or define your own, e.g.: +The templated container functions are defined with static linking by default, which is normally optimal +for both performance and compiled binary size. However, some common container type instances, e.g. `cvec_int` +may be used in several translation units. When they are used in more than 3-4, consider creating a separate +header file for them [as described here](#1-include-as-a-header-file). Now it will use shared +linking, so *one* c-file must implement the templated container, e.g.: ```c -// stc_libs.c -#define STC_IMPLEMENT // implement all the following as shared objects #define i_implement -#include -#include "Point.h" - -#define i_key int -#define i_val int -#define i_tag ii -#include // cmap_ii: int => int +#include "cvec_int.h" +``` +The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by +`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so +linking specifications and implementation are only needed for a few lesser used functions. -#define i_key int64_t -#define i_tag ix -#include // cset_ix +Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**, +**csview**, **cregex**, **utf8**, and **crand**. -#define i_key int -#include // cvec_int +As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent +**utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc. -#define i_key Point -#define i_tag pnt -#include // clist_pnt -``` --- ## Specifying template parameters diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 2648e267..f12d29b6 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -179,7 +179,7 @@ extern void cstr_lowercase(cstr* self); extern void cstr_uppercase(cstr* self); extern bool cstr_valid_utf8(const cstr* self); -// other utf8 +// utf8 functions not depending on src/utf8code.c: STC_INLINE intptr_t cstr_u8_size(const cstr* self) { return utf8_size(cstr_str(self)); } diff --git a/src/libstc.c b/src/libstc.c index 7b49540a..462c97c4 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -2,6 +2,8 @@ #include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement #include "../include/stc/csview.h" +#define i_implement +#include "../include/stc/crand.h" #if __STDC_VERSION__ >= 201112L # define i_implement # include "../include/c11/fmt.h" -- cgit v1.2.3 From be5651c9fc3d3ecd2d9d24e6e4763260ef86de41 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 10 Aug 2023 21:17:48 +0200 Subject: Update template.h - also renamed i_cmp_native => i_use_cmp --- README.md | 4 +- docs/carc_api.md | 2 +- docs/cbox_api.md | 2 +- docs/cdeq_api.md | 2 +- docs/clist_api.md | 2 +- docs/cvec_api.md | 4 +- include/stc/carc.h | 64 ++++++++++++--------------- include/stc/cbox.h | 65 ++++++++++++---------------- include/stc/ccommon.h | 2 +- include/stc/priv/template.h | 29 ++++++------- include/stc/priv/template2.h | 2 +- misc/examples/linkedlists/intrusive.c | 2 +- misc/examples/linkedlists/list.c | 2 +- misc/examples/linkedlists/new_list.c | 2 +- misc/examples/mixed/astar.c | 1 - misc/examples/mixed/complex.c | 1 - misc/examples/mixed/demos.c | 3 +- misc/examples/smartpointers/arc_containers.c | 4 +- misc/examples/smartpointers/arc_demo.c | 3 +- misc/examples/smartpointers/arcvec_erase.c | 3 +- misc/examples/smartpointers/box.c | 1 + misc/examples/smartpointers/box2.c | 1 - misc/examples/smartpointers/music_arc.c | 4 +- misc/examples/smartpointers/new_sptr.c | 3 +- misc/examples/smartpointers/person_arc.c | 3 +- misc/examples/sortedmaps/csmap_insert.c | 1 - misc/examples/sortedmaps/multimap.c | 1 + misc/examples/vectors/lower_bound.c | 2 +- 28 files changed, 99 insertions(+), 116 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 69c51417..48ccdd6f 100644 --- a/README.md +++ b/README.md @@ -251,7 +251,7 @@ struct Point { float x, y; }; #include // cvec_pnt: vector of struct Point #define i_key int -#define i_cmp_native // enable sort/search. Use native `<` and `==` operators +#define i_use_cmp // enable sort/search. Use native `<` and `==` operators #include // clist_int: singly linked list #define i_key int @@ -658,7 +658,7 @@ STC is generally very memory efficient. Memory usage for the different container - Removed deprecated . Use `` with the new API. - Reverted names _unif and _norm back to `_uniform` and `_normal`. - Removed default comparison for **clist**, **cvec** and **cdeq**: - - Define `i_cmp_native` to enable comparison for built-in i_key types (<, ==). + - Define `i_use_cmp` to enable comparison for built-in i_key types (<, ==). - Use of `i_keyclass` still expects comparison functions to be defined. - Use of `i_keyboxed` compares stored pointers instead of pointed to values if comparison not defined. - Renamed input enum flags for ***cregex***-functions. diff --git a/docs/carc_api.md b/docs/carc_api.md index fb79019a..3e394378 100644 --- a/docs/carc_api.md +++ b/docs/carc_api.md @@ -25,7 +25,7 @@ See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory #define i_cmp // three-way compareison. REQUIRED IF i_key is a non-integral type // Note that containers of carcs will "inherit" i_cmp // when using carc in containers with i_valboxed MyArc - ie. the i_type. -#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type. #define i_keydrop // destroy element func - defaults to empty destruct #define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. diff --git a/docs/cbox_api.md b/docs/cbox_api.md index 0e6fca64..c683d9ef 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -19,7 +19,7 @@ See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory #define i_cmp // three-way compareison. REQUIRED IF i_key is a non-integral type // Note that containers of carcs will "inherit" i_cmp // when using carc in containers with i_valboxed MyArc - ie. the i_type. -#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type. #define i_keydrop // destroy element func - defaults to empty destruct #define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined. diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index c544f213..3ce58e78 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -13,7 +13,7 @@ See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque #define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. #define i_type // cdeq container type name #define i_cmp // three-way compare of two i_keyraw*. -#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type. #define i_keydrop // destroy value func - defaults to empty destruct #define i_keyclone // REQUIRED IF i_keydrop is defined diff --git a/docs/clist_api.md b/docs/clist_api.md index d8d614c2..a24d813b 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -25,7 +25,7 @@ See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list) #define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. #define i_type // clist container type name #define i_cmp // three-way compare two i_keyraw* -#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type. #define i_keydrop // destroy value func - defaults to empty destruct #define i_keyclone // REQUIRED IF i_keydrop defined diff --git a/docs/cvec_api.md b/docs/cvec_api.md index 3f827df6..8997ed51 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -15,7 +15,7 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect #define i_type // container type name #define i_key // element type: REQUIRED. Note: i_val* may be specified instead of i_key*. #define i_cmp // three-way compare two i_keyraw* -#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type. +#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type. #define i_keydrop // destroy value func - defaults to empty destruct #define i_keyclone // REQUIRED IF i_keydrop defined @@ -224,4 +224,4 @@ int main(void) { c_drop(UVec, &vec, &vec2); // cleanup } -``` \ No newline at end of file +``` diff --git a/include/stc/carc.h b/include/stc/carc.h index 9ba2ddd1..e1dfe14e 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -176,50 +176,40 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { *self = ptr; } -#if defined _i_has_cmp +#if defined i_use_cmp STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); - } -#else - STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) - { return c_default_cmp(&rx, &ry); } - - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - return c_default_cmp(&self->get, &other->get); - } -#endif -#if defined _i_has_eq || defined _i_has_cmp STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } - - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); - } -#else - STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return rx == ry; } - - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - return self->get == other->get; - } -#endif -#if defined i_hash + #ifndef i_no_hash STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } - - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } -#else - STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) - { return c_default_hash(&rx); } - - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { return c_default_hash(&self->get); } + #endif // i_no_hash + + #if defined i_ptr_cmp + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } + #else + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_cmp((&rx), (&ry)); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_eq((&rx), (&ry)); + } + #ifndef i_no_hash + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } + #endif // i_no_hash + #endif // i_ptr_cmp #endif #undef _i_atomic_inc diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 25d41b92..b799c24c 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -159,50 +159,41 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) { moved->get = NULL; } -#if defined _i_has_cmp +#if defined i_use_cmp STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); - } -#else - STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) - { return c_default_cmp(&rx, &ry); } - - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - return c_default_cmp(&self->get, &other->get); - } -#endif -#if defined _i_has_eq || defined _i_has_cmp STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } - - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); - } -#else - STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return rx == ry; } - - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - return self->get == other->get; - } -#endif -#if defined i_hash + #ifndef i_no_hash STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } - - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } -#else - STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) - { return c_default_hash(&rx); } - - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { return c_default_hash(&self->get); } + #endif // i_no_hash + + #if defined i_ptr_cmp + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } + #else + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_cmp((&rx), (&ry)); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_eq((&rx), (&ry)); + } + #ifndef i_no_hash + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } + #endif // i_no_hash + #endif // i_ptr_cmp #endif + #include "priv/template2.h" #undef _i_cbox diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 2528b94f..b37ad1da 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -117,7 +117,7 @@ typedef long long _llong; #define c_no_clone (1<<2) #define c_no_emplace (1<<3) #define c_no_cmp (1<<4) -#define c_native_cmp (1<<5) +#define c_use_cmp (1<<5) #define c_no_hash (1<<6) /* Function macros and others */ diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 49b4d8da..fae9093e 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -102,8 +102,8 @@ #if c_option(c_no_emplace) #define i_no_emplace #endif -#if c_option(c_native_cmp) - #define i_cmp_native +#if c_option(c_use_cmp) || defined _i_ismap || defined _i_isset || defined _i_ispque + #define i_use_cmp #endif #if c_option(c_no_clone) || defined _i_carc #define i_no_clone @@ -127,7 +127,7 @@ #elif defined i_keyboxed #define i_keyclass i_keyboxed #define i_rawclass c_PASTE(i_keyboxed, _raw) - #ifndef i_no_cmp + #if !defined i_no_cmp && defined i_use_cmp #define i_eq c_PASTE(i_keyboxed, _raw_eq) #endif #endif @@ -138,7 +138,7 @@ #define i_rawclass i_key #endif -#ifdef i_keyclass +#if defined i_keyclass #define i_key i_keyclass #ifndef i_keyclone #define i_keyclone c_PASTE(i_key, _clone) @@ -154,8 +154,8 @@ #endif #endif -#ifdef i_rawclass - #if !(defined i_cmp || defined i_no_cmp) +#if defined i_rawclass && defined i_use_cmp + #if !(defined i_cmp || defined i_less || defined i_no_cmp) #define i_cmp c_PASTE(i_keyraw, _cmp) #endif #if !(defined i_hash || defined i_no_hash || defined i_no_cmp) @@ -171,26 +171,29 @@ #endif #endif -#ifndef i_no_cmp - #if defined i_cmp || defined i_less || defined i_cmp_native +#if !defined i_no_cmp + #if defined i_cmp || defined i_less || defined i_use_cmp #define _i_has_cmp #endif - #if defined i_eq || defined i_cmp_native + #if defined i_eq || defined i_use_cmp #define _i_has_eq #endif #endif +#if !(defined i_hash || defined i_no_hash || defined i_no_cmp) + #define i_hash c_default_hash +#endif #if !defined i_key #error "No i_key or i_val defined" #elif defined i_keyraw ^ defined i_keyto #error "Both i_keyraw/i_valraw and i_keyto/i_valto must be defined, if any" #elif !defined i_no_clone && (defined i_keyclone ^ defined i_keydrop) - #error "Both i_keyclone/i_valclone and i_keydrop/i_valdrop must be defined, if any" + #error "Both i_keyclone/i_valclone and i_keydrop/i_valdrop must be defined, if any (unless i_no_clone defined)." #elif defined i_from || defined i_drop #error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead" #elif defined i_keyraw && defined _i_ishash && !(defined i_hash && (defined _i_has_cmp || defined i_eq)) #error "For cmap/cset, both i_hash and i_eq (or i_less or i_cmp) must be defined when i_keyraw is defined." -#elif defined i_keyraw && (defined _i_ismap || defined _i_isset || defined _i_ispque) && !defined _i_has_cmp +#elif defined i_keyraw && defined i_use_cmp && !defined _i_has_cmp #error "For csmap/csset/cpque, i_cmp or i_less must be defined when i_keyraw is defined." #endif @@ -234,10 +237,6 @@ #endif #endif -#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_cmp_native) - #define i_hash c_default_hash -#endif - #if defined _i_ismap // ---- process cmap/csmap value i_val, ... ---- #ifdef i_val_str diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 351defde..1e0d4a2e 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -67,7 +67,7 @@ #undef i_realloc #undef i_free -#undef i_cmp_native +#undef i_use_cmp #undef i_no_cmp #undef i_no_hash #undef i_no_clone diff --git a/misc/examples/linkedlists/intrusive.c b/misc/examples/linkedlists/intrusive.c index c7402d09..edb072c7 100644 --- a/misc/examples/linkedlists/intrusive.c +++ b/misc/examples/linkedlists/intrusive.c @@ -4,7 +4,7 @@ #define i_type List #define i_key int -#define i_cmp_native +#define i_use_cmp #include void printList(List list) { diff --git a/misc/examples/linkedlists/list.c b/misc/examples/linkedlists/list.c index 518cc09b..e83dc6b2 100644 --- a/misc/examples/linkedlists/list.c +++ b/misc/examples/linkedlists/list.c @@ -5,7 +5,7 @@ #define i_type DList #define i_key double -#define i_cmp_native +#define i_use_cmp #include int main(void) { diff --git a/misc/examples/linkedlists/new_list.c b/misc/examples/linkedlists/new_list.c index 2112bf1f..7518929a 100644 --- a/misc/examples/linkedlists/new_list.c +++ b/misc/examples/linkedlists/new_list.c @@ -27,7 +27,7 @@ int point_cmp(const Point* a, const Point* b) { #include #define i_key float -#define i_cmp_native // use < and == operators for comparison +#define i_use_cmp // use < and == operators for comparison #include void MyStruct_drop(MyStruct* s); diff --git a/misc/examples/mixed/astar.c b/misc/examples/mixed/astar.c index 590b7952..d15a9ed7 100644 --- a/misc/examples/mixed/astar.c +++ b/misc/examples/mixed/astar.c @@ -61,7 +61,6 @@ point_key_cmp(const point* a, const point* b) #include #define i_key point -#define i_opt c_no_cmp #include #define i_key point diff --git a/misc/examples/mixed/complex.c b/misc/examples/mixed/complex.c index 4eb1574b..9fcbc417 100644 --- a/misc/examples/mixed/complex.c +++ b/misc/examples/mixed/complex.c @@ -14,7 +14,6 @@ #define i_type StackList #define i_keyclass FloatStack // "class" picks up _clone, _drop, _cmp -#define i_opt c_no_cmp // exclude FloatStack_cmp(): not defined #include #define i_type ListMap diff --git a/misc/examples/mixed/demos.c b/misc/examples/mixed/demos.c index 7f5091fd..43c9a7ae 100644 --- a/misc/examples/mixed/demos.c +++ b/misc/examples/mixed/demos.c @@ -53,6 +53,7 @@ void vectordemo1(void) } #define i_key_str +#define i_use_cmp #include void vectordemo2(void) @@ -74,7 +75,7 @@ void vectordemo2(void) #define i_key int #define i_tag ix -#define i_cmp_native +#define i_use_cmp #include void listdemo1(void) diff --git a/misc/examples/smartpointers/arc_containers.c b/misc/examples/smartpointers/arc_containers.c index 6209005d..c2bff56f 100644 --- a/misc/examples/smartpointers/arc_containers.c +++ b/misc/examples/smartpointers/arc_containers.c @@ -12,11 +12,11 @@ #define i_key Map #define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) // no need for atomic ref. count in single thread: -#define i_opt c_no_atomic +#define i_opt c_no_atomic|c_no_cmp #include #define i_type Stack -#define i_keyboxed Arc // define i_keyboxed for carc/cbox value (not i_key) +#define i_keyboxed Arc // use i_keyboxed for carc/cbox key #include #define i_type List diff --git a/misc/examples/smartpointers/arc_demo.c b/misc/examples/smartpointers/arc_demo.c index 929a48a1..a66d84b0 100644 --- a/misc/examples/smartpointers/arc_demo.c +++ b/misc/examples/smartpointers/arc_demo.c @@ -11,13 +11,14 @@ void int_drop(int* x) { #define i_type Arc // set type name to be defined (instead of 'carc_int') #define i_key int #define i_keydrop int_drop // optional, just to display the elements destroyed -#define i_cmp_native // use int comparison (x < y, x == y). +#define i_use_cmp // use int comparison (x < y, x == y). #include // Arc #define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements #include // csset_Arc (like: std::set>) #define i_keyboxed Arc // note: as above. +#define i_use_cmp #include // cvec_Arc (like: std::vector>) int main(void) diff --git a/misc/examples/smartpointers/arcvec_erase.c b/misc/examples/smartpointers/arcvec_erase.c index 9d757533..0526b6a0 100644 --- a/misc/examples/smartpointers/arcvec_erase.c +++ b/misc/examples/smartpointers/arcvec_erase.c @@ -5,11 +5,12 @@ void show_drop(int* x) { printf("drop: %d\n", *x); } #define i_type Arc #define i_key int #define i_keydrop show_drop -#define i_cmp_native // enable sort/search for int type +#define i_use_cmp // enable sort/search for int type #include // Shared pointer to int #define i_type Vec #define i_keyboxed Arc +#define i_use_cmp #include // Vec: cvec diff --git a/misc/examples/smartpointers/box.c b/misc/examples/smartpointers/box.c index 94d126c0..5c8018d4 100644 --- a/misc/examples/smartpointers/box.c +++ b/misc/examples/smartpointers/box.c @@ -30,6 +30,7 @@ void Person_drop(Person* p) { #define i_type PBox #define i_keyclass Person // "class" binds _cmp, _clone, _drop functions. +#define i_use_cmp #include #define i_type Persons diff --git a/misc/examples/smartpointers/box2.c b/misc/examples/smartpointers/box2.c index eaab1c47..9b782c74 100644 --- a/misc/examples/smartpointers/box2.c +++ b/misc/examples/smartpointers/box2.c @@ -22,7 +22,6 @@ typedef struct { // Box in box: #define i_type BoxBoxPoint #define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc! -#define i_no_cmp #include // BoxBoxPoint Point origin(void) { diff --git a/misc/examples/smartpointers/music_arc.c b/misc/examples/smartpointers/music_arc.c index 13d368c3..e9ebbbfe 100644 --- a/misc/examples/smartpointers/music_arc.c +++ b/misc/examples/smartpointers/music_arc.c @@ -23,7 +23,7 @@ void Song_drop(Song* s) { // Define the shared pointer: #define i_type SongArc #define i_keyclass Song -#define i_no_hash // no hash fn for Song, fallback hash pointer to Song. +#define i_opt c_use_cmp|c_no_hash #include // ... and a vector of them @@ -64,4 +64,4 @@ void example3(void) int main(void) { example3(); -} +} \ No newline at end of file diff --git a/misc/examples/smartpointers/new_sptr.c b/misc/examples/smartpointers/new_sptr.c index 3c6fa16c..50e28ae2 100644 --- a/misc/examples/smartpointers/new_sptr.c +++ b/misc/examples/smartpointers/new_sptr.c @@ -10,12 +10,13 @@ uint64_t Person_hash(const Person* p); #define i_type PersonArc #define i_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined. +#define i_use_cmp #include #define i_type IPtr #define i_key int #define i_keydrop(x) printf("drop: %d\n", *x) -#define i_cmp_native +#define i_use_cmp #include #define i_type IPStack diff --git a/misc/examples/smartpointers/person_arc.c b/misc/examples/smartpointers/person_arc.c index 38c883a7..11040cd2 100644 --- a/misc/examples/smartpointers/person_arc.c +++ b/misc/examples/smartpointers/person_arc.c @@ -31,11 +31,12 @@ void Person_drop(Person* p) { #define i_type PSPtr #define i_keyclass Person // ensure Person_drop -#define i_cmp Person_cmp // specify object cmp, instead of ptr cmp for arc. +#define i_use_cmp #include #define i_type Persons #define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop... +#define i_use_cmp #include diff --git a/misc/examples/sortedmaps/csmap_insert.c b/misc/examples/sortedmaps/csmap_insert.c index c9f02891..04b8ddc6 100644 --- a/misc/examples/sortedmaps/csmap_insert.c +++ b/misc/examples/sortedmaps/csmap_insert.c @@ -13,7 +13,6 @@ #include #define i_key csmap_ii_raw -#define i_opt c_no_cmp #define i_tag ii #include diff --git a/misc/examples/sortedmaps/multimap.c b/misc/examples/sortedmaps/multimap.c index 1068a5dc..a4490f91 100644 --- a/misc/examples/sortedmaps/multimap.c +++ b/misc/examples/sortedmaps/multimap.c @@ -41,6 +41,7 @@ void OlympicLoc_drop(OlympicLoc* self); // Create a clist, can be sorted by year. #define i_keyclass OlympicLoc // binds _cmp, _clone and _drop. +#define i_use_cmp #define i_tag OL #include diff --git a/misc/examples/vectors/lower_bound.c b/misc/examples/vectors/lower_bound.c index bea828f2..09cf2008 100644 --- a/misc/examples/vectors/lower_bound.c +++ b/misc/examples/vectors/lower_bound.c @@ -1,7 +1,7 @@ #include #define i_key int -#define i_cmp_native +#define i_use_cmp #include #define i_key int -- cgit v1.2.3 From 4ba846d378481cb74f68456a3ad4d7cd77d92522 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 11 Aug 2023 08:52:50 +0200 Subject: Updated carc, cbox and template.h - simplifications: removed i_no_cmp/c_no_cmp, --- README.md | 9 +++++-- include/stc/carc.h | 49 ++++++++++++++++----------------- include/stc/cbox.h | 50 +++++++++++++++++----------------- include/stc/priv/template.h | 64 ++++++++++++++++++-------------------------- include/stc/priv/template2.h | 1 - 5 files changed, 83 insertions(+), 90 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 48ccdd6f..fbdbd9fc 100644 --- a/README.md +++ b/README.md @@ -194,8 +194,13 @@ int main(void) Floats_drop(&nums); } ``` -For user-defined struct elements, `i_cmp` compare function should be defined because the default `<` and `==` -only works for integral types. *Alternatively, `#define i_opt c_no_cmp` to disable sorting and searching*. Similarily, if an element destructor `i_keydrop` is defined, `i_keyclone` function is required. +Comparison/lookup functions are enabled by default for associative containers and priority queue (cmap, cset, csmap, csset, cpque). To enable it for the remaining containers, define `i_cmp` or `i_less` (and optionally `i_eq`) on the element type. If the element is an integral type, simply define `i_use_cmp` to use `<` and `==` operators for comparisons. + +Note that for `#define i_keyclass Type`, defining `i_use_cmp` means that *Type_cmp()* function is expected to exist (along with *Type_clone()* and *Type_drop()*). + +To summarize, `i_use_cmp` is only needed to enable comparison (sort/search) functions when defining cstack, cvec, cqueue, cdeq, carc, cbox. With built-in types, it enables the comparison operators, whereas for keyclass types, it binds comparison to its Type_cmp() function. + +If an element destructor `i_keydrop` is defined, `i_keyclone` function is required. *Alternatively `#define i_opt c_no_clone` to disable container cloning.* Let's make a vector of vectors, which can be cloned. All of its element vectors will be destroyed when destroying the Vec2D. diff --git a/include/stc/carc.h b/include/stc/carc.h index e1dfe14e..e987f453 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -180,37 +180,38 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_cmp((&rx), (&ry)); + } + STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } + + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_eq((&rx), (&ry)); + } + #ifndef i_no_hash STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } + + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } #endif // i_no_hash - #if defined i_ptr_cmp - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - return c_default_cmp(&self->get, &other->get); - } - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - return self->get == other->get; - } - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { return c_default_hash(&self->get); } - #else - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); - } - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); - } - #ifndef i_no_hash - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } - #endif // i_no_hash - #endif // i_ptr_cmp -#endif +#else + + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } +#endif // i_use_cmp #undef _i_atomic_inc #undef _i_atomic_dec_and_test diff --git a/include/stc/cbox.h b/include/stc/cbox.h index b799c24c..37daa69e 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -44,7 +44,6 @@ void Person_drop(Person* p) { #define i_type PBox #define i_valclass Person // bind Person clone+drop fn's -#define i_no_cmp // no cmp/hash is defined #include int main(void) { @@ -163,37 +162,38 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) { STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_cmp((&rx), (&ry)); + } + STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } + + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); + return i_eq((&rx), (&ry)); + } + #ifndef i_no_hash STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } + + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } #endif // i_no_hash - #if defined i_ptr_cmp - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - return c_default_cmp(&self->get, &other->get); - } - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - return self->get == other->get; - } - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { return c_default_hash(&self->get); } - #else - STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); - } - STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); - } - #ifndef i_no_hash - STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) - { _cx_raw rx = i_keyto(self->get); return i_hash(&rx); } - #endif // i_no_hash - #endif // i_ptr_cmp -#endif +#else + + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } +#endif // i_use_cmp #include "priv/template2.h" #undef _i_cbox diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index fae9093e..3b8a5b39 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -93,9 +93,6 @@ #if c_option(c_is_forward) #define i_is_forward #endif -#if c_option(c_no_cmp) - #define i_no_cmp -#endif #if c_option(c_no_hash) #define i_no_hash #endif @@ -127,7 +124,7 @@ #elif defined i_keyboxed #define i_keyclass i_keyboxed #define i_rawclass c_PASTE(i_keyboxed, _raw) - #if !defined i_no_cmp && defined i_use_cmp + #if defined i_use_cmp #define i_eq c_PASTE(i_keyboxed, _raw_eq) #endif #endif @@ -152,34 +149,27 @@ #ifndef i_keydrop #define i_keydrop c_PASTE(i_key, _drop) #endif + #if !defined i_keyraw && (defined i_cmp || defined i_less || defined i_eq || defined i_hash) + #define i_use_cmp + #endif #endif #if defined i_rawclass && defined i_use_cmp - #if !(defined i_cmp || defined i_less || defined i_no_cmp) + #if !(defined i_cmp || defined i_less) #define i_cmp c_PASTE(i_keyraw, _cmp) #endif - #if !(defined i_hash || defined i_no_hash || defined i_no_cmp) + #if !(defined i_hash || defined i_no_hash) #define i_hash c_PASTE(i_keyraw, _hash) #endif #endif -#if !defined i_keyraw && !defined i_no_clone - #if !defined i_keyfrom && defined i_keyclone - #define i_keyfrom i_keyclone - #elif !defined i_keyclone && defined i_keyfrom - #define i_keyclone i_keyfrom - #endif +#if defined i_cmp || defined i_less || defined i_use_cmp + #define _i_has_cmp #endif - -#if !defined i_no_cmp - #if defined i_cmp || defined i_less || defined i_use_cmp - #define _i_has_cmp - #endif - #if defined i_eq || defined i_use_cmp - #define _i_has_eq - #endif +#if defined i_eq || defined i_use_cmp + #define _i_has_eq #endif -#if !(defined i_hash || defined i_no_hash || defined i_no_cmp) +#if !(defined i_hash || defined i_no_hash) #define i_hash c_default_hash #endif @@ -218,23 +208,21 @@ #define i_keydrop c_default_drop #endif -#ifndef i_no_cmp - // i_eq, i_less, i_cmp - #if !defined i_eq && (defined i_cmp || defined i_less) - #define i_eq(x, y) !(i_cmp(x, y)) - #elif !defined i_eq - #define i_eq(x, y) *x == *y - #endif - #if defined i_cmp && defined i_less - #error "Only one of i_cmp and i_less may be defined" - #elif defined i_cmp - #define i_less(x, y) (i_cmp(x, y)) < 0 - #elif !defined i_less - #define i_less(x, y) *x < *y - #endif - #ifndef i_cmp - #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y)) - #endif +// i_eq, i_less, i_cmp +#if !defined i_eq && (defined i_cmp || defined i_less) + #define i_eq(x, y) !(i_cmp(x, y)) +#elif !defined i_eq + #define i_eq(x, y) *x == *y +#endif +#if defined i_cmp && defined i_less + #error "Only one of i_cmp and i_less may be defined" +#elif defined i_cmp + #define i_less(x, y) (i_cmp(x, y)) < 0 +#elif !defined i_less + #define i_less(x, y) *x < *y +#endif +#ifndef i_cmp + #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y)) #endif #if defined _i_ismap // ---- process cmap/csmap value i_val, ... ---- diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 1e0d4a2e..44254601 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -68,7 +68,6 @@ #undef i_free #undef i_use_cmp -#undef i_no_cmp #undef i_no_hash #undef i_no_clone #undef i_no_emplace -- cgit v1.2.3 From 31ba4b2a36dee10b7e5d58561a2c0291cff6faeb Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 11 Aug 2023 22:43:59 +0200 Subject: Finalized converting to i_use_cmp (vs i_no_cmp) --- README.md | 10 ++++------ docs/cbox_api.md | 2 +- include/stc/carc.h | 9 ++++++--- include/stc/ccommon.h | 3 +-- misc/examples/smartpointers/arc_containers.c | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index fbdbd9fc..722d2559 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,6 @@ Let's make a vector of vectors, which can be cloned. All of its element vectors #define i_type Vec2D #define i_keyclass Vec // Use i_keyclass instead i_key when element type has "members" _clone(), _drop() and _cmp(). -#define i_opt c_no_cmp // Disable cmp (search/sort) for Vec2D because Vec_cmp() does not exist. #include int main(void) @@ -370,14 +369,14 @@ The list of template parameters: - `i_key` *Type* - Element key type. **[required]**. Note: `i_val` *may* be used instead for non-maps (not recommended). - `i_val` *Type* - Element value type. **[required for]** cmap/csmap as the mapped value type. -- `i_cmp` *Func* - Three-way comparison of two *i_keyraw*\* or *i_valraw*\* - **[required for]** non-integral *i_keyraw* elements unless *i_opt* is defined with *c_no_cmp*. +- `i_cmp` *Func* - Three-way comparison of two *i_keyraw*\* or *i_valraw*\* - **[required for]** non-integral *i_keyraw* elements. - `i_hash` *Func* - Hash function taking *i_keyraw*\* - defaults to *c_default_hash*. **[required for]** ***cmap/cset*** with non-POD *i_keyraw* elements. - `i_eq` *Func* - Equality comparison of two *i_keyraw*\* - defaults to *!i_cmp*. Companion with *i_hash*. Properties: - `i_tag` *Name* - Container type name tag. Defaults to *i_key* name. - `i_type` *Name* - Full container type name. Alternative to *i_tag*. -- `i_opt` *Flags* - Boolean properties: may combine *c_no_cmp*, *c_no_clone*, *c_no_atomic*, *c_is_forward*, *c_static*, *c_header* with the *|* separator. +- `i_opt` *Flags* - Boolean properties: may combine *c_no_clone*, *c_no_atomic*, *c_is_forward*, *c_static*, *c_header* with the *|* separator. Key: - `i_keydrop` *Func* - Destroy map/set key func - defaults to empty destructor. @@ -398,7 +397,7 @@ Specials: Meta-template parameters. Use instead of `i_key` / `i_val`. If `i_keyraw` is defined, it sets `i_keyto` = *Type_toraw()* and `i_keyfrom` = *Type_from()*. Only functions required by the container type is required to be defined. E.g.: - *Type_hash()* and *Type_eq()* are only required by **cmap**, **cset** and smart pointers. - - *Type_cmp()* is not used by **cstack** and **cmap/cset**, or if *#define i_opt c_no_cmp* is specified. + - *Type_cmp()* is not used by **cstack** and **cmap/cset**. - *Type_clone()* is not used if *#define i_opt c_no_clone* is specified. - `i_key_str` - Sets `i_keyclass` = *cstr*, `i_tag` = *str*, and `i_keyraw` = *const char*\*. Defines both type convertion `i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *const char\*\** as argument. @@ -409,7 +408,6 @@ NB: Do not use when defining carc/cbox types themselves. - `i_valclass` *Type*, `i_val_str`, `i_val_ssv`, `i_valboxed` - Similar rules as for ***key***. **Notes**: -- Instead of defining `i_cmp`, you may define *i_opt c_no_cmp* to disable *searching and sorting* functions. - Instead of defining `i_*clone`, you may define *i_opt c_no_clone* to disable *clone* functionality. - For `i_keyclass`, if *i_keyraw* is defined along with it, *i_keyfrom* may also be defined to enable the *emplace*-functions. NB: the signature for ***cmp***, ***eq***, and ***hash*** uses *i_keyraw* as input. @@ -764,6 +762,6 @@ Major changes: - Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`. - Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly. - Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions. -- Added: `i_opt` template parameter: compile-time options: `c_no_cmp`, `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` +- Added: `i_opt` template parameter: compile-time options: `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` - Added: [**cbox**](docs/cbox_api.md) type: smart pointer, similar to [Rust Box](https://doc.rust-lang.org/rust-by-example/std/box.html) and [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr). - Added: [**c_forpair**](docs/algorithm_api.md) macro: for-loop with "structured binding" diff --git a/docs/cbox_api.md b/docs/cbox_api.md index c683d9ef..7d25aed8 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -34,7 +34,7 @@ See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. -Define `i_opt` with `c_no_cmp` if comparison between i_key's is not needed/available. Will then +Unless `c_use_cmp` is defined, comparison between i_key's is not needed/available. Will then compare the pointer addresses when used. Additionally, `c_no_clone` or `i_is_fwd` may be defined. ## Methods diff --git a/include/stc/carc.h b/include/stc/carc.h index e987f453..1b1c22eb 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -43,7 +43,6 @@ void Person_drop(Person* p) { #define i_type ArcPers #define i_valclass Person // clone, drop, cmp, hash -#define i_opt c_no_cmp|c_no_hash // exclude cmp, hash #include int main(void) { @@ -86,7 +85,10 @@ int main(void) { #include "priv/template.h" typedef i_keyraw _cx_raw; -#if !c_option(c_no_atomic) +#if c_option(c_no_atomic) + #define i_no_atomic +#endif +#if !defined i_no_atomic #define _i_atomic_inc(v) c_atomic_inc(v) #define _i_atomic_dec_and_test(v) c_atomic_dec_and_test(v) #else @@ -213,7 +215,8 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { { return c_default_hash(&self->get); } #endif // i_use_cmp +#include "priv/template2.h" +#undef i_no_atomic #undef _i_atomic_inc #undef _i_atomic_dec_and_test -#include "priv/template2.h" #undef _i_carc diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index b37ad1da..45fa01c6 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -116,9 +116,8 @@ typedef long long _llong; #define c_no_atomic (1<<1) #define c_no_clone (1<<2) #define c_no_emplace (1<<3) -#define c_no_cmp (1<<4) +#define c_no_hash (1<<4) #define c_use_cmp (1<<5) -#define c_no_hash (1<<6) /* Function macros and others */ #define c_litstrlen(literal) (c_sizeof("" literal) - 1) diff --git a/misc/examples/smartpointers/arc_containers.c b/misc/examples/smartpointers/arc_containers.c index c2bff56f..79211d2b 100644 --- a/misc/examples/smartpointers/arc_containers.c +++ b/misc/examples/smartpointers/arc_containers.c @@ -12,7 +12,7 @@ #define i_key Map #define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) // no need for atomic ref. count in single thread: -#define i_opt c_no_atomic|c_no_cmp +#define i_opt c_no_atomic #include #define i_type Stack -- cgit v1.2.3 From ea878349e94ef00643b2510045f6482385cff1a7 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 11 Aug 2023 23:11:01 +0200 Subject: Updated godbolt code. --- README.md | 2 +- docs/algorithm_api.md | 2 +- docs/coroutine_api.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 722d2559..d516f389 100644 --- a/README.md +++ b/README.md @@ -240,7 +240,7 @@ int main(void) ``` This example uses four different container types: -[ [Run this code](https://godbolt.org/z/qor16Gf6j) ] +[ [Run this code](https://godbolt.org/z/j68od14hv) ] ```c #include diff --git a/docs/algorithm_api.md b/docs/algorithm_api.md index 127aa120..63bced22 100644 --- a/docs/algorithm_api.md +++ b/docs/algorithm_api.md @@ -128,7 +128,7 @@ Iterate a container or a crange with chained `&&` filtering. | `c_flt_counter(it)` | Increment current and return count | | `c_flt_getcount(it)` | Number of items passed skip*/take*/counter | -[ [Run this example](https://godbolt.org/z/n9aYrYPv8) ] +[ [Run this example](https://godbolt.org/z/exqYEK6qa) ] ```c #include #include diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md index 6bd558f2..f7d81a34 100644 --- a/docs/coroutine_api.md +++ b/docs/coroutine_api.md @@ -78,7 +78,7 @@ yield or await from a (deeply) nested coroutine call using cco_task objects desc The first example is a generator of Pythagorian triples, and stops when diagonal size > max_c. -[ [Run this code](https://godbolt.org/z/3Efn17cP6) ] +[ [Run this code](https://godbolt.org/z/d5zW3f9Gv) ] ```c #include #include @@ -126,7 +126,7 @@ The next variant skips the triples which are upscaled version of smaller ones by the gcd() function. Note that the gcd1_triples struct contains the triples struct so that both functions have separate call frames: -[ [Run this code](https://godbolt.org/z/ndhMq1haj) ] +[ [Run this code](https://godbolt.org/z/a7da9M8P5) ] ```c int gcd(int a, int b) { // greatest common denominator while (b) { -- cgit v1.2.3 From 25dc58db206714dc02c1ae0548f6ba7dd3519d29 Mon Sep 17 00:00:00 2001 From: tylov Date: Sun, 13 Aug 2023 23:15:45 +0200 Subject: API CHANGES: Changed csview: becomes a null-terminated string view. Added csubview: a null-terminated string view/span, like previous csview. Note that csview works like a csubview, so not much compability issues should arise. However, some functions have changed from _sv suffix to _ss. --- README.md | 30 ++-- docs/cmap_api.md | 2 +- docs/coroutine_api.md | 2 +- docs/cregex_api.md | 28 +-- docs/cstr_api.md | 44 +++-- docs/csubstr_api.md | 217 +++++++++++++++++++++++ docs/csview_api.md | 151 +++------------- include/stc/ccommon.h | 8 +- include/stc/cregex.h | 36 ++-- include/stc/cstr.h | 100 ++++++----- include/stc/csubstr.h | 208 ++++++++++++++++++++++ include/stc/csview.h | 155 ++++------------ include/stc/forward.h | 25 ++- include/stc/priv/template.h | 14 +- include/stc/utf8.h | 4 +- misc/benchmarks/various/string_bench_STC.cpp | 32 ++-- misc/examples/algorithms/forfilter.c | 12 +- misc/examples/regularexpressions/regex2.c | 2 +- misc/examples/regularexpressions/regex_match.c | 4 +- misc/examples/regularexpressions/regex_replace.c | 6 +- misc/examples/strings/cstr_match.c | 12 +- misc/examples/strings/replace.c | 4 +- misc/examples/strings/splitstr.c | 8 +- misc/examples/strings/sso_substr.c | 16 +- misc/examples/strings/sview_split.c | 14 +- misc/examples/strings/utf8replace_c.c | 4 +- misc/tests/cregex_test.c | 32 ++-- src/cregex.c | 28 +-- src/libstc.c | 2 +- src/singleupdate.sh | 2 +- src/utf8code.c | 2 +- 31 files changed, 733 insertions(+), 471 deletions(-) create mode 100644 docs/csubstr_api.md create mode 100644 include/stc/csubstr.h (limited to 'README.md') diff --git a/README.md b/README.md index d516f389..96479fa0 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Containers - [***csset*** - **std::set** sorted set alike type](docs/csset_api.md) - [***cstack*** - **std::stack** alike type](docs/cstack_api.md) - [***cstr*** - **std::string** alike type](docs/cstr_api.md) -- [***csview*** - **std::string_view** alike type](docs/csview_api.md) +- [***csubstr*** - **std::string_view** alike type](docs/csubstr_api.md) - [***cspan*** - **std::span/std::mdspan** alike type](docs/cspan_api.md) - [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md) - [***cvec*** - **std::vector** alike type](docs/cvec_api.md) @@ -351,11 +351,11 @@ linking, so *one* c-file must implement the templated container, e.g.: #include "cvec_int.h" ``` The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by -`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so +`#define i_static`. Same for the string-view type **csubstr**, but most of its functions are static inlined, so linking specifications and implementation are only needed for a few lesser used functions. Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**, -**csview**, **cregex**, **utf8**, and **crand**. +**csubstr**, **cregex**, **utf8**, and **crand**. As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent **utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc. @@ -401,8 +401,8 @@ Only functions required by the container type is required to be defined. E.g.: - *Type_clone()* is not used if *#define i_opt c_no_clone* is specified. - `i_key_str` - Sets `i_keyclass` = *cstr*, `i_tag` = *str*, and `i_keyraw` = *const char*\*. Defines both type convertion `i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *const char\*\** as argument. -- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csview\**. Defines both type convertion -`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csview\** as argument. +- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csubstr\**. Defines both type convertion +`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csubstr\** as argument. - `i_keyboxed` *Type* - Use when *Type* is a smart pointer **carc** or **cbox**. Defines *i_keyclass = Type*, and *i_keyraw = Type\**. NB: Do not use when defining carc/cbox types themselves. - `i_valclass` *Type*, `i_val_str`, `i_val_ssv`, `i_valboxed` - Similar rules as for ***key***. @@ -640,7 +640,7 @@ void maptest() STC is generally very memory efficient. Memory usage for the different containers: - **cstr**, **cvec**, **cstack**, **cpque**: 1 pointer, 2 intptr_t + memory for elements. -- **csview**, 1 pointer, 1 intptr_t. Does not own data! +- **csubstr**, 1 pointer, 1 intptr_t. Does not own data! - **cspan**, 1 pointer and 2 \* dimension \* int32_t. Does not own data! - **clist**: Type size: 1 pointer. Each node allocates a struct to store its value and a next pointer. - **cdeq**, **cqueue**: Type size: 2 pointers, 2 intptr_t. Otherwise like *cvec*. @@ -654,7 +654,7 @@ STC is generally very memory efficient. Memory usage for the different container ## Version 4.3 - Breaking changes: - - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. + - **cstr** and **csubstr** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. - Renamed => `` - Moved => `` - Much improved with some new API and added features. @@ -686,7 +686,7 @@ STC is generally very memory efficient. Memory usage for the different container - Renamed c_flt_count(i) => `c_flt_counter(i)` - Renamed c_flt_last(i) => `c_flt_getcount(i)` - Renamed c_ARRAYLEN() => c_arraylen() -- Removed deprecated c_ARGSV(). Use c_SV() +- Removed deprecated c_ARGSV(). Use c_SS() - Removed c_PAIR ## Version 4.1.1 @@ -699,7 +699,7 @@ Major changes: - [crange](docs/algorithm_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - [c_forfilter](docs/algorithm_api.md#c_forfilter) - ranges-like view filtering. - [csort](include/stc/algo/sort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. -- Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. +- Renamed `c_ARGSV()` => `c_SS()`: **csubstr** print arg. Note `c_ss()` is shorthand for *csubstr_from()*. - Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. - Some API changes in **cregex** and **cstr**. - Create single header container versions with python script. @@ -713,18 +713,18 @@ Major changes: - New + renamed loop iteration/scope macros: - `c_forlist`: macro replacing `c_forarray` and `c_apply`. Iterate a compound literal list. - `c_forrange`: macro replacing `c_forrange`. Iterate a `long long` type number sequence. -- Updated **cstr**, now always takes self as pointer, like all containers except csview. +- Updated **cstr**, now always takes self as pointer, like all containers except csubstr. - Updated **cvec**, **cdeq**, changed `*_range*` function names. ## Changes version 3.8 -- Overhauled some **cstr** and **csview** API: +- Overhauled some **cstr** and **csubstr** API: - Changed cstr_replace*() => `cstr_replace_at*(self, pos, len, repl)`: Replace at specific position. - Changed `cstr_replace_all() cstr_replace*(self, search, repl, count)`: Replace count occurences. - Renamed `cstr_find_from()` => `cstr_find_at()` - Renamed `cstr_*_u8()` => `cstr_u8_*()` - - Renamed `csview_*_u8()` => `csview_u8_*()` - - Added cstr_u8_slice() and csview_u8_slice(). - - Removed `csview_from_s()`: Use `cstr_sv(s)` instead. + - Renamed `csubstr_*_u8()` => `csubstr_u8_*()` + - Added cstr_u8_slice() and csubstr_u8_slice(). + - Removed `csubstr_from_s()`: Use `cstr_ss(s)` instead. - Added back file coption.h - Simplified **cbits** usage: all inlined. - Updated docs. @@ -759,7 +759,7 @@ Major changes: - Renamed: *cstr_new()* to `cstr_lit(literal)`, and *cstr_assign_fmt()* to `cstr_printf()`. - Renamed: *c_default_fromraw()* to `c_default_from()`. - Changed: the [**c_apply**](docs/algorithm_api.md) macros API. -- Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`. +- Replaced: *csubstr_first_token()* and *csubstr_next_token()* with one function: `csubstr_token()`. - Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly. - Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions. - Added: `i_opt` template parameter: compile-time options: `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 4e6da57d..65777221 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -282,7 +282,7 @@ typedef struct { cstr country; } Viking; -#define Viking_init() ((Viking){cstr_null, cstr_null}) +#define Viking_init() ((Viking){.name={0}, .country={0}}) static inline int Viking_cmp(const Viking* a, const Viking* b) { int c = cstr_cmp(&a->name, &b->name); diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md index f7d81a34..c44f4a4d 100644 --- a/docs/coroutine_api.md +++ b/docs/coroutine_api.md @@ -237,7 +237,7 @@ cco_task_struct (produce_items, int produce_items(struct produce_items* p, cco_runtime* rt) { cco_routine (p) { - p->str = cstr_null; + p->str = cstr_init(); p->next.cco_func = next_value; while (true) { diff --git a/docs/cregex_api.md b/docs/cregex_api.md index 52476e09..98161fe9 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -33,11 +33,11 @@ int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_ int cregex_captures(const cregex* self); // return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR -int cregex_find(const cregex* re, const char* input, csview match[], int mflags = CREG_DEFAULT); +int cregex_find(const cregex* re, const char* input, csubstr match[], int mflags = CREG_DEFAULT); // Search inside input string-view only -int cregex_find_sv(const cregex* re, csview input, csview match[]); +int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]); // All-in-one search (compile + find + drop) -int cregex_find_pattern(const char* pattern, const char* input, csview match[], int cmflags = CREG_DEFAULT); +int cregex_find_pattern(const char* pattern, const char* input, csubstr match[], int cmflags = CREG_DEFAULT); // Check if there are matches in input bool cregex_is_match(const cregex* re, const char* input); @@ -45,14 +45,14 @@ bool cregex_is_match(const cregex* re, const char* input); // Replace all matches in input cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX); // Replace count matches in input string-view. Optionally transform replacement. -cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX); -cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count, - bool(*transform)(int group, csview match, cstr* result), int rflags); +cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count = INT_MAX); +cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count, + bool(*transform)(int group, csubstr match, cstr* result), int rflags); // All-in-one replacement (compile + find/replace + drop) cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX); cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count, - bool(*transform)(int group, csview match, cstr* result), int rflags); + bool(*transform)(int group, csubstr match, cstr* result), int rflags); // destroy void cregex_drop(cregex* self); ``` @@ -109,9 +109,9 @@ int main(void) { cregex re = cregex_from(pattern); // Lets find the first date in the string: - csview match[4]; // full-match, year, month, date. + csubstr match[4]; // full-match, year, month, date. if (cregex_find(&re, input, match) == CREG_OK) - printf("Found date: %.*s\n", c_SV(match[0])); + printf("Found date: %.*s\n", c_SS(match[0])); else printf("Could not find any date\n"); @@ -127,7 +127,7 @@ int main(void) { For a single match you may use the all-in-one function: ```c if (cregex_find_pattern(pattern, input, match)) - printf("Found date: %.*s\n", c_SV(match[0])); + printf("Found date: %.*s\n", c_SS(match[0])); ``` To use: `gcc first_match.c src/cregex.c src/utf8code.c`. @@ -137,16 +137,16 @@ In order to use a callback function in the replace call, see `examples/regex_rep To iterate multiple matches in an input string, you may use ```c -csview match[5] = {0}; +csubstr match[5] = {0}; while (cregex_find(&re, input, match, CREG_NEXT) == CREG_OK) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SV(match[k])); + printf("submatch %d: %.*s\n", k, c_SS(match[k])); ``` There is also a for-loop macro to simplify it: ```c c_formatch (it, &re, input) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SV(it.match[k])); + printf("submatch %d: %.*s\n", k, c_SS(it.match[k])); ``` ## Using cregex in a project @@ -154,7 +154,7 @@ c_formatch (it, &re, input) The easiest is to `#define i_import` before `#include `. Make sure to do that in one translation unit only. For reference, **cregex** uses the following files: -- `stc/cregex.h`, `stc/utf8.h`, `stc/csview.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` +- `stc/cregex.h`, `stc/utf8.h`, `stc/csubstr.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` - `src/cregex.c`, `src/utf8code.c`. ## Regex Cheatsheet diff --git a/docs/cstr_api.md b/docs/cstr_api.md index dae5669f..36606b76 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -18,11 +18,11 @@ All cstr definitions and prototypes are available by including a single header f ## Methods ```c -cstr cstr_init(void); // constructor; same as cstr_null. +cstr cstr_init(void); // constructor; empty string cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call. cstr cstr_from(const char* str); // constructor using strlen() cstr cstr_from_n(const char* str, intptr_t n); // constructor with n first bytes of str -cstr cstr_from_sv(csview sv); // construct cstr from csview +cstr cstr_from_ss(csubstr sv); // construct cstr from csubstr cstr cstr_with_capacity(intptr_t cap); cstr cstr_with_size(intptr_t len, char fill); // repeat fill len times cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting @@ -34,7 +34,7 @@ void cstr_drop(cstr* self); // destructo const char* cstr_str(const cstr* self); // cast to const char* char* cstr_data(cstr* self); // cast to mutable char* -csview cstr_sv(const cstr* self); // cast to string view +csubstr cstr_ss(const cstr* self); // cast to string view cstr_buf cstr_buffer(cstr* self); // cast to mutable buffer (with capacity) intptr_t cstr_size(const cstr* self); @@ -48,13 +48,13 @@ void cstr_clear(cstr* self); char* cstr_assign(cstr* self, const char* str); char* cstr_assign_n(cstr* self, const char* str, intptr_t n); // assign n first bytes of str -char* cstr_assign_sv(cstr* self, csview sv); +char* cstr_assign_ss(cstr* self, csubstr sv); char* cstr_copy(cstr* self, cstr s); // copy-assign a cstr int cstr_printf(cstr* self, const char* fmt, ...); // source and target must not overlap. char* cstr_append(cstr* self, const char* str); char* cstr_append_n(cstr* self, const char* str, intptr_t n); // append n first bytes of str -char* cstr_append_sv(cstr* self, csview str); +char* cstr_append_ss(cstr* self, csubstr str); char* cstr_append_s(cstr* self, cstr str); int cstr_append_fmt(cstr* self, const char* fmt, ...); // printf() formatting char* cstr_append_uninit(cstr* self, intptr_t len); // return ptr to start of uninited data @@ -63,19 +63,19 @@ void cstr_push(cstr* self, const char* chr); // append on void cstr_pop(cstr* self); // pop one utf8 char void cstr_insert(cstr* self, intptr_t pos, const char* ins); -void cstr_insert_sv(cstr* self, intptr_t pos, csview ins); +void cstr_insert_ss(cstr* self, intptr_t pos, csubstr ins); void cstr_insert_s(cstr* self, intptr_t pos, cstr ins); void cstr_erase(cstr* self, intptr_t pos, intptr_t len); // erase len bytes from pos void cstr_replace(cstr* self, const char* search, const char* repl, unsigned count = MAX_INT); -cstr cstr_replace_sv(csview in, csview search, csview repl, unsigned count); +cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, unsigned count); void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl); // replace at a pos -void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl); +void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl); void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl); bool cstr_equals(const cstr* self, const char* str); -bool cstr_equals_sv(const cstr* self, csview sv); +bool cstr_equals_ss(const cstr* self, csubstr sv); bool cstr_equals_s(const cstr* self, cstr s); intptr_t cstr_find(const cstr* self, const char* search); @@ -83,11 +83,11 @@ intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); // bool cstr_contains(const cstr* self, const char* search); bool cstr_starts_with(const cstr* self, const char* str); -bool cstr_starts_with_sv(const cstr* self, csview sv); +bool cstr_starts_with_ss(const cstr* self, csubstr sv); bool cstr_starts_with_s(const cstr* self, cstr s); bool cstr_ends_with(const cstr* self, const char* str); -bool cstr_ends_with_sv(const cstr* self, csview sv); +bool cstr_ends_with_ss(const cstr* self, csubstr sv); bool cstr_ends_with_s(const cstr* self, cstr s); bool cstr_getline(cstr *self, FILE *stream); // cstr_getdelim(self, '\n', stream) @@ -100,8 +100,8 @@ intptr_t cstr_u8_size(const cstr* self); // number of intptr_t cstr_u8_size_n(const cstr self, intptr_t nbytes); // utf8 size within n bytes intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx); // byte pos offset at utf8 codepoint index const char* cstr_u8_at(const cstr* self, intptr_t u8idx); // char* position at utf8 codepoint index -csview cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csview -void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl); // replace u8len utf8 chars +csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csubstr +void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl); // replace u8len utf8 chars void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); // erase u8len codepoints from pos // iterate utf8 codepoints @@ -112,14 +112,14 @@ cstr_iter cstr_advance(cstr_iter it, intptr_t n); // utf8 functions requires linking with src/utf8code.c symbols: bool cstr_valid_utf8(const cstr* self); // check if str is valid utf8 -cstr cstr_casefold_sv(csview sv); // returns new casefolded utf8 cstr +cstr cstr_casefold_ss(csubstr sv); // returns new casefolded utf8 cstr cstr cstr_tolower(const char* str); // returns new lowercase utf8 cstr -cstr cstr_tolower_sv(csview sv); // returns new lowercase utf8 cstr +cstr cstr_tolower_ss(csubstr sv); // returns new lowercase utf8 cstr void cstr_lowercase(cstr* self); // transform cstr to lowercase utf8 cstr cstr_toupper(const char* str); // returns new uppercase utf8 cstr -cstr cstr_toupper_sv(csview sv); // returns new uppercase utf8 cstr +cstr cstr_toupper_ss(csubstr sv); // returns new uppercase utf8 cstr void cstr_uppercase(cstr* self); // transform cstr to uppercase utf8 int cstr_icmp(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison @@ -132,11 +132,10 @@ Note that all methods with arguments `(..., const char* str, intptr_t n)`, `n` m #### Helper methods: ```c -int cstr_cmp(const cstr* s1, const cstr* s2); -bool cstr_eq(const cstr* s1, const cstr* s2); -bool cstr_hash(const cstr* self); - -char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen); +int cstr_cmp(const cstr* s1, const cstr* s2); +bool cstr_eq(const cstr* s1, const cstr* s2); +bool cstr_hash(const cstr* self); +char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen); ``` ## Types @@ -145,7 +144,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt |:----------------|:---------------------------------------------|:---------------------| | `cstr` | `struct { ... }` | The string type | | `cstr_value` | `char` | String element type | -| `csview` | `struct { const char *str; intptr_t size; }` | String view type | +| `csubstr` | `struct { const char *str; intptr_t size; }` | String view type | | `cstr_buf` | `struct { char *data; intptr_t size, cap; }` | String buffer type | ## Constants and macros @@ -153,7 +152,6 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt | Name | Value | |:------------------|:------------------| | `c_NPOS` | `INTPTR_MAX` | -| `cstr_null` | empty cstr value | ## Example ```c diff --git a/docs/csubstr_api.md b/docs/csubstr_api.md new file mode 100644 index 00000000..925c69db --- /dev/null +++ b/docs/csubstr_api.md @@ -0,0 +1,217 @@ +# STC [csubstr](../include/stc/csubstr.h): String View +![String](pics/string.jpg) + +The type **csubstr** is a string view and can refer to a constant contiguous sequence of char-elements with the first +element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size. + +**csubstr** is non-null terminated, and therefore not a replacent for `const char*` - see [csview](csview_api.md) for +that. **csubstr** never allocates memory, and therefore need not be destructed. +Its lifetime is limited by the source string storage. It keeps the length of the string, and does not need to call +*strlen()* to acquire the length. + +Note: a **csubstr** may ***not be null-terminated***, and must therefore be printed this way: +```c +printf("%.*s", c_SS(sstr)) +``` + +See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional +description. + +## Header file + +All csubstr definitions and prototypes are available by including a single header file. + +```c +#define i_implement +#include +#include // after cstr.h: include extra cstr-csubstr functions +``` +## Methods + +```c +csubstr c_ss(const char literal_only[]); // construct from literal, no strlen() +csubstr c_ss(const char* str, intptr_t n); // construct from str and length n +csubstr csubstr_from(const char* str); // construct from const char* +csubstr csubstr_from_n(const char* str, intptr_t n); // alias for c_ss(str, n) + +intptr_t csubstr_size(csubstr sv); +bool csubstr_empty(csubstr sv); +void csubstr_clear(csubstr* self); + +bool csubstr_equals(csubstr sv, csubstr sv2); +intptr_t csubstr_find(csubstr sv, const char* str); +intptr_t csubstr_find_ss(csubstr sv, csubstr find); +bool csubstr_contains(csubstr sv, const char* str); +bool csubstr_starts_with(csubstr sv, const char* str); +bool csubstr_ends_with(csubstr sv, const char* str); + +csubstr csubstr_substr_ex(csubstr sv, intptr_t pos, intptr_t n); // negative pos count from end +csubstr csubstr_slice_ex(csubstr sv, intptr_t p1, intptr_t p2); // negative p1, p2 count from end +csubstr csubstr_token(csubstr sv, const char* sep, intptr_t* start); // *start > sv.size after last token +``` + +#### UTF8 methods +```c +intptr_t csubstr_u8_size(csubstr sv); +csubstr csubstr_u8_substr(csubstr sv, intptr_t bytepos, intptr_t u8len); +bool csubstr_valid_utf8(csubstr sv); // requires linking with src/utf8code.c + +csubstr_iter csubstr_begin(const csubstr* self); +csubstr_iter csubstr_end(const csubstr* self); +void csubstr_next(csubstr_iter* it); // utf8 codepoint step, not byte! +csubstr_iter csubstr_advance(csubstr_iter it, intptr_t n); +``` + +#### Extended cstr methods +```c +csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n); +csubstr cstr_substr_ex(const cstr* s, intptr_t pos, intptr_t n); // negative pos count from end +csubstr cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); + +csubstr cstr_slice(const cstr* self, intptr_t p1, intptr_t p2); +csubstr cstr_slice_ex(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end +``` +#### Iterate tokens with *c_fortoken*, *c_fortoken_ss* + +To iterate tokens in an input string separated by a string: +```c +c_fortoken (i, "hello, one, two, three", ", ") + printf("token: %.*s\n", c_SS(i.token)); +``` + +#### Helper methods +```c +int csubstr_cmp(const csubstr* x, const csubstr* y); +int csubstr_icmp(const csubstr* x, const csubstr* y); +bool csubstr_eq(const csubstr* x, const csubstr* y); +uint64_t csubstr_hash(const csubstr* x); +``` + +## Types + +| Type name | Type definition | Used to represent... | +|:----------------|:-------------------------------------------|:-------------------------| +| `csubstr` | `struct { const char *str; intptr_t size; }` | The string view type | +| `csubstr_value` | `char` | The string element type | +| `csubstr_iter` | `struct { csubstr_value *ref; }` | UTF8 iterator | + +## Constants and macros + +| Name | Value | Usage | +|:---------------|:---------------------|:---------------------------------------------| +| `c_SS(sv)` | printf argument | `printf("sv: %.*s\n", c_SS(sv));` | + +## Example +```c +#define i_implement +#include +#include + +int main(void) +{ + cstr str1 = cstr_lit("We think in generalities, but we live in details."); + // (quoting Alfred N. Whitehead) + + csubstr sv1 = cstr_substr_ex(&str1, 3, 5); // "think" + intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 + csubstr sv2 = cstr_substr_ex(&str1, pos, 4); // get "live" + csubstr sv3 = cstr_slice_ex(&str1, -8, -1); // get "details" + printf("%.*s %.*s %.*s\n", + c_SS(sv1), c_SS(sv2), c_SS(sv3)); + cstr s1 = cstr_lit("Apples are red"); + cstr s2 = cstr_from_ss(cstr_substr_ex(&s1, -3, 3)); // "red" + cstr s3 = cstr_from_ss(cstr_substr_ex(&s1, 0, 6)); // "Apples" + printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); + + c_drop(cstr, &str1, &s1, &s2, &s3); +} +``` +Output: +``` +think live details +red Apples +``` + +### Example 2: UTF8 handling +```c +#define i_import // include dependent cstr, utf8 and cregex function definitions. +#include + +int main(void) +{ + cstr s1 = cstr_lit("hell😀 w😀rld"); + + cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_ss("ø")); + printf("%s\n", cstr_str(&s1)); + + c_foreach (i, cstr, s1) + printf("%.*s,", c_SS(i.u8.chr)); + + cstr_drop(&s1); +} +``` +Output: +``` +hell😀 wørld +h,e,l,l,😀, ,w,ø,r,l,d, +``` + +### Example 3: csubstr tokenizer (string split) +Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, +and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. +```c +#include +#include + +void print_split(csubstr input, const char* sep) +{ + c_fortoken_ss (i, input, sep) + printf("[%.*s]\n", c_SS(i.token)); + puts(""); +} +#define i_implement +#include +#define i_key_str +#include + +cstack_str string_split(csubstr input, const char* sep) +{ + cstack_str out = cstack_str_init(); + + c_fortoken_ss (i, input, sep) + cstack_str_push(&out, cstr_from_ss(i.token)); + + return out; +} + +int main(void) +{ + print_split(c_ss("//This is a//double-slash//separated//string"), "//"); + print_split(c_ss("This has no matching separator"), "xx"); + + cstack_str s = string_split(c_ss("Split,this,,string,now,"), ","); + + c_foreach (i, cstack_str, s) + printf("[%s]\n", cstr_str(i.ref)); + puts(""); + + cstack_str_drop(&s); +} +``` +Output: +``` +[] +[This is a] +[double-slash] +[separated] +[string] + +[This has no matching separator] + +[Split] +[this] +[] +[string] +[now] +[] +``` diff --git a/docs/csview_api.md b/docs/csview_api.md index 49e4f9d1..4fdff0d1 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -1,19 +1,14 @@ # STC [csview](../include/stc/csview.h): String View ![String](pics/string.jpg) -The type **csview** is a string view and can refer to a constant contiguous sequence of char-elements with the first -element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size. +The type **csview** is a ***null-terminated*** string view and refers to a constant contiguous sequence of +char-elements with the first element of the sequence at position zero. The implementation holds two +members: a pointer to constant char and a size. See [csubstr](csubstr_api.md) for a ***non null-terminated*** +string view/span type. -**csview** is an efficient replacent for `const char*`. It never allocates memory, and therefore need not be destructed. -Its lifetime is limited by the source string storage. It keeps the length of the string, and does not call *strlen()* -when passing it around. It is faster when using`csview` as convertion type (raw) than `const char*` in associative -containers with cstr keys. - -Note: a **csview** may ***not be null-terminated***, and must therefore be printed like: -`printf("%.*s", csview_ARG(sv))`. - -See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional -description. +Because **csview** is null-terminated, it can be a more efficient replacent for `const char*`. It never +allocates memory, and need therefore not be destructed. Its lifetime is limited by the source string +storage. It keeps the length of the string, and does not call *strlen()* when passing it around. ## Header file @@ -42,17 +37,12 @@ intptr_t csview_find_sv(csview sv, csview find); bool csview_contains(csview sv, const char* str); bool csview_starts_with(csview sv, const char* str); bool csview_ends_with(csview sv, const char* str); - -csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); // negative pos count from end -csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); // negative p1, p2 count from end -csview csview_token(csview sv, const char* sep, intptr_t* start); // *start > sv.size after last token ``` #### UTF8 methods ```c intptr_t csview_u8_size(csview sv); -csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len); -bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c +bool csview_valid_utf8(csview sv); // depends on src/utf8code.c csview_iter csview_begin(const csview* self); csview_iter csview_end(const csview* self); @@ -74,27 +64,10 @@ uint32_t utf8_peek(const char* s); // codep uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative) ``` -#### Extended cstr methods -```c -csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n); -csview cstr_substr_ex(const cstr* s, intptr_t pos, intptr_t n); // negative pos count from end -csview cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); - -csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2); -csview cstr_slice_ex(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end -``` -#### Iterate tokens with *c_fortoken*, *c_fortoken_sv* - -To iterate tokens in an input string separated by a string: -```c -c_fortoken (i, "hello, one, two, three", ", ") - printf("token: %.*s\n", c_SV(i.token)); -``` - #### Helper methods ```c int csview_cmp(const csview* x, const csview* y); -int csview_icmp(const csview* x, const csview* y); +int csview_icmp(const csview* x, const csview* y); // depends on src/utf8code.c: bool csview_eq(const csview* x, const csview* y); uint64_t csview_hash(const csview* x); ``` @@ -107,46 +80,36 @@ uint64_t csview_hash(const csview* x); | `csview_value` | `char` | The string element type | | `csview_iter` | `struct { csview_value *ref; }` | UTF8 iterator | -## Constants and macros - -| Name | Value | Usage | -|:---------------|:---------------------|:---------------------------------------------| -| `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` | - -## Example +## Example: UTF8 iteration and case conversion ```c -#define i_implement +#define i_import #include #include int main(void) { - cstr str1 = cstr_lit("We think in generalities, but we live in details."); - // (quoting Alfred N. Whitehead) - - csview sv1 = cstr_substr_ex(&str1, 3, 5); // "think" - intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 - csview sv2 = cstr_substr_ex(&str1, pos, 4); // get "live" - csview sv3 = cstr_slice_ex(&str1, -8, -1); // get "details" - printf("%.*s %.*s %.*s\n", - c_SV(sv1), c_SV(sv2), c_SV(sv3)); - cstr s1 = cstr_lit("Apples are red"); - cstr s2 = cstr_from_sv(cstr_substr_ex(&s1, -3, 3)); // "red" - cstr s3 = cstr_from_sv(cstr_substr_ex(&s1, 0, 6)); // "Apples" - printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); - - c_drop(cstr, &str1, &s1, &s2, &s3); + cstr str = cstr_from("Liberté, égalité, fraternité."); + csview sv = cstr_sv(&str); + + c_foreach (i, csview, sv) + printf("%.*s ", c_SS(i.u8.chr)); + puts(""); + + cstr_uppercase(&str); + printf("%s\n", cstr_str(&str)); + + cstr_drop(&str); } ``` Output: ``` -think live details -red Apples +L i b e r t é , é g a l i t é , f r a t e r n i t é . +LIBERTÉ, ÉGALITÉ, FRATERNITÉ. ``` -### Example 2: UTF8 handling +### Example 2: UTF8 replace ```c -#define i_import // include dependent cstr, utf8 and cregex function definitions. +#define i_import // include dependent utf8 definitions. #include int main(void) @@ -157,7 +120,7 @@ int main(void) printf("%s\n", cstr_str(&s1)); c_foreach (i, cstr, s1) - printf("%.*s,", c_SV(i.u8.chr)); + printf("%.*s,", c_SS(i.u8.chr)); // u8.chr is a csubstr cstr_drop(&s1); } @@ -167,63 +130,3 @@ Output: hell😀 wørld h,e,l,l,😀, ,w,ø,r,l,d, ``` - -### Example 3: csview tokenizer (string split) -Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, -and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. -```c -#include -#include - -void print_split(csview input, const char* sep) -{ - c_fortoken_sv (i, input, sep) - printf("[%.*s]\n", c_SV(i.token)); - puts(""); -} -#define i_implement -#include -#define i_key_str -#include - -cstack_str string_split(csview input, const char* sep) -{ - cstack_str out = cstack_str_init(); - - c_fortoken_sv (i, input, sep) - cstack_str_push(&out, cstr_from_sv(i.token)); - - return out; -} - -int main(void) -{ - print_split(c_sv("//This is a//double-slash//separated//string"), "//"); - print_split(c_sv("This has no matching separator"), "xx"); - - cstack_str s = string_split(c_sv("Split,this,,string,now,"), ","); - - c_foreach (i, cstack_str, s) - printf("[%s]\n", cstr_str(i.ref)); - puts(""); - - cstack_str_drop(&s); -} -``` -Output: -``` -[] -[This is a] -[double-slash] -[separated] -[string] - -[This has no matching separator] - -[Split] -[this] -[] -[string] -[now] -[] -``` diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 45fa01c6..24967a10 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -130,11 +130,15 @@ typedef const char* ccharptr; #define ccharptr_clone(s) (s) #define ccharptr_drop(p) ((void)p) +#define c_ss(...) c_MACRO_OVERLOAD(c_ss, __VA_ARGS__) +#define c_ss_1(literal) c_ss_2(literal, c_litstrlen(literal)) +#define c_ss_2(str, n) (c_LITERAL(csubstr){str, n}) +#define c_SS(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SS(ss)); + #define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) -#define c_sv_1(lit) c_sv_2(lit, c_litstrlen(lit)) +#define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal)) #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) -#define c_SV(sv) (int)(sv).size, (sv).str // print csview: use format "%.*s" #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { diff --git a/include/stc/cregex.h b/include/stc/cregex.h index bce94b04..3aab3c8b 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -34,7 +34,7 @@ THE SOFTWARE. */ #include #include -#include "forward.h" // csview +#include "forward.h" // csubstr #include "ccommon.h" enum { @@ -82,7 +82,7 @@ typedef struct { typedef struct { const cregex* re; const char* input; - csview match[CREG_MAX_CAPTURES]; + csubstr match[CREG_MAX_CAPTURES]; } cregex_iter; #define c_formatch(it, Re, Input) \ @@ -115,11 +115,11 @@ int cregex_captures(const cregex* re); /* return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */ #define cregex_find(...) c_MACRO_OVERLOAD(cregex_find, __VA_ARGS__) #define cregex_find_3(re, input, match) cregex_find_4(re, input, match, CREG_DEFAULT) -int cregex_find_4(const cregex* re, const char* input, csview match[], int mflags); +int cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags); -/* find with csview as input. */ -STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { - csview *mp = NULL; +/* find with csubstr as input. */ +STC_INLINE int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]) { + csubstr *mp = NULL; if (match) { match[0] = input; mp = match; } return cregex_find(re, input.str, mp, CREG_STARTEND); } @@ -129,27 +129,27 @@ STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { #define cregex_find_pattern_3(pattern, input, match) \ cregex_find_pattern_4(pattern, input, match, CREG_DEFAULT) int cregex_find_pattern_4(const char* pattern, const char* input, - csview match[], int cmflags); + csubstr match[], int cmflags); STC_INLINE bool cregex_is_match(const cregex* re, const char* input) { return cregex_find_4(re, input, NULL, CREG_DEFAULT) == CREG_OK; } -/* replace csview input with replace using regular expression pattern */ -#define cregex_replace_sv(...) c_MACRO_OVERLOAD(cregex_replace_sv, __VA_ARGS__) -#define cregex_replace_sv_3(pattern, input, replace) \ - cregex_replace_sv_4(pattern, input, replace, INT32_MAX) -#define cregex_replace_sv_4(pattern, input, replace, count) \ - cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT) -cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, - bool (*transform)(int group, csview match, cstr* result), int rflags); +/* replace csubstr input with replace using regular expression pattern */ +#define cregex_replace_ss(...) c_MACRO_OVERLOAD(cregex_replace_ss, __VA_ARGS__) +#define cregex_replace_ss_3(pattern, input, replace) \ + cregex_replace_ss_4(pattern, input, replace, INT32_MAX) +#define cregex_replace_ss_4(pattern, input, replace, count) \ + cregex_replace_ss_6(pattern, input, replace, count, NULL, CREG_DEFAULT) +cstr cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, + bool (*transform)(int group, csubstr match, cstr* result), int rflags); /* replace input with replace using regular expression */ #define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__) #define cregex_replace_3(re, input, replace) cregex_replace_4(re, input, replace, INT32_MAX) STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char* replace, int count) { - csview sv = {input, c_strlen(input)}; - return cregex_replace_sv_4(re, sv, replace, count); + csubstr ss = {input, c_strlen(input)}; + return cregex_replace_ss_4(re, ss, replace, count); } /* replace + compile RE pattern, and extra arguments */ @@ -159,7 +159,7 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char #define cregex_replace_pattern_4(pattern, input, replace, count) \ cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*transform)(int group, csview match, cstr* result), int crflags); + bool (*transform)(int group, csubstr match, cstr* result), int crflags); /* destroy regex */ void cregex_drop(cregex* re); diff --git a/include/stc/cstr.h b/include/stc/cstr.h index f12d29b6..47cf65da 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -75,7 +75,7 @@ STC_API char* cstr_reserve(cstr* self, intptr_t cap); STC_API void cstr_shrink_to_fit(cstr* self); STC_API char* cstr_resize(cstr* self, intptr_t size, char value); STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); -STC_API intptr_t cstr_find_sv(const cstr* self, csview search); +STC_API intptr_t cstr_find_ss(const cstr* self, csubstr search); STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_uninit(cstr *self, intptr_t len); @@ -85,7 +85,7 @@ STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); STC_API cstr cstr_from_fmt(const char* fmt, ...); STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...); -STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); +STC_API cstr cstr_replace_ss(csubstr sv, csubstr search, csubstr repl, int32_t count); STC_API uint64_t cstr_hash(const cstr *self); STC_INLINE cstr_buf cstr_buffer(cstr* s) { @@ -94,9 +94,11 @@ STC_INLINE cstr_buf cstr_buffer(cstr* s) { : c_LITERAL(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap}; } STC_INLINE csview cstr_sv(const cstr* s) { - return cstr_is_long(s) ? c_LITERAL(csview){s->lon.data, cstr_l_size(s)} - : c_LITERAL(csview){s->sml.data, cstr_s_size(s)}; + return cstr_is_long(s) ? c_sv_2(s->lon.data, cstr_l_size(s)) + : c_sv_2(s->sml.data, cstr_s_size(s)); } +STC_INLINE csubstr cstr_ss(const cstr* s) + { csview sv = cstr_sv(s); return c_ss_2(sv.str, sv.size); } STC_INLINE cstr cstr_init(void) { return cstr_null; } @@ -110,7 +112,10 @@ STC_INLINE cstr cstr_from_n(const char* str, const intptr_t len) { STC_INLINE cstr cstr_from(const char* str) { return cstr_from_n(str, c_strlen(str)); } -STC_INLINE cstr cstr_from_sv(csview sv) +STC_INLINE cstr cstr_from_ss(csubstr sv) + { return cstr_from_n(sv.str, sv.size); } + +STC_INLINE cstr cstr_from_v(csview sv) { return cstr_from_n(sv.str, sv.size); } STC_INLINE cstr cstr_with_size(const intptr_t size, const char value) { @@ -170,9 +175,9 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self) // utf8 methods defined in/depending on src/utf8code.c: -extern cstr cstr_casefold_sv(csview sv); -extern cstr cstr_tolower_sv(csview sv); -extern cstr cstr_toupper_sv(csview sv); +extern cstr cstr_casefold_ss(csubstr sv); +extern cstr cstr_tolower_ss(csubstr sv); +extern cstr cstr_toupper_ss(csubstr sv); extern cstr cstr_tolower(const char* str); extern cstr cstr_toupper(const char* str); extern void cstr_lowercase(cstr* self); @@ -193,9 +198,9 @@ STC_INLINE intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx) STC_INLINE const char* cstr_u8_at(const cstr* self, intptr_t u8idx) { return utf8_at(cstr_str(self), u8idx); } -STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { +STC_INLINE csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx) { const char* str = cstr_str(self); - csview sv; + csubstr sv; sv.str = utf8_at(str, u8idx); sv.size = utf8_chr_size(sv.str); return sv; @@ -205,7 +210,7 @@ STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { STC_INLINE cstr_iter cstr_begin(const cstr* self) { csview sv = cstr_sv(self); - if (!sv.size) return c_LITERAL(cstr_iter){NULL}; + if (!sv.size) return c_LITERAL(cstr_iter){.ref = NULL}; return c_LITERAL(cstr_iter){.u8 = {{sv.str, utf8_chr_size(sv.str)}}}; } STC_INLINE cstr_iter cstr_end(const cstr* self) { @@ -244,6 +249,9 @@ STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { STC_INLINE bool cstr_equals(const cstr* self, const char* str) { return !strcmp(cstr_str(self), str); } +STC_INLINE bool cstr_equals_ss(const cstr* self, csubstr sv) + { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } + STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv) { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } @@ -266,14 +274,14 @@ STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search) STC_INLINE bool cstr_contains(const cstr* self, const char* search) { return strstr((char*)cstr_str(self), search) != NULL; } -STC_INLINE bool cstr_contains_sv(const cstr* self, csview search) - { return cstr_find_sv(self, search) != c_NPOS; } +STC_INLINE bool cstr_contains_ss(const cstr* self, csubstr search) + { return cstr_find_ss(self, search) != c_NPOS; } STC_INLINE bool cstr_contains_s(const cstr* self, cstr search) { return strstr((char*)cstr_str(self), cstr_str(&search)) != NULL; } -STC_INLINE bool cstr_starts_with_sv(const cstr* self, csview sub) { +STC_INLINE bool cstr_starts_with_ss(const cstr* self, csubstr sub) { if (sub.size > cstr_size(self)) return false; return !c_memcmp(cstr_str(self), sub.str, sub.size); } @@ -285,26 +293,26 @@ STC_INLINE bool cstr_starts_with(const cstr* self, const char* sub) { } STC_INLINE bool cstr_starts_with_s(const cstr* self, cstr sub) - { return cstr_starts_with_sv(self, cstr_sv(&sub)); } + { return cstr_starts_with_ss(self, cstr_ss(&sub)); } STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) { - csview sv = cstr_sv(self); + csubstr sv = cstr_ss(self); intptr_t len = c_strlen(sub); - return len <= sv.size && !utf8_icmp_sv(sv, c_sv(sub, len)); + return len <= sv.size && !utf8_icmp_ss(sv, c_ss(sub, len)); } -STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) { +STC_INLINE bool cstr_ends_with_ss(const cstr* self, csubstr sub) { csview sv = cstr_sv(self); if (sub.size > sv.size) return false; return !c_memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); } STC_INLINE bool cstr_ends_with_s(const cstr* self, cstr sub) - { return cstr_ends_with_sv(self, cstr_sv(&sub)); } + { return cstr_ends_with_ss(self, cstr_ss(&sub)); } STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub) - { return cstr_ends_with_sv(self, c_sv(sub, c_strlen(sub))); } + { return cstr_ends_with_ss(self, c_ss(sub, c_strlen(sub))); } STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { csview sv = cstr_sv(self); @@ -316,7 +324,7 @@ STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { STC_INLINE char* cstr_assign(cstr* self, const char* str) { return cstr_assign_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_assign_sv(cstr* self, csview sv) +STC_INLINE char* cstr_assign_ss(cstr* self, csubstr sv) { return cstr_assign_n(self, sv.str, sv.size); } STC_INLINE char* cstr_copy(cstr* self, cstr s) { @@ -338,44 +346,42 @@ STC_INLINE void cstr_pop(cstr* self) { STC_INLINE char* cstr_append(cstr* self, const char* str) { return cstr_append_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_append_sv(cstr* self, csview sv) +STC_INLINE char* cstr_append_ss(cstr* self, csubstr sv) { return cstr_append_n(self, sv.str, sv.size); } STC_INLINE char* cstr_append_s(cstr* self, cstr s) - { return cstr_append_sv(self, cstr_sv(&s)); } + { return cstr_append_ss(self, cstr_ss(&s)); } #define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__) #define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, INT32_MAX) STC_INLINE void cstr_replace_4(cstr* self, const char* search, const char* repl, int32_t count) { - cstr_take(self, cstr_replace_sv(cstr_sv(self), c_sv(search, c_strlen(search)), - c_sv(repl, c_strlen(repl)), count)); + cstr_take(self, cstr_replace_ss(cstr_ss(self), c_ss(search, c_strlen(search)), + c_ss(repl, c_strlen(repl)), count)); } -STC_INLINE void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl) { +STC_INLINE void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl) { char* d = _cstr_internal_move(self, pos + len, pos + repl.size); c_memcpy(d + pos, repl.str, repl.size); } STC_INLINE void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl) - { cstr_replace_at_sv(self, pos, len, c_sv(repl, c_strlen(repl))); } + { cstr_replace_at_ss(self, pos, len, c_ss(repl, c_strlen(repl))); } STC_INLINE void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl) - { cstr_replace_at_sv(self, pos, len, cstr_sv(&repl)); } + { cstr_replace_at_ss(self, pos, len, cstr_ss(&repl)); } -STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl) - { cstr_replace_at_sv(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } +STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl) + { cstr_replace_at_ss(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } STC_INLINE void cstr_insert(cstr* self, intptr_t pos, const char* str) - { cstr_replace_at_sv(self, pos, 0, c_sv(str, c_strlen(str))); } + { cstr_replace_at_ss(self, pos, 0, c_ss(str, c_strlen(str))); } -STC_INLINE void cstr_insert_sv(cstr* self, intptr_t pos, csview sv) - { cstr_replace_at_sv(self, pos, 0, sv); } +STC_INLINE void cstr_insert_ss(cstr* self, intptr_t pos, csubstr sv) + { cstr_replace_at_ss(self, pos, 0, sv); } -STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) { - csview sv = cstr_sv(&s); - cstr_replace_at_sv(self, pos, 0, sv); -} +STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) + { cstr_replace_at_ss(self, pos, 0, cstr_ss(&s)); } STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } @@ -394,7 +400,7 @@ fn_tocase[] = {{tolower, utf8_casefold}, {tolower, utf8_tolower}, {toupper, utf8_toupper}}; -static cstr cstr_tocase(csview sv, int k) { +static cstr cstr_tocase(csubstr sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); const char *end = sv.str + sv.size; @@ -415,26 +421,26 @@ static cstr cstr_tocase(csview sv, int k) { return out; } -cstr cstr_casefold_sv(csview sv) +cstr cstr_casefold_ss(csubstr sv) { return cstr_tocase(sv, 0); } -cstr cstr_tolower_sv(csview sv) +cstr cstr_tolower_ss(csubstr sv) { return cstr_tocase(sv, 1); } -cstr cstr_toupper_sv(csview sv) +cstr cstr_toupper_ss(csubstr sv) { return cstr_tocase(sv, 2); } cstr cstr_tolower(const char* str) - { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } + { return cstr_tolower_ss(c_ss(str, c_strlen(str))); } cstr cstr_toupper(const char* str) - { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } + { return cstr_toupper_ss(c_ss(str, c_strlen(str))); } void cstr_lowercase(cstr* self) - { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } + { cstr_take(self, cstr_tolower_ss(cstr_ss(self))); } void cstr_uppercase(cstr* self) - { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } + { cstr_take(self, cstr_toupper_ss(cstr_ss(self))); } bool cstr_valid_utf8(const cstr* self) { return utf8_valid(cstr_str(self)); } @@ -450,7 +456,7 @@ STC_DEF uint64_t cstr_hash(const cstr *self) { return cfasthash(sv.str, sv.size); } -STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { +STC_DEF intptr_t cstr_find_ss(const cstr* self, csubstr search) { csview sv = cstr_sv(self); char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); return res ? (res - sv.str) : c_NPOS; @@ -580,7 +586,7 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } } -STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { +STC_DEF cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, int32_t count) { cstr out = cstr_null; intptr_t from = 0; char* res; if (!count) count = INT32_MAX; diff --git a/include/stc/csubstr.h b/include/stc/csubstr.h new file mode 100644 index 00000000..152f7041 --- /dev/null +++ b/include/stc/csubstr.h @@ -0,0 +1,208 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#define i_header // external linkage by default. override with i_static. +#define _i_inc_utf8 +#include "utf8.h" + +#ifndef CSUBSTR_H_INCLUDED +#define CSUBSTR_H_INCLUDED + +#define csubstr_init() c_ss_1("") +#define csubstr_drop(p) c_default_drop(p) +#define csubstr_clone(ss) c_default_clone(ss) +#define csubstr_from_n(str, n) c_ss_2(str, n) + +STC_API csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos); +STC_API intptr_t csubstr_find_ss(csubstr ss, csubstr search); +STC_API uint64_t csubstr_hash(const csubstr *self); +STC_API csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2); +STC_API csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n); +STC_API csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start); + +STC_INLINE csubstr csubstr_from(const char* str) + { return c_LITERAL(csubstr){str, c_strlen(str)}; } +STC_INLINE void csubstr_clear(csubstr* self) { *self = csubstr_init(); } +STC_INLINE intptr_t csubstr_size(csubstr ss) { return ss.size; } +STC_INLINE bool csubstr_empty(csubstr ss) { return ss.size == 0; } + +STC_INLINE bool csubstr_equals(csubstr ss, const char* str) + { intptr_t n = c_strlen(str); return ss.size == n && !c_memcmp(ss.str, str, n); } + +STC_INLINE intptr_t csubstr_find(csubstr ss, const char* str) + { return csubstr_find_ss(ss, c_ss_2(str, c_strlen(str))); } + +STC_INLINE bool csubstr_contains(csubstr ss, const char* str) + { return csubstr_find(ss, str) != c_NPOS; } + +STC_INLINE bool csubstr_starts_with(csubstr ss, const char* str) { + intptr_t n = c_strlen(str); + return n > ss.size ? false : !c_memcmp(ss.str, str, n); +} + +STC_INLINE bool csubstr_ends_with(csubstr ss, const char* str) { + intptr_t n = c_strlen(str); + return n > ss.size ? false : !c_memcmp(ss.str + ss.size - n, str, n); +} + +STC_INLINE csubstr csubstr_substr(csubstr ss, intptr_t pos, intptr_t n) { + if (pos + n > ss.size) n = ss.size - pos; + ss.str += pos, ss.size = n; + return ss; +} + +STC_INLINE csubstr csubstr_slice(csubstr ss, intptr_t p1, intptr_t p2) { + if (p2 > ss.size) p2 = ss.size; + ss.str += p1, ss.size = p2 > p1 ? p2 - p1 : 0; + return ss; +} + +/* utf8 iterator */ +STC_INLINE csubstr_iter csubstr_begin(const csubstr* self) { + if (!self->size) return c_LITERAL(csubstr_iter){NULL}; + return c_LITERAL(csubstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, + self->str + self->size}}; +} +STC_INLINE csubstr_iter csubstr_end(const csubstr* self) { + return c_LITERAL(csubstr_iter){.u8 = {{NULL}, self->str + self->size}}; +} +STC_INLINE void csubstr_next(csubstr_iter* it) { + it->ref += it->u8.chr.size; + it->u8.chr.size = utf8_chr_size(it->ref); + if (it->ref == it->u8.end) it->ref = NULL; +} + +/* utf8 */ +STC_INLINE intptr_t csubstr_u8_size(csubstr ss) + { return utf8_size_n(ss.str, ss.size); } + +STC_INLINE csubstr csubstr_u8_substr(csubstr ss, intptr_t bytepos, intptr_t u8len) { + ss.str += bytepos; + ss.size = utf8_pos(ss.str, u8len); + return ss; +} + +STC_INLINE bool csubstr_valid_utf8(csubstr ss) // depends on src/utf8code.c + { return utf8_valid_n(ss.str, ss.size); } + +#define c_fortoken_ss(it, inputss, sep) \ + for (struct { csubstr _inp, token, *ref; const char *_sep; intptr_t pos; } \ + it = {._inp=inputss, .token=it._inp, .ref=&it.token, ._sep=sep} \ + ; it.pos <= it._inp.size && (it.token = csubstr_token(it._inp, it._sep, &it.pos)).str ; ) + +#define c_fortoken(it, input, sep) \ + c_fortoken_ss(it, csubstr_from(input), sep) + +/* ---- Container helper functions ---- */ + +STC_INLINE int csubstr_cmp(const csubstr* x, const csubstr* y) { + intptr_t n = x->size < y->size ? x->size : y->size; + int c = c_memcmp(x->str, y->str, n); + return c ? c : (int)(x->size - y->size); +} + +STC_INLINE int csubstr_icmp(const csubstr* x, const csubstr* y) + { return utf8_icmp_ss(*x, *y); } + +STC_INLINE bool csubstr_eq(const csubstr* x, const csubstr* y) + { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } + +#endif // CSUBSTR_H_INCLUDED + +/* csubstr interaction with cstr: */ +#ifdef CSTR_H_INCLUDED + +STC_INLINE csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n) + { return csubstr_substr(cstr_ss(self), pos, n); } + +STC_INLINE csubstr cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) + { return csubstr_slice(cstr_ss(self), p1, p2); } + +STC_INLINE csubstr cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n) + { return csubstr_substr_ex(cstr_ss(self), pos, n); } + +STC_INLINE csubstr cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) + { return csubstr_slice_ex(cstr_ss(self), p1, p2); } + +STC_INLINE csubstr cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) + { return csubstr_u8_substr(cstr_ss(self), bytepos, u8len); } +#endif + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined i_implement || defined i_static +#ifndef CSUBSTR_C_INCLUDED +#define CSUBSTR_C_INCLUDED + +STC_DEF csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (it.ref == it.u8.end) it.ref = NULL; + return it; +} + +STC_DEF intptr_t csubstr_find_ss(csubstr ss, csubstr search) { + char* res = cstrnstrn(ss.str, search.str, ss.size, search.size); + return res ? (res - ss.str) : c_NPOS; +} + +STC_DEF uint64_t csubstr_hash(const csubstr *self) + { return cfasthash(self->str, self->size); } + +STC_DEF csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n) { + if (pos < 0) { + pos += ss.size; + if (pos < 0) pos = 0; + } + if (pos > ss.size) pos = ss.size; + if (pos + n > ss.size) n = ss.size - pos; + ss.str += pos, ss.size = n; + return ss; +} + +STC_DEF csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2) { + if (p1 < 0) { + p1 += ss.size; + if (p1 < 0) p1 = 0; + } + if (p2 < 0) p2 += ss.size; + if (p2 > ss.size) p2 = ss.size; + ss.str += p1, ss.size = (p2 > p1 ? p2 - p1 : 0); + return ss; +} + +STC_DEF csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start) { + intptr_t sep_size = c_strlen(sep); + csubstr slice = {ss.str + *start, ss.size - *start}; + const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); + csubstr tok = {slice.str, res ? (res - slice.str) : slice.size}; + *start += tok.size + sep_size; + return tok; +} +#endif // CSUBSTR_C_INCLUDED +#endif // i_implement +#undef i_static +#undef i_header +#undef i_implement +#undef i_import +#undef i_opt diff --git a/include/stc/csview.h b/include/stc/csview.h index bbf7cd8e..0d1ca36c 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,7 +20,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#define i_header // external linkage by default. override with i_static. #define _i_inc_utf8 #include "utf8.h" @@ -32,25 +31,26 @@ #define csview_clone(sv) c_default_clone(sv) #define csview_from_n(str, n) c_sv_2(str, n) -STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); -STC_API intptr_t csview_find_sv(csview sv, csview search); -STC_API uint64_t csview_hash(const csview *self); -STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); -STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); -STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); - STC_INLINE csview csview_from(const char* str) - { return c_LITERAL(csview){str, c_strlen(str)}; } + { return csview_from_n(str, c_strlen(str)); } STC_INLINE void csview_clear(csview* self) { *self = csview_init(); } +STC_INLINE csubstr csview_ss(csview sv) { return c_ss_2(sv.str, sv.size); } -STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } +STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } -STC_INLINE bool csview_equals(csview sv, const char* str) - { intptr_t n = c_strlen(str); return sv.size == n && !c_memcmp(sv.str, str, n); } +STC_INLINE bool csview_equals(csview sv, const char* str) { + intptr_t n = c_strlen(str); + return sv.size == n && !c_memcmp(sv.str, str, n); +} + +STC_INLINE intptr_t csview_find_v(csview sv, csview search) { + char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); + return res ? (res - sv.str) : c_NPOS; +} STC_INLINE intptr_t csview_find(csview sv, const char* str) - { return csview_find_sv(sv, c_sv_2(str, c_strlen(str))); } + { return csview_find_v(sv, c_sv_2(str, c_strlen(str))); } STC_INLINE bool csview_contains(csview sv, const char* str) { return csview_find(sv, str) != c_NPOS; } @@ -65,55 +65,40 @@ STC_INLINE bool csview_ends_with(csview sv, const char* str) { return n > sv.size ? false : !c_memcmp(sv.str + sv.size - n, str, n); } -STC_INLINE csview csview_substr(csview sv, intptr_t pos, intptr_t n) { - if (pos + n > sv.size) n = sv.size - pos; - sv.str += pos, sv.size = n; - return sv; -} - -STC_INLINE csview csview_slice(csview sv, intptr_t p1, intptr_t p2) { - if (p2 > sv.size) p2 = sv.size; - sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; - return sv; -} - /* utf8 iterator */ STC_INLINE csview_iter csview_begin(const csview* self) { - if (!self->size) return c_LITERAL(csview_iter){NULL}; - return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, - self->str + self->size}}; + if (!self->size) return c_LITERAL(csview_iter){.ref = NULL}; + return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}}; } STC_INLINE csview_iter csview_end(const csview* self) { - return c_LITERAL(csview_iter){.u8 = {{NULL}, self->str + self->size}}; + (void)self; return c_LITERAL(csview_iter){.ref = NULL}; } STC_INLINE void csview_next(csview_iter* it) { it->ref += it->u8.chr.size; it->u8.chr.size = utf8_chr_size(it->ref); - if (it->ref == it->u8.end) it->ref = NULL; + if (!*it->ref) it->ref = NULL; +} +STC_INLINE csview_iter csview_advance(csview_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (!*it.ref) it.ref = NULL; + return it; } -/* utf8 */ +/* utf8 size */ STC_INLINE intptr_t csview_u8_size(csview sv) { return utf8_size_n(sv.str, sv.size); } -STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) { - sv.str += bytepos; - sv.size = utf8_pos(sv.str, u8len); - return sv; -} - -STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c +/* utf8 validation: depends on src/utf8code.c */ +STC_INLINE bool csview_valid_utf8(csview sv) { return utf8_valid_n(sv.str, sv.size); } -#define c_fortoken_sv(it, inputsv, sep) \ - for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \ - it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \ - ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).str ; ) - -#define c_fortoken(it, input, sep) \ - c_fortoken_sv(it, csview_from(input), sep) +/* utf8 ignore case cmp: depends on src/utf8code.c */ +STC_INLINE int csview_icmp(const csview* x, const csview* y) + { return utf8_icmp_ss(c_ss_2(x->str, x->size), c_ss_2(y->str, y->size)); } -/* ---- Container helper functions ---- */ STC_INLINE int csview_cmp(const csview* x, const csview* y) { intptr_t n = x->size < y->size ? x->size : y->size; @@ -121,87 +106,13 @@ STC_INLINE int csview_cmp(const csview* x, const csview* y) { return c ? c : (int)(x->size - y->size); } -STC_INLINE int csview_icmp(const csview* x, const csview* y) - { return utf8_icmp_sv(*x, *y); } - STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } -#endif // CSVIEW_H_INCLUDED - -/* csview interaction with cstr: */ -#ifdef CSTR_H_INCLUDED - -STC_INLINE csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n) - { return csview_substr(cstr_sv(self), pos, n); } - -STC_INLINE csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) - { return csview_slice(cstr_sv(self), p1, p2); } - -STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n) - { return csview_substr_ex(cstr_sv(self), pos, n); } - -STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) - { return csview_slice_ex(cstr_sv(self), p1, p2); } - -STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) - { return csview_u8_substr(cstr_sv(self), bytepos, u8len); } -#endif - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement || defined i_static -#ifndef CSVIEW_C_INCLUDED -#define CSVIEW_C_INCLUDED - -STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (it.ref == it.u8.end) it.ref = NULL; - return it; -} - -STC_DEF intptr_t csview_find_sv(csview sv, csview search) { - char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); - return res ? (res - sv.str) : c_NPOS; -} - -STC_DEF uint64_t csview_hash(const csview *self) +STC_INLINE uint64_t csview_hash(const csview *self) { return cfasthash(self->str, self->size); } -STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { - if (pos < 0) { - pos += sv.size; - if (pos < 0) pos = 0; - } - if (pos > sv.size) pos = sv.size; - if (pos + n > sv.size) n = sv.size - pos; - sv.str += pos, sv.size = n; - return sv; -} - -STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { - if (p1 < 0) { - p1 += sv.size; - if (p1 < 0) p1 = 0; - } - if (p2 < 0) p2 += sv.size; - if (p2 > sv.size) p2 = sv.size; - sv.str += p1, sv.size = (p2 > p1 ? p2 - p1 : 0); - return sv; -} - -STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { - intptr_t sep_size = c_strlen(sep); - csview slice = {sv.str + *start, sv.size - *start}; - const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); - csview tok = {slice.str, res ? (res - slice.str) : slice.size}; - *start += tok.size + sep_size; - return tok; -} -#endif // CSVIEW_C_INCLUDED -#endif // i_implement +#endif // CSVIEW_H_INCLUDED #undef i_static #undef i_header #undef i_implement diff --git a/include/stc/forward.h b/include/stc/forward.h index 572a319f..5c9c4f4d 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -39,8 +39,21 @@ #define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL) #define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL) -// csview -typedef const char csview_value; +// csubstr : non-null terminated string view +typedef const char csubstr_value; +typedef struct csubstr { + csubstr_value* str; + intptr_t size; +} csubstr; + +typedef union { + csubstr_value* ref; + struct { csubstr chr; csubstr_value* end; } u8; +} csubstr_iter; + + +// csview : null-terminated string view +typedef csubstr_value csview_value; typedef struct csview { csview_value* str; intptr_t size; @@ -48,10 +61,11 @@ typedef struct csview { typedef union { csview_value* ref; - struct { csview chr; csview_value* end; } u8; + struct { csubstr chr; } u8; } csview_iter; -// cstr + +// cstr : null-terminated string (short string optimized - sso) typedef char cstr_value; typedef struct { cstr_value* data; intptr_t size, cap; } cstr_buf; typedef union cstr { @@ -61,9 +75,10 @@ typedef union cstr { typedef union { cstr_value* ref; - struct { csview chr; } u8; + struct { csubstr chr; } u8; } cstr_iter; + #define c_true(...) __VA_ARGS__ #define c_false(...) diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 65dee203..47225ec8 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -114,10 +114,10 @@ #endif #elif defined i_key_ssv #define i_keyclass cstr - #define i_rawclass csview - #define i_keyfrom cstr_from_sv - #define i_keyto cstr_sv - #define i_eq csview_eq + #define i_rawclass csubstr + #define i_keyfrom cstr_from_ss + #define i_keyto cstr_ss + #define i_eq csubstr_eq #ifndef i_tag #define i_tag ssv #endif @@ -232,9 +232,9 @@ #define i_valraw const char* #elif defined i_val_ssv #define i_valclass cstr - #define i_valraw csview - #define i_valfrom cstr_from_sv - #define i_valto cstr_sv + #define i_valraw csubstr + #define i_valfrom cstr_from_ss + #define i_valto cstr_ss #elif defined i_valboxed #define i_valclass i_valboxed #define i_valraw c_PASTE(i_valboxed, _raw) diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 6d12856f..7d2adee0 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -48,7 +48,7 @@ extern uint32_t utf8_toupper(uint32_t c); extern bool utf8_iscased(uint32_t c); extern bool utf8_isword(uint32_t c); extern bool utf8_valid_n(const char* s, intptr_t nbytes); -extern int utf8_icmp_sv(csview s1, csview s2); +extern int utf8_icmp_ss(csubstr s1, csubstr s2); extern int utf8_encode(char *out, uint32_t c); extern uint32_t utf8_peek_off(const char *s, int offset); @@ -92,7 +92,7 @@ STC_INLINE uint32_t utf8_peek(const char* s) { /* case-insensitive utf8 string comparison */ STC_INLINE int utf8_icmp(const char* s1, const char* s2) { - return utf8_icmp_sv(c_sv(s1, INTPTR_MAX), c_sv(s2, INTPTR_MAX)); + return utf8_icmp_ss(c_ss(s1, INTPTR_MAX), c_ss(s2, INTPTR_MAX)); } STC_INLINE bool utf8_valid(const char* s) { diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp index a5dfd901..9173d4b6 100644 --- a/misc/benchmarks/various/string_bench_STC.cpp +++ b/misc/benchmarks/various/string_bench_STC.cpp @@ -7,16 +7,16 @@ #define i_implement #include // string #define i_implement -#include // string_view +#include // string_view #include #define i_key_str #include // vec of cstr with const char* lookup -#define i_type cvec_sv // override default type name (cvec_csview) -#define i_key csview -#define i_cmp csview_cmp -#include // cvec_vs: vec of csview +#define i_type cvec_ss // override default type name (cvec_csubstr) +#define i_key csubstr +#define i_cmp csubstr_cmp +#include // cvec_vs: vec of csubstr #define i_key_str #define i_val size_t @@ -24,7 +24,7 @@ #define i_key_ssv #define i_val size_t -#include // sorted map of cstr, csview lookup +#include // sorted map of cstr, csubstr lookup #define i_key_str #define i_val size_t @@ -32,7 +32,7 @@ #define i_key_ssv #define i_val size_t -#include // unordered map of cstr, csview lookup +#include // unordered map of cstr, csubstr lookup cvec_str read_file(const char* name) @@ -67,7 +67,7 @@ private: std::chrono::high_resolution_clock::time_point begin; }; -void initShortStringVec(cvec_str* vs, cvec_sv* vsv) +void initShortStringVec(cvec_str* vs, cvec_ss* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -101,14 +101,14 @@ void initShortStringVec(cvec_str* vs, cvec_sv* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_sv(i.ref)); + cvec_sv_push_back(vsv, cstr_ss(i.ref)); num += cstr_size(i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; std::cout << "avg str len: " << num / (float)cvec_sv_size(vsv) << std::endl; } -void initLongStringVec(cvec_str* vs, cvec_sv* vsv) +void initLongStringVec(cvec_str* vs, cvec_ss* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -147,7 +147,7 @@ void initLongStringVec(cvec_str* vs, cvec_sv* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_sv(i.ref)); + cvec_sv_push_back(vsv, cstr_ss(i.ref)); num += cstr_size(i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; @@ -175,7 +175,7 @@ void initMaps(const cvec_str* vs, csmap_str* mapTrans, csmap_ssv* mapSview, void benchmark( const cvec_str* vec_string, - const cvec_sv* vec_stringview, + const cvec_ss* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -187,7 +187,7 @@ const size_t MAX_LOOP = 2000; int main(void) { c_auto (cvec_str, vec_string) - c_auto (cvec_sv, vec_stringview) + c_auto (cvec_ss, vec_stringview) c_auto (csmap_str, mapTrans) c_auto (csmap_ssv, mapSview) c_auto (cmap_str, unordmapTrans) @@ -229,7 +229,7 @@ int main(void) void benchmark( const cvec_str* vec_string, - const cvec_sv* vec_stringview, + const cvec_ss* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -258,7 +258,7 @@ void benchmark( stopwatch.start("Trans Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_sv, *vec_stringview) + c_foreach (j, cvec_ss, *vec_stringview) { const csmap_ssv_value* v = csmap_ssv_get(mapSview, *j.ref); if (v) @@ -286,7 +286,7 @@ void benchmark( stopwatch.start("Trans Unord Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_sv, *vec_stringview) + c_foreach (j, cvec_ss, *vec_stringview) { const cmap_ssv_value* v = cmap_ssv_get(unordmapSview, *j.ref); if (v) diff --git a/misc/examples/algorithms/forfilter.c b/misc/examples/algorithms/forfilter.c index c1426045..d058660d 100644 --- a/misc/examples/algorithms/forfilter.c +++ b/misc/examples/algorithms/forfilter.c @@ -2,7 +2,7 @@ #define i_import #include #define i_implement -#include +#include #include #define i_type IVec @@ -82,7 +82,7 @@ fn main() { } */ #define i_type SVec -#define i_keyclass csview +#define i_keyclass csubstr #include void demo3(void) @@ -94,11 +94,11 @@ void demo3(void) SVec words_containing_i = {0}; c_forfilter (w, SVec, words, - csview_contains(*w.ref, "i")) + csubstr_contains(*w.ref, "i")) SVec_push(&words_containing_i, *w.ref); c_foreach (w, SVec, words_containing_i) - printf(" %.*s", c_SV(*w.ref)); + printf(" %.*s", c_SS(*w.ref)); puts(""); c_drop(SVec, &words, &words_containing_i); @@ -107,10 +107,10 @@ void demo3(void) void demo4(void) { // Keep only uppercase letters and convert them to lowercase: - csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte + csubstr s = c_ss("ab123cReAghNGnΩoEp"); // Ω = multi-byte cstr out = {0}; - c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) { + c_forfilter (i, csubstr, s, utf8_isupper(utf8_peek(i.ref))) { char chr[4]; utf8_encode(chr, utf8_tolower(utf8_peek(i.ref))); cstr_push(&out, chr); diff --git a/misc/examples/regularexpressions/regex2.c b/misc/examples/regularexpressions/regex2.c index a798b1a1..85890070 100644 --- a/misc/examples/regularexpressions/regex2.c +++ b/misc/examples/regularexpressions/regex2.c @@ -27,7 +27,7 @@ int main(void) c_formatch (j, &re, s[i].input) { c_forrange (k, cregex_captures(&re) + 1) - printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); + printf(" submatch %lld: %.*s\n", k, c_SS(j.match[k])); } } cregex_drop(&re); diff --git a/misc/examples/regularexpressions/regex_match.c b/misc/examples/regularexpressions/regex_match.c index 11426d2d..6eaea781 100644 --- a/misc/examples/regularexpressions/regex_match.c +++ b/misc/examples/regularexpressions/regex_match.c @@ -1,7 +1,7 @@ #define i_import #include #define i_implement -#include +#include #define i_key float #include @@ -28,7 +28,7 @@ int main(void) printf(" %g\n", (double)*i.ref); // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); + cstr nums = cregex_replace_ss(&re, csubstr_from(str), " $0,", 0, NULL, CREG_STRIP); printf("\n%s\n", cstr_str(&nums)); cstr_drop(&nums); diff --git a/misc/examples/regularexpressions/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c index f1ea2711..f5fd8691 100644 --- a/misc/examples/regularexpressions/regex_replace.c +++ b/misc/examples/regularexpressions/regex_replace.c @@ -1,8 +1,8 @@ #define i_import #include -#include +#include -bool add_10_years(int i, csview match, cstr* out) { +bool add_10_years(int i, csubstr match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -47,7 +47,7 @@ int main(void) printf("euros: %s\n", cstr_str(&str)); /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); printf("strip: %s\n", cstr_str(&str)); /* Wrap all words in ${} */ diff --git a/misc/examples/strings/cstr_match.c b/misc/examples/strings/cstr_match.c index be03e981..3c41bd43 100644 --- a/misc/examples/strings/cstr_match.c +++ b/misc/examples/strings/cstr_match.c @@ -1,11 +1,11 @@ #define i_implement #include -#include +#include #include int main(void) { - cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"); + cstr ss = cstr_from("The quick brown fox jumps over the lazy dog.JPG"); intptr_t pos = cstr_find_at(&ss, 0, "brown"); printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "" : cstr_str(&ss) + pos); @@ -16,11 +16,11 @@ int main(void) printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); cstr s1 = cstr_lit("hell😀 w😀rl🐨"); - csview ch1 = cstr_u8_chr(&s1, 7); - csview ch2 = cstr_u8_chr(&s1, 10); + csubstr ch1 = cstr_u8_chr(&s1, 7); + csubstr ch2 = cstr_u8_chr(&s1, 10); printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); - printf("ch1: %.*s\n", c_SV(ch1)); - printf("ch2: %.*s\n", c_SV(ch2)); + printf("ch1: %.*s\n", c_SS(ch1)); + printf("ch2: %.*s\n", c_SS(ch2)); c_drop(cstr, &ss, &s1); } diff --git a/misc/examples/strings/replace.c b/misc/examples/strings/replace.c index 59a56bf7..2411f1a7 100644 --- a/misc/examples/strings/replace.c +++ b/misc/examples/strings/replace.c @@ -20,13 +20,13 @@ int main(void) cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) printf("(1) %s\n", cstr_str(&s)); - cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) + cstr_replace_at_ss(&s, 19, 6, c_ss(s3+7, 6)); // "this is an example phrase." (2) printf("(2) %s\n", cstr_str(&s)); cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) printf("(3) %s\n", cstr_str(&s)); - cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) + cstr_replace_at_ss(&s, 8, 6, c_ss("a shorty", 7)); // "this is a short phrase." (4) printf("(4) %s\n", cstr_str(&s)); cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) diff --git a/misc/examples/strings/splitstr.c b/misc/examples/strings/splitstr.c index ef7ed174..6fa76d34 100644 --- a/misc/examples/strings/splitstr.c +++ b/misc/examples/strings/splitstr.c @@ -2,20 +2,20 @@ #define i_import // cstr + utf8 functions #include #define i_implement -#include +#include int main(void) { - puts("Split with c_fortoken (csview):"); + puts("Split with c_fortoken (csubstr):"); c_fortoken (i, "Hello World C99!", " ") - printf("'%.*s'\n", c_SV(i.token)); + printf("'%.*s'\n", c_SS(i.token)); puts("\nSplit with c_formatch (regex):"); cregex re = cregex_from("[^ ]+"); c_formatch (i, &re, " Hello World C99! ") - printf("'%.*s'\n", c_SV(i.match[0])); + printf("'%.*s'\n", c_SS(i.match[0])); cregex_drop(&re); } diff --git a/misc/examples/strings/sso_substr.c b/misc/examples/strings/sso_substr.c index 687658df..3c6b1046 100644 --- a/misc/examples/strings/sso_substr.c +++ b/misc/examples/strings/sso_substr.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { cstr str = cstr_lit("We think in generalities, but we live in details."); - csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" - intptr_t pos = cstr_find(&str, "live"); // position of "live" - csview sv2 = cstr_substr_ex(&str, pos, 4); // "live" - csview sv3 = cstr_slice_ex(&str, -8, -1); // "details" - printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); + csubstr sv1 = cstr_substr_ex(&str, 3, 5); // "think" + intptr_t pos = cstr_find(&str, "live"); // position of "live" + csubstr sv2 = cstr_substr_ex(&str, pos, 4); // "live" + csubstr sv3 = cstr_slice_ex(&str, -8, -1); // "details" + printf("%.*s, %.*s, %.*s\n", c_SS(sv1), c_SS(sv2), c_SS(sv3)); cstr_assign(&str, "apples are green or red"); - cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red" - cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples" + cstr s2 = cstr_from_ss(cstr_substr_ex(&str, -3, 3)); // "red" + cstr s3 = cstr_from_ss(cstr_substr_ex(&str, 0, 6)); // "apples" printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), cstr_is_long(&str), cstr_is_long(&s2)); c_drop (cstr, &str, &s2, &s3); diff --git a/misc/examples/strings/sview_split.c b/misc/examples/strings/sview_split.c index ac275da0..6abbf5e7 100644 --- a/misc/examples/strings/sview_split.c +++ b/misc/examples/strings/sview_split.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { // No memory allocations or string length calculations! - const csview date = c_sv("2021/03/12"); + const csubstr date = c_ss("2021/03/12"); intptr_t pos = 0; - const csview year = csview_token(date, "/", &pos); - const csview month = csview_token(date, "/", &pos); - const csview day = csview_token(date, "/", &pos); + const csubstr year = csubstr_token(date, "/", &pos); + const csubstr month = csubstr_token(date, "/", &pos); + const csubstr day = csubstr_token(date, "/", &pos); - printf("%.*s, %.*s, %.*s\n", c_SV(year), c_SV(month), c_SV(day)); + printf("%.*s, %.*s, %.*s\n", c_SS(year), c_SS(month), c_SS(day)); - cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); + cstr y = cstr_from_ss(year), m = cstr_from_ss(month), d = cstr_from_ss(day); printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); c_drop(cstr, &y, &m, &d); } diff --git a/misc/examples/strings/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c index 1d54486f..03a0442f 100644 --- a/misc/examples/strings/utf8replace_c.c +++ b/misc/examples/strings/utf8replace_c.c @@ -10,12 +10,12 @@ int main(void) cstr_u8_replace_at(&hello, cstr_u8_to_pos(&hello, 7), 1, - c_sv("🐨") + c_ss("🐨") ); printf("%s\n", cstr_str(&hello)); c_foreach (c, cstr, hello) - printf("%.*s,", c_SV(c.u8.chr)); + printf("%.*s,", c_SS(c.u8.chr)); cstr str = cstr_lit("scooby, dooby doo"); cstr_replace(&str, "oo", "00"); diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 4e192de6..7cd03930 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -1,6 +1,6 @@ #define i_import #include -#include +#include #include #include "ctest.h" @@ -14,7 +14,7 @@ CTEST(cregex, compile_match_char) cregex re = cregex_from("äsdf"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_FULLMATCH), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); // ä is two bytes wide @@ -32,7 +32,7 @@ CTEST(cregex, compile_match_anchors) cregex re = cregex_from(inp="^äs.f$"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -50,7 +50,7 @@ CTEST(cregex, compile_match_quantifiers1) re = cregex_from("ä+"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="ääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 4); @@ -70,7 +70,7 @@ CTEST(cregex, compile_match_quantifiers2) re = cregex_from("bä*"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, inp="bääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -90,7 +90,7 @@ CTEST(cregex, compile_match_escaped_chars) cregex re = cregex_from("\\n\\r\\t\\{"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, "\n\r\t{", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "\n\r\t", &match), CREG_NOMATCH); @@ -108,7 +108,7 @@ CTEST(cregex, compile_match_class_simple) re3 = cregex_from("\\D"); ASSERT_EQ(re3.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re1, " " , &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\r", &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\n", &match), CREG_OK); @@ -129,7 +129,7 @@ CTEST(cregex, compile_match_or) re = cregex_from("as|df"); ASSERT_EQ(re.error, 0); - csview match[4]; + csubstr match[4]; ASSERT_EQ(cregex_find(&re, "as", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "df", match), CREG_OK); @@ -146,7 +146,7 @@ CTEST(cregex, compile_match_class_complex_0) cregex re = cregex_from("[asdf]"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "s", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "d", &match), CREG_OK); @@ -160,7 +160,7 @@ CTEST(cregex, compile_match_class_complex_1) cregex re = cregex_from("[a-zä0-9öA-Z]"); ASSERT_EQ(re.error, 0); - csview match; + csubstr match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "5", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "A", &match), CREG_OK); @@ -175,7 +175,7 @@ CTEST(cregex, compile_match_cap) cregex re = cregex_from("(abc)d"); ASSERT_EQ(re.error, 0); - csview match[4]; + csubstr match[4]; ASSERT_EQ(cregex_find(&re, "abcd", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "llljabcdkk", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "abc", match), CREG_NOMATCH); @@ -189,7 +189,7 @@ CTEST(cregex, search_all) c_auto (cregex, re) { re = cregex_from("ab"); - csview m = {0}; + csubstr m = {0}; int res; ASSERT_EQ(re.error, CREG_OK); inp="ab,ab,ab"; @@ -220,9 +220,9 @@ CTEST(cregex, captures_cap) re = cregex_from("(ab)((cd)+)"); ASSERT_EQ(cregex_captures(&re), 3); - csview cap[5]; + csubstr cap[5]; ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap), CREG_OK); - ASSERT_TRUE(csview_equals(cap[0], "abcdcd")); + ASSERT_TRUE(csubstr_equals(cap[0], "abcdcd")); ASSERT_EQ(M_END(cap[0]), 8); ASSERT_EQ(M_START(cap[1]), 2); @@ -235,7 +235,7 @@ CTEST(cregex, captures_cap) } } -static bool add_10_years(int i, csview match, cstr* out) { +static bool add_10_years(int i, csubstr match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -280,7 +280,7 @@ CTEST(cregex, replace) ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022"); // Strip out everything but the matches - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;"); } } diff --git a/src/cregex.c b/src/cregex.c index 975a5104..c045b9f3 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -100,7 +100,7 @@ typedef struct _Reprog /* * Sub expression matches */ -typedef csview _Resub; +typedef csubstr _Resub; /* * substitution list @@ -1215,8 +1215,8 @@ _regexec(const _Reprog *progp, /* program to run */ static void -_build_subst(const char* replace, int nmatch, const csview match[], - bool (*mfun)(int, csview, cstr*), cstr* subst) { +_build_subst(const char* replace, int nmatch, const csubstr match[], + bool (*mfun)(int, csubstr, cstr*), cstr* subst) { cstr_buf buf = cstr_buffer(subst); intptr_t len = 0, cap = buf.cap; char* dst = buf.data; @@ -1233,7 +1233,7 @@ _build_subst(const char* replace, int nmatch, const csview match[], if (replace[1] >= '0' && replace[1] <= '9' && replace[2] == ';') { g = g*10 + (replace[1] - '0'); replace += 2; } if (g < nmatch) { - csview m = mfun && mfun(g, match[g], &mstr) ? cstr_sv(&mstr) : match[g]; + csubstr m = mfun && mfun(g, match[g], &mstr) ? cstr_ss(&mstr) : match[g]; if (len + m.size > cap) dst = cstr_reserve(subst, cap += cap/2 + m.size); for (int i = 0; i < m.size; ++i) @@ -1270,7 +1270,7 @@ cregex_captures(const cregex* self) { } int -cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { +cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags) { int res = _regexec(re->prog, input, cregex_captures(re) + 1, match, mflags); switch (res) { case 1: return CREG_OK; @@ -1281,7 +1281,7 @@ cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { int cregex_find_pattern_4(const char* pattern, const char* input, - csview match[], int cmflags) { + csubstr match[], int cmflags) { cregex re = cregex_init(); int res = cregex_compile(&re, pattern, cmflags); if (res != CREG_OK) return res; @@ -1291,16 +1291,16 @@ cregex_find_pattern_4(const char* pattern, const char* input, } cstr -cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, - bool (*mfun)(int, csview, cstr*), int rflags) { +cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, + bool (*mfun)(int, csubstr, cstr*), int rflags) { cstr out = cstr_init(); cstr subst = cstr_init(); - csview match[CREG_MAX_CAPTURES]; + csubstr match[CREG_MAX_CAPTURES]; int nmatch = cregex_captures(re) + 1; if (!count) count = INT32_MAX; bool copy = !(rflags & CREG_STRIP); - while (count-- && cregex_find_sv(re, input, match) == CREG_OK) { + while (count-- && cregex_find_ss(re, input, match) == CREG_OK) { _build_subst(replace, nmatch, match, mfun, &subst); const intptr_t mpos = (match[0].str - input.str); if (copy & (mpos > 0)) cstr_append_n(&out, input.str, mpos); @@ -1308,19 +1308,19 @@ cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int cou input.str = match[0].str + match[0].size; input.size -= mpos + match[0].size; } - if (copy) cstr_append_sv(&out, input); + if (copy) cstr_append_ss(&out, input); cstr_drop(&subst); return out; } cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*mfun)(int, csview, cstr*), int crflags) { + bool (*mfun)(int, csubstr, cstr*), int crflags) { cregex re = cregex_init(); if (cregex_compile(&re, pattern, crflags) != CREG_OK) assert(0); - csview sv = {input, c_strlen(input)}; - cstr out = cregex_replace_sv(&re, sv, replace, count, mfun, crflags); + csubstr ss = c_ss(input, c_strlen(input)); + cstr out = cregex_replace_ss(&re, ss, replace, count, mfun, crflags); cregex_drop(&re); return out; } diff --git a/src/libstc.c b/src/libstc.c index 462c97c4..b0d27350 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,7 +1,7 @@ #define i_import #include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement -#include "../include/stc/csview.h" +#include "../include/stc/csubstr.h" #define i_implement #include "../include/stc/crand.h" #if __STDC_VERSION__ >= 201112L diff --git a/src/singleupdate.sh b/src/singleupdate.sh index e706dd97..be99d4a7 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -17,12 +17,12 @@ python singleheader.py $d/include/stc/cqueue.h $d/../stcsingle/stc/cqueue.h python singleheader.py $d/include/stc/crand.h $d/../stcsingle/stc/crand.h python singleheader.py $d/include/stc/cregex.h $d/../stcsingle/stc/cregex.h python singleheader.py $d/include/stc/cset.h $d/../stcsingle/stc/cset.h - python singleheader.py $d/include/stc/csmap.h $d/../stcsingle/stc/csmap.h python singleheader.py $d/include/stc/cspan.h $d/../stcsingle/stc/cspan.h python singleheader.py $d/include/stc/csset.h $d/../stcsingle/stc/csset.h python singleheader.py $d/include/stc/cstack.h $d/../stcsingle/stc/cstack.h python singleheader.py $d/include/stc/cstr.h $d/../stcsingle/stc/cstr.h +python singleheader.py $d/include/stc/csubstr.h $d/../stcsingle/stc/csubstr.h python singleheader.py $d/include/stc/csview.h $d/../stcsingle/stc/csview.h python singleheader.py $d/include/stc/cvec.h $d/../stcsingle/stc/cvec.h python singleheader.py $d/include/stc/extend.h $d/../stcsingle/stc/extend.h diff --git a/src/utf8code.c b/src/utf8code.c index 4abf10ea..ddc4cb97 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -101,7 +101,7 @@ uint32_t utf8_toupper(uint32_t c) { return c; } -int utf8_icmp_sv(const csview s1, const csview s2) { +int utf8_icmp_ss(const csubstr s1, const csubstr s2) { utf8_decode_t d1 = {.state=0}, d2 = {.state=0}; intptr_t j1 = 0, j2 = 0; while ((j1 < s1.size) & (j2 < s2.size)) { -- cgit v1.2.3 From 2b6b4785c5c26bc47d800c1a7c7a48784df2d57b Mon Sep 17 00:00:00 2001 From: tylov Date: Mon, 14 Aug 2023 10:33:32 +0200 Subject: Some docs updates. --- README.md | 9 +++++---- docs/csubstr_api.md | 9 +++++---- docs/csview_api.md | 8 ++++---- 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 96479fa0..1c8c3878 100644 --- a/README.md +++ b/README.md @@ -18,18 +18,19 @@ Containers - [***cbox*** - **std::unique_ptr** alike type](docs/cbox_api.md) - [***cbits*** - **std::bitset** alike type](docs/cbits_api.md) - [***clist*** - **std::forward_list** alike type](docs/clist_api.md) +- [***cstack*** - **std::stack** alike type](docs/cstack_api.md) +- [***cvec*** - **std::vector** alike type](docs/cvec_api.md) - [***cqueue*** - **std::queue** alike type](docs/cqueue_api.md) +- [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md) - [***cpque*** - **std::priority_queue** alike type](docs/cpque_api.md) - [***cmap*** - **std::unordered_map** alike type](docs/cmap_api.md) - [***cset*** - **std::unordered_set** alike type](docs/cset_api.md) - [***csmap*** - **std::map** sorted map alike type](docs/csmap_api.md) - [***csset*** - **std::set** sorted set alike type](docs/csset_api.md) -- [***cstack*** - **std::stack** alike type](docs/cstack_api.md) - [***cstr*** - **std::string** alike type](docs/cstr_api.md) - [***csubstr*** - **std::string_view** alike type](docs/csubstr_api.md) -- [***cspan*** - **std::span/std::mdspan** alike type](docs/cspan_api.md) -- [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md) -- [***cvec*** - **std::vector** alike type](docs/cvec_api.md) +- [***csview*** - null-terminated string view type](docs/csview_api.md) +- [***cspan*** - **std::span** + **std::mdspan** alike type](docs/cspan_api.md) Algorithms ---------- diff --git a/docs/csubstr_api.md b/docs/csubstr_api.md index 6cf76cf7..7094cf82 100644 --- a/docs/csubstr_api.md +++ b/docs/csubstr_api.md @@ -1,18 +1,19 @@ -# STC [csubstr](../include/stc/csubstr.h): String View +# STC [csubstr](../include/stc/csubstr.h): Sub-string View ![String](pics/string.jpg) The type **csubstr** is a non-null terminated string view and can refer to a constant contiguous sequence of char-elements with the first element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size. -Because **csubstr** is non-null terminated, it is not a replacent for `const char*` - see [csview](csview_api.md) +Because **csubstr** is non-null terminated, it is not a replacent view for `const char*` - see [csview](csview_api.md) for that. **csubstr** never allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string storage. It keeps the length of the string, and does not need to call *strlen()* to acquire the length. -Note: a **csubstr** must be printed the following way: +- **csubstr** iterators works on UTF8 codepoints - like **cstr** and **csview** (see Example 2). +- Because it is null-terminated, it must be printed the following way: ```c -printf("%.*s", c_SS(sstr)) +printf("%.*s", c_SS(sstr)); ``` See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional diff --git a/docs/csview_api.md b/docs/csview_api.md index f7e0e2b0..d28e3ed2 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -1,4 +1,4 @@ -# STC [csview](../include/stc/csview.h): String View +# STC [csview](../include/stc/csview.h): Null-terminated UTF8 String View ![String](pics/string.jpg) The type **csview** is a ***null-terminated*** string view and refers to a constant contiguous sequence of @@ -6,9 +6,9 @@ char-elements with the first element of the sequence at position zero. The imple members: a pointer to constant char and a size. See [csubstr](csubstr_api.md) for a ***non null-terminated*** string view/span type. -Because **csview** is null-terminated, it can be a more efficient replacent for `const char*`. It never -allocates memory, and need therefore not be destructed. Its lifetime is limited by the source string -storage. It keeps the length of the string, and does not call *strlen()* when passing it around. +Because **csview** is null-terminated, it can be an efficient replacent for `const char*`. It never +allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string +storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations. ## Header file -- cgit v1.2.3 From 78d8668e6d527070568a405408ed906e51055bf4 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 14 Aug 2023 16:46:24 +0200 Subject: Reverted csubstr => csview. Sorry about that! Added crawstr to become the null-terminated string view. --- README.md | 32 ++-- docs/crawstr_api.md | 130 +++++++++++++ docs/cregex_api.md | 28 +-- docs/cstr_api.md | 34 ++-- docs/csubstr_api.md | 221 ----------------------- docs/csview_api.md | 217 +++++++++++++++------- include/stc/ccommon.h | 13 +- include/stc/crawstr.h | 116 ++++++++++++ include/stc/cregex.h | 36 ++-- include/stc/cstr.h | 148 +++++++-------- include/stc/csubstr.h | 211 ---------------------- include/stc/csview.h | 159 ++++++++++++---- include/stc/forward.h | 34 ++-- include/stc/priv/template.h | 14 +- include/stc/utf8.h | 4 +- misc/benchmarks/various/string_bench_STC.cpp | 32 ++-- misc/examples/algorithms/forfilter.c | 12 +- misc/examples/regularexpressions/regex2.c | 2 +- misc/examples/regularexpressions/regex_match.c | 4 +- misc/examples/regularexpressions/regex_replace.c | 6 +- misc/examples/strings/cstr_match.c | 10 +- misc/examples/strings/replace.c | 4 +- misc/examples/strings/splitstr.c | 8 +- misc/examples/strings/sso_substr.c | 14 +- misc/examples/strings/sview_split.c | 14 +- misc/examples/strings/utf8replace_c.c | 4 +- misc/tests/cregex_test.c | 32 ++-- src/cregex.c | 28 +-- src/libstc.c | 2 +- src/singleupdate.sh | 2 +- src/utf8code.c | 2 +- 31 files changed, 786 insertions(+), 787 deletions(-) create mode 100644 docs/crawstr_api.md delete mode 100644 docs/csubstr_api.md create mode 100644 include/stc/crawstr.h delete mode 100644 include/stc/csubstr.h (limited to 'README.md') diff --git a/README.md b/README.md index 1c8c3878..d99d8a76 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ Containers - [***csmap*** - **std::map** sorted map alike type](docs/csmap_api.md) - [***csset*** - **std::set** sorted set alike type](docs/csset_api.md) - [***cstr*** - **std::string** alike type](docs/cstr_api.md) -- [***csubstr*** - **std::string_view** alike type](docs/csubstr_api.md) -- [***csview*** - null-terminated string view type](docs/csview_api.md) +- [***csview*** - **std::string_view** alike type](docs/csview_api.md) +- [***crawstr*** - null-terminated string view type](docs/crawstr_api.md) - [***cspan*** - **std::span** + **std::mdspan** alike type](docs/cspan_api.md) Algorithms @@ -352,11 +352,11 @@ linking, so *one* c-file must implement the templated container, e.g.: #include "cvec_int.h" ``` The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by -`#define i_static`. Same for the string-view type **csubstr**, but most of its functions are static inlined, so +`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so linking specifications and implementation are only needed for a few lesser used functions. Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**, -**csubstr**, **cregex**, **utf8**, and **crand**. +**csview**, **cregex**, **utf8**, and **crand**. As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent **utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc. @@ -402,8 +402,8 @@ Only functions required by the container type is required to be defined. E.g.: - *Type_clone()* is not used if *#define i_opt c_no_clone* is specified. - `i_key_str` - Sets `i_keyclass` = *cstr*, `i_tag` = *str*, and `i_keyraw` = *const char*\*. Defines both type convertion `i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *const char\*\** as argument. -- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csubstr\**. Defines both type convertion -`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csubstr\** as argument. +- `i_key_ssv` - Sets `i_keyclass` = *cstr*, `i_tag` = *ssv*, and `i_keyraw` = *csview\**. Defines both type convertion +`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *csview\** as argument. - `i_keyboxed` *Type* - Use when *Type* is a smart pointer **carc** or **cbox**. Defines *i_keyclass = Type*, and *i_keyraw = Type\**. NB: Do not use when defining carc/cbox types themselves. - `i_valclass` *Type*, `i_val_str`, `i_val_ssv`, `i_valboxed` - Similar rules as for ***key***. @@ -641,7 +641,7 @@ void maptest() STC is generally very memory efficient. Memory usage for the different containers: - **cstr**, **cvec**, **cstack**, **cpque**: 1 pointer, 2 intptr_t + memory for elements. -- **csubstr**, 1 pointer, 1 intptr_t. Does not own data! +- **csview**, 1 pointer, 1 intptr_t. Does not own data! - **cspan**, 1 pointer and 2 \* dimension \* int32_t. Does not own data! - **clist**: Type size: 1 pointer. Each node allocates a struct to store its value and a next pointer. - **cdeq**, **cqueue**: Type size: 2 pointers, 2 intptr_t. Otherwise like *cvec*. @@ -655,7 +655,7 @@ STC is generally very memory efficient. Memory usage for the different container ## Version 4.3 - Breaking changes: - - **cstr** and **csubstr** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. + - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including. - Renamed => `` - Moved => `` - Much improved with some new API and added features. @@ -687,7 +687,7 @@ STC is generally very memory efficient. Memory usage for the different container - Renamed c_flt_count(i) => `c_flt_counter(i)` - Renamed c_flt_last(i) => `c_flt_getcount(i)` - Renamed c_ARRAYLEN() => c_arraylen() -- Removed deprecated c_ARGSV(). Use c_SS() +- Removed deprecated c_ARGSV(). Use c_SV() - Removed c_PAIR ## Version 4.1.1 @@ -700,7 +700,7 @@ Major changes: - [crange](docs/algorithm_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator. - [c_forfilter](docs/algorithm_api.md#c_forfilter) - ranges-like view filtering. - [csort](include/stc/algo/sort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison. -- Renamed `c_ARGSV()` => `c_SS()`: **csubstr** print arg. Note `c_ss()` is shorthand for *csubstr_from()*. +- Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*. - Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h. - Some API changes in **cregex** and **cstr**. - Create single header container versions with python script. @@ -714,18 +714,18 @@ Major changes: - New + renamed loop iteration/scope macros: - `c_forlist`: macro replacing `c_forarray` and `c_apply`. Iterate a compound literal list. - `c_forrange`: macro replacing `c_forrange`. Iterate a `long long` type number sequence. -- Updated **cstr**, now always takes self as pointer, like all containers except csubstr. +- Updated **cstr**, now always takes self as pointer, like all containers except csview. - Updated **cvec**, **cdeq**, changed `*_range*` function names. ## Changes version 3.8 -- Overhauled some **cstr** and **csubstr** API: +- Overhauled some **cstr** and **csview** API: - Changed cstr_replace*() => `cstr_replace_at*(self, pos, len, repl)`: Replace at specific position. - Changed `cstr_replace_all() cstr_replace*(self, search, repl, count)`: Replace count occurences. - Renamed `cstr_find_from()` => `cstr_find_at()` - Renamed `cstr_*_u8()` => `cstr_u8_*()` - - Renamed `csubstr_*_u8()` => `csubstr_u8_*()` - - Added cstr_u8_slice() and csubstr_u8_slice(). - - Removed `csubstr_from_s()`: Use `cstr_ss(s)` instead. + - Renamed `csview_*_u8()` => `csview_u8_*()` + - Added cstr_u8_slice() and csview_u8_slice(). + - Removed `csview_from_s()`: Use `cstr_sv(s)` instead. - Added back file coption.h - Simplified **cbits** usage: all inlined. - Updated docs. @@ -760,7 +760,7 @@ Major changes: - Renamed: *cstr_new()* to `cstr_lit(literal)`, and *cstr_assign_fmt()* to `cstr_printf()`. - Renamed: *c_default_fromraw()* to `c_default_from()`. - Changed: the [**c_apply**](docs/algorithm_api.md) macros API. -- Replaced: *csubstr_first_token()* and *csubstr_next_token()* with one function: `csubstr_token()`. +- Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`. - Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly. - Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions. - Added: `i_opt` template parameter: compile-time options: `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|` diff --git a/docs/crawstr_api.md b/docs/crawstr_api.md new file mode 100644 index 00000000..d44c302d --- /dev/null +++ b/docs/crawstr_api.md @@ -0,0 +1,130 @@ +# STC [crawstr](../include/stc/crawstr.h): Null-terminated UTF8 String View +![String](pics/string.jpg) + +The type **crawstr** is a ***null-terminated*** string view and refers to a constant contiguous sequence of +char-elements with the first element of the sequence at position zero. The implementation holds two +members: a pointer to constant char and a size. See [csview](csview_api.md) for a ***non null-terminated*** +string view/span type. + +Because **crawstr** is null-terminated, it can be an efficient replacent for `const char*`. It never +allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string +storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations. + +## Header file + +All crawstr definitions and prototypes are available by including a single header file. + +```c +#define i_implement +#include +#include +``` +## Methods + +```c +crawstr crawstr_from(const char* str); // construct from const char* +crawstr c_rs(const char literal_only[]); // construct from literal, no strlen() + +intptr_t crawstr_size(crawstr rs); +bool crawstr_empty(crawstr rs); // check if size == 0 +void crawstr_clear(crawstr* self); +csview crawstr_sv(crawstr rs); // convert to csview type + +bool crawstr_equals(crawstr rs, const char* str); +intptr_t crawstr_find(crawstr rs, const char* str); +bool crawstr_contains(crawstr rs, const char* str); +bool crawstr_starts_with(crawstr rs, const char* str); +bool crawstr_ends_with(crawstr rs, const char* str); +``` + +#### UTF8 methods +```c +intptr_t crawstr_u8_size(crawstr rs); +bool crawstr_valid_utf8(crawstr rs); // depends on src/utf8code.c + +crawstr_iter crawstr_begin(const crawstr* self); +crawstr_iter crawstr_end(const crawstr* self); +void crawstr_next(crawstr_iter* it); // utf8 codepoint step, not byte! +crawstr_iter crawstr_advance(crawstr_iter it, intptr_t n); + + // from utf8.h +intptr_t utf8_size(const char *s); +intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes +const char* utf8_at(const char *s, intptr_t index); // from UTF8 index to char* position +intptr_t utf8_pos(const char* s, intptr_t index); // from UTF8 index to byte index position +unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4 + // implemented in src/utf8code.c: +bool utf8_valid(const char* s); +bool utf8_valid_n(const char* s, intptr_t nbytes); +uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, return state. +unsigned utf8_encode(char *out, uint32_t codepoint); // encode unicode cp into out buffer +uint32_t utf8_peek(const char* s); // codepoint value of character at s +uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative) +``` + +#### Helper methods +```c +int crawstr_cmp(const crawstr* x, const crawstr* y); +int crawstr_icmp(const crawstr* x, const crawstr* y); // depends on src/utf8code.c: +bool crawstr_eq(const crawstr* x, const crawstr* y); +uint64_t crawstr_hash(const crawstr* x); +``` + +## Types + +| Type name | Type definition | Used to represent... | +|:----------------|:-------------------------------------------|:-------------------------| +| `crawstr` | `struct { const char *str; intptr_t size; }` | The string view type | +| `crawstr_value` | `char` | The string element type | +| `crawstr_iter` | `struct { crawstr_value *ref; }` | UTF8 iterator | + +## Example: UTF8 iteration and case conversion +```c +#define i_import +#include +#include + +int main(void) +{ + cstr str = cstr_from("Liberté, égalité, fraternité."); + crawstr rs = cstr_rs(&str); + + c_foreach (i, crawstr, rs) + printf("%.*s ", c_SV(i.u8.chr)); + puts(""); + + cstr_uppercase(&str); + printf("%s\n", cstr_str(&str)); + + cstr_drop(&str); +} +``` +Output: +``` +L i b e r t é , é g a l i t é , f r a t e r n i t é . +LIBERTÉ, ÉGALITÉ, FRATERNITÉ. +``` + +### Example 2: UTF8 replace +```c +#define i_import // include dependent utf8 definitions. +#include + +int main(void) +{ + cstr s1 = cstr_lit("hell😀 w😀rld"); + + cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_rs("ø")); + printf("%s\n", cstr_str(&s1)); + + c_foreach (i, cstr, s1) + printf("%.*s,", c_SV(i.u8.chr)); // u8.chr is a csview + + cstr_drop(&s1); +} +``` +Output: +``` +hell😀 wørld +h,e,l,l,😀, ,w,ø,r,l,d, +``` diff --git a/docs/cregex_api.md b/docs/cregex_api.md index 98161fe9..52476e09 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -33,11 +33,11 @@ int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_ int cregex_captures(const cregex* self); // return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR -int cregex_find(const cregex* re, const char* input, csubstr match[], int mflags = CREG_DEFAULT); +int cregex_find(const cregex* re, const char* input, csview match[], int mflags = CREG_DEFAULT); // Search inside input string-view only -int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]); +int cregex_find_sv(const cregex* re, csview input, csview match[]); // All-in-one search (compile + find + drop) -int cregex_find_pattern(const char* pattern, const char* input, csubstr match[], int cmflags = CREG_DEFAULT); +int cregex_find_pattern(const char* pattern, const char* input, csview match[], int cmflags = CREG_DEFAULT); // Check if there are matches in input bool cregex_is_match(const cregex* re, const char* input); @@ -45,14 +45,14 @@ bool cregex_is_match(const cregex* re, const char* input); // Replace all matches in input cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX); // Replace count matches in input string-view. Optionally transform replacement. -cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count = INT_MAX); -cstr cregex_replace_ss(const cregex* re, csubstr input, const char* replace, int count, - bool(*transform)(int group, csubstr match, cstr* result), int rflags); +cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX); +cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count, + bool(*transform)(int group, csview match, cstr* result), int rflags); // All-in-one replacement (compile + find/replace + drop) cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX); cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count, - bool(*transform)(int group, csubstr match, cstr* result), int rflags); + bool(*transform)(int group, csview match, cstr* result), int rflags); // destroy void cregex_drop(cregex* self); ``` @@ -109,9 +109,9 @@ int main(void) { cregex re = cregex_from(pattern); // Lets find the first date in the string: - csubstr match[4]; // full-match, year, month, date. + csview match[4]; // full-match, year, month, date. if (cregex_find(&re, input, match) == CREG_OK) - printf("Found date: %.*s\n", c_SS(match[0])); + printf("Found date: %.*s\n", c_SV(match[0])); else printf("Could not find any date\n"); @@ -127,7 +127,7 @@ int main(void) { For a single match you may use the all-in-one function: ```c if (cregex_find_pattern(pattern, input, match)) - printf("Found date: %.*s\n", c_SS(match[0])); + printf("Found date: %.*s\n", c_SV(match[0])); ``` To use: `gcc first_match.c src/cregex.c src/utf8code.c`. @@ -137,16 +137,16 @@ In order to use a callback function in the replace call, see `examples/regex_rep To iterate multiple matches in an input string, you may use ```c -csubstr match[5] = {0}; +csview match[5] = {0}; while (cregex_find(&re, input, match, CREG_NEXT) == CREG_OK) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SS(match[k])); + printf("submatch %d: %.*s\n", k, c_SV(match[k])); ``` There is also a for-loop macro to simplify it: ```c c_formatch (it, &re, input) for (int k = 1; i <= cregex_captures(&re); ++k) - printf("submatch %d: %.*s\n", k, c_SS(it.match[k])); + printf("submatch %d: %.*s\n", k, c_SV(it.match[k])); ``` ## Using cregex in a project @@ -154,7 +154,7 @@ c_formatch (it, &re, input) The easiest is to `#define i_import` before `#include `. Make sure to do that in one translation unit only. For reference, **cregex** uses the following files: -- `stc/cregex.h`, `stc/utf8.h`, `stc/csubstr.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` +- `stc/cregex.h`, `stc/utf8.h`, `stc/csview.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h` - `src/cregex.c`, `src/utf8code.c`. ## Regex Cheatsheet diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 07b9b4c8..1da57b0c 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -22,8 +22,8 @@ cstr cstr_init(void); // construct cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call. cstr cstr_from(const char* str); // constructor using strlen() cstr cstr_from_n(const char* str, intptr_t n); // constructor with n first bytes of str -cstr cstr_from_sv(csview sv); // construct cstr from csview -cstr cstr_from_ss(csubstr ss); // construct cstr from csubstr +cstr cstr_from_sv(csview ss); // construct cstr from csview +cstr cstr_from_rs(crawstr rs); // construct cstr from crawstr cstr cstr_with_capacity(intptr_t cap); cstr cstr_with_size(intptr_t len, char fill); // repeat fill len times cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting @@ -35,7 +35,7 @@ void cstr_drop(cstr* self); // destructo const char* cstr_str(const cstr* self); // to const char* csview cstr_sv(const cstr* self); // to csview -csubstr cstr_ss(const cstr* self); // to csubstr +crawstr cstr_rs(const cstr* self); // to crawstr char* cstr_data(cstr* self); // to mutable char* cstr_buf cstr_buffer(cstr* self); // to mutable buffer (with capacity) @@ -50,13 +50,13 @@ void cstr_clear(cstr* self); char* cstr_assign(cstr* self, const char* str); char* cstr_assign_n(cstr* self, const char* str, intptr_t n); // assign n first bytes of str -char* cstr_assign_ss(cstr* self, csubstr ss); +char* cstr_assign_sv(cstr* self, csview ss); char* cstr_copy(cstr* self, cstr s); // copy-assign a cstr int cstr_printf(cstr* self, const char* fmt, ...); // source and target must not overlap. char* cstr_append(cstr* self, const char* str); char* cstr_append_n(cstr* self, const char* str, intptr_t n); // append n first bytes of str -char* cstr_append_ss(cstr* self, csubstr str); +char* cstr_append_sv(cstr* self, csview str); char* cstr_append_s(cstr* self, cstr str); int cstr_append_fmt(cstr* self, const char* fmt, ...); // printf() formatting char* cstr_append_uninit(cstr* self, intptr_t len); // return ptr to start of uninited data @@ -65,19 +65,19 @@ void cstr_push(cstr* self, const char* chr); // append on void cstr_pop(cstr* self); // pop one utf8 char void cstr_insert(cstr* self, intptr_t pos, const char* ins); -void cstr_insert_ss(cstr* self, intptr_t pos, csubstr ins); +void cstr_insert_sv(cstr* self, intptr_t pos, csview ins); void cstr_insert_s(cstr* self, intptr_t pos, cstr ins); void cstr_erase(cstr* self, intptr_t pos, intptr_t len); // erase len bytes from pos void cstr_replace(cstr* self, const char* search, const char* repl, unsigned count = MAX_INT); -cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, unsigned count); +cstr cstr_replace_sv(csview in, csview search, csview repl, unsigned count); void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl); // replace at a pos -void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl); +void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl); void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl); bool cstr_equals(const cstr* self, const char* str); -bool cstr_equals_ss(const cstr* self, csubstr ss); +bool cstr_equals_sv(const cstr* self, csview ss); bool cstr_equals_s(const cstr* self, cstr s); intptr_t cstr_find(const cstr* self, const char* search); @@ -85,11 +85,11 @@ intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); // bool cstr_contains(const cstr* self, const char* search); bool cstr_starts_with(const cstr* self, const char* str); -bool cstr_starts_with_ss(const cstr* self, csubstr ss); +bool cstr_starts_with_sv(const cstr* self, csview ss); bool cstr_starts_with_s(const cstr* self, cstr s); bool cstr_ends_with(const cstr* self, const char* str); -bool cstr_ends_with_ss(const cstr* self, csubstr ss); +bool cstr_ends_with_sv(const cstr* self, csview ss); bool cstr_ends_with_s(const cstr* self, cstr s); bool cstr_getline(cstr *self, FILE *stream); // cstr_getdelim(self, '\n', stream) @@ -102,8 +102,8 @@ intptr_t cstr_u8_size(const cstr* self); // number of intptr_t cstr_u8_size_n(const cstr self, intptr_t nbytes); // utf8 size within n bytes intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx); // byte pos offset at utf8 codepoint index const char* cstr_u8_at(const cstr* self, intptr_t u8idx); // char* position at utf8 codepoint index -csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csubstr -void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl); // replace u8len utf8 chars +csview cstr_u8_chr(const cstr* self, intptr_t u8idx); // get utf8 character as a csview +void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl); // replace u8len utf8 chars void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); // erase u8len codepoints from pos // iterate utf8 codepoints @@ -114,14 +114,14 @@ cstr_iter cstr_advance(cstr_iter it, intptr_t n); // utf8 functions requires linking with src/utf8code.c symbols: bool cstr_valid_utf8(const cstr* self); // check if str is valid utf8 -cstr cstr_casefold_ss(csubstr ss); // returns new casefolded utf8 cstr +cstr cstr_casefold_sv(csview ss); // returns new casefolded utf8 cstr cstr cstr_tolower(const char* str); // returns new lowercase utf8 cstr -cstr cstr_tolower_ss(csubstr ss); // returns new lowercase utf8 cstr +cstr cstr_tolower_sv(csview ss); // returns new lowercase utf8 cstr void cstr_lowercase(cstr* self); // transform cstr to lowercase utf8 cstr cstr_toupper(const char* str); // returns new uppercase utf8 cstr -cstr cstr_toupper_ss(csubstr ss); // returns new uppercase utf8 cstr +cstr cstr_toupper_sv(csview ss); // returns new uppercase utf8 cstr void cstr_uppercase(cstr* self); // transform cstr to uppercase utf8 int cstr_icmp(const cstr* s1, const cstr* s2); // utf8 case-insensitive comparison @@ -146,7 +146,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr |:----------------|:---------------------------------------------|:---------------------| | `cstr` | `struct { ... }` | The string type | | `cstr_value` | `char` | String element type | -| `csubstr` | `struct { const char *str; intptr_t size; }` | String view type | +| `csview` | `struct { const char *str; intptr_t size; }` | String view type | | `cstr_buf` | `struct { char *data; intptr_t size, cap; }` | String buffer type | ## Constants and macros diff --git a/docs/csubstr_api.md b/docs/csubstr_api.md deleted file mode 100644 index 7094cf82..00000000 --- a/docs/csubstr_api.md +++ /dev/null @@ -1,221 +0,0 @@ -# STC [csubstr](../include/stc/csubstr.h): Sub-string View -![String](pics/string.jpg) - -The type **csubstr** is a non-null terminated string view and can refer to a constant contiguous sequence of -char-elements with the first element of the sequence at position zero. The implementation holds two members: -a pointer to constant char and a size. - -Because **csubstr** is non-null terminated, it is not a replacent view for `const char*` - see [csview](csview_api.md) -for that. **csubstr** never allocates memory, and therefore need not be destructed. Its lifetime is limited by -the source string storage. It keeps the length of the string, and does not need to call *strlen()* to acquire -the length. - -- **csubstr** iterators works on UTF8 codepoints - like **cstr** and **csview** (see Example 2). -- Because it is null-terminated, it must be printed the following way: -```c -printf("%.*s", c_SS(sstr)); -``` - -See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional -description. - -## Header file - -All csubstr definitions and prototypes are available by including a single header file. - -```c -#define i_implement -#include -#include // after cstr.h: include extra cstr-csubstr functions -``` -## Methods - -```c -csubstr c_ss(const char literal_only[]); // construct from literal, no strlen() -csubstr c_ss(const char* str, intptr_t n); // construct from str and length n -csubstr csubstr_from(const char* str); // construct from const char* -csubstr csubstr_from_n(const char* str, intptr_t n); // alias for c_ss(str, n) - -intptr_t csubstr_size(csubstr ss); -bool csubstr_empty(csubstr ss); -void csubstr_clear(csubstr* self); - -bool csubstr_equals(csubstr ss, const char* str); -intptr_t csubstr_equals_ss(csubstr ss, csubstr find); -intptr_t csubstr_find(csubstr ss, const char* str); -intptr_t csubstr_find_ss(csubstr ss, csubstr find); -bool csubstr_contains(csubstr ss, const char* str); -bool csubstr_starts_with(csubstr ss, const char* str); -bool csubstr_ends_with(csubstr ss, const char* str); -csubstr csubstr_substr(csubstr ss, intptr_t pos, intptr_t n); -csubstr csubstr_slice(csubstr ss, intptr_t pos1, intptr_t pos2); - -csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n); // negative pos count from end -csubstr csubstr_slice_ex(csubstr ss, intptr_t pos1, intptr_t pos2); // negative pos1, pos2 count from end -csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start); // *start > ss.size after last token -``` - -#### UTF8 methods -```c -intptr_t csubstr_u8_size(csubstr ss); -csubstr csubstr_u8_substr(csubstr ss, intptr_t bytepos, intptr_t u8len); -bool csubstr_valid_utf8(csubstr ss); // requires linking with src/utf8code.c - -csubstr_iter csubstr_begin(const csubstr* self); -csubstr_iter csubstr_end(const csubstr* self); -void csubstr_next(csubstr_iter* it); // utf8 codepoint step, not byte! -csubstr_iter csubstr_advance(csubstr_iter it, intptr_t n); -``` - -#### cstr methods returning csubstr -```c -csubstr cstr_slice(const cstr* self, intptr_t pos1, intptr_t pos2); -csubstr cstr_slice_ex(const cstr* self, intptr_t pos1, intptr_t pos2); // see csubstr_slice_ex() -csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n); -csubstr cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n); // see csubstr_substr_ex() -csubstr cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); -``` -#### Iterate tokens with *c_fortoken*, *c_fortoken_ss* - -To iterate tokens in an input string separated by a string: -```c -c_fortoken (i, "hello, one, two, three", ", ") - printf("token: %.*s\n", c_SS(i.token)); -``` - -#### Helper methods -```c -int csubstr_cmp(const csubstr* x, const csubstr* y); -int csubstr_icmp(const csubstr* x, const csubstr* y); -bool csubstr_eq(const csubstr* x, const csubstr* y); -uint64_t csubstr_hash(const csubstr* x); -``` - -## Types - -| Type name | Type definition | Used to represent... | -|:----------------|:-------------------------------------------|:-------------------------| -| `csubstr` | `struct { const char *str; intptr_t size; }` | The string view type | -| `csubstr_value` | `char` | The string element type | -| `csubstr_iter` | `struct { csubstr_value *ref; }` | UTF8 iterator | - -## Constants and macros - -| Name | Value | Usage | -|:---------------|:---------------------|:---------------------------------------------| -| `c_SS(ss)` | printf argument | `printf("ss: %.*s\n", c_SS(ss));` | - -## Example -```c -#define i_implement -#include -#include - -int main(void) -{ - cstr str1 = cstr_from("We think in generalities, but we live in details."); - // (quoting Alfred N. Whitehead) - - csubstr ss1 = cstr_substr_ex(&str1, 3, 5); // "think" - intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 - csubstr ss2 = cstr_substr_ex(&str1, pos, 4); // get "live" - csubstr ss3 = cstr_slice_ex(&str1, -8, -1); // get "details" - printf("%.*s %.*s %.*s\n", - c_SS(ss1), c_SS(ss2), c_SS(ss3)); - cstr s1 = cstr_lit("Apples are red"); - cstr s2 = cstr_from_ss(cstr_substr_ex(&s1, -3, 3)); // "red" - cstr s3 = cstr_from_ss(cstr_substr_ex(&s1, 0, 6)); // "Apples" - printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); - - c_drop(cstr, &str1, &s1, &s2, &s3); -} -``` -Output: -``` -think live details -red Apples -``` - -### Example 2: UTF8 handling -```c -#define i_import // include dependent cstr, utf8 and cregex function definitions. -#include - -int main(void) -{ - cstr s1 = cstr_lit("hell😀 w😀rld"); - - cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_ss("ø")); - printf("%s\n", cstr_str(&s1)); - - c_foreach (i, cstr, s1) - printf("%.*s,", c_SS(i.u8.chr)); - - cstr_drop(&s1); -} -``` -Output: -``` -hell😀 wørld -h,e,l,l,😀, ,w,ø,r,l,d, -``` - -### Example 3: csubstr tokenizer (string split) -Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, -and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. -```c -#include -#include - -void print_split(csubstr input, const char* sep) -{ - c_fortoken_ss (i, input, sep) - printf("[%.*s]\n", c_SS(i.token)); - puts(""); -} -#define i_implement -#include -#define i_key_str -#include - -cstack_str string_split(csubstr input, const char* sep) -{ - cstack_str out = cstack_str_init(); - - c_fortoken_ss (i, input, sep) - cstack_str_push(&out, cstr_from_ss(i.token)); - - return out; -} - -int main(void) -{ - print_split(c_ss("//This is a//double-slash//separated//string"), "//"); - print_split(c_ss("This has no matching separator"), "xx"); - - cstack_str s = string_split(c_ss("Split,this,,string,now,"), ","); - - c_foreach (i, cstack_str, s) - printf("[%s]\n", cstr_str(i.ref)); - puts(""); - - cstack_str_drop(&s); -} -``` -Output: -``` -[] -[This is a] -[double-slash] -[separated] -[string] - -[This has no matching separator] - -[Split] -[this] -[] -[string] -[now] -[] -``` diff --git a/docs/csview_api.md b/docs/csview_api.md index d28e3ed2..eafc6854 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -1,14 +1,23 @@ -# STC [csview](../include/stc/csview.h): Null-terminated UTF8 String View +# STC [csview](../include/stc/csview.h): Sub-string View ![String](pics/string.jpg) -The type **csview** is a ***null-terminated*** string view and refers to a constant contiguous sequence of -char-elements with the first element of the sequence at position zero. The implementation holds two -members: a pointer to constant char and a size. See [csubstr](csubstr_api.md) for a ***non null-terminated*** -string view/span type. +The type **csview** is a non-null terminated string view and can refer to a constant contiguous sequence of +char-elements with the first element of the sequence at position zero. The implementation holds two members: +a pointer to constant char and a size. -Because **csview** is null-terminated, it can be an efficient replacent for `const char*`. It never -allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string -storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations. +Because **csview** is non-null terminated, it is not an ideal replacent view for `const char*` - see [crawstr](crawstr_api.md) +for that. **csview** never allocates memory, and therefore need not be destructed. Its lifetime is limited by +the source string storage. It keeps the length of the string, and does not need to call *strlen()* to acquire +the length. + +- **csview** iterators works on UTF8 codepoints - like **cstr** and **crawstr** (see Example 2). +- Because it is null-terminated, it must be printed the following way: +```c +printf("%.*s", c_SV(sstr)); +``` + +See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional +description. ## Header file @@ -22,52 +31,64 @@ All csview definitions and prototypes are available by including a single header ## Methods ```c -csview c_sv(const char literal_only[]); // construct from literal, no strlen() -csview csview_from(const char* str); // construct from const char* +csview c_sv(const char literal_only[]); // construct from literal, no strlen() +csview c_sv(const char* str, intptr_t n); // construct from str and length n +csview csview_from(const char* str); // construct from const char* +csview csview_from_n(const char* str, intptr_t n); // alias for c_sv(str, n) + +intptr_t csview_size(csview sv); +bool csview_empty(csview sv); +void csview_clear(csview* self); + +bool csview_equals(csview sv, const char* str); +intptr_t csview_equals_sv(csview sv, csview find); +intptr_t csview_find(csview sv, const char* str); +intptr_t csview_find_sv(csview sv, csview find); +bool csview_contains(csview sv, const char* str); +bool csview_starts_with(csview sv, const char* str); +bool csview_ends_with(csview sv, const char* str); +csview csview_substr(csview sv, intptr_t pos, intptr_t n); +csview csview_slice(csview sv, intptr_t pos1, intptr_t pos2); + +csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); // negative pos count from end +csview csview_slice_ex(csview sv, intptr_t pos1, intptr_t pos2); // negative pos1, pos2 count from end +csview csview_token(csview sv, const char* sep, intptr_t* start); // *start > sv.size after last token +``` -intptr_t csview_size(csview sv); -bool csview_empty(csview sv); // check if size == 0 -void csview_clear(csview* self); -csubstr csview_ss(csview sv); // convert to csubstr type +#### UTF8 methods +```c +intptr_t csview_u8_size(csview sv); +csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len); +bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c + +csview_iter csview_begin(const csview* self); +csview_iter csview_end(const csview* self); +void csview_next(csview_iter* it); // utf8 codepoint step, not byte! +csview_iter csview_advance(csview_iter it, intptr_t n); +``` -bool csview_equals(csview sv, const char* str); -intptr_t csview_find(csview sv, const char* str); -bool csview_contains(csview sv, const char* str); -bool csview_starts_with(csview sv, const char* str); -bool csview_ends_with(csview sv, const char* str); +#### cstr methods returning csview +```c +csview cstr_slice(const cstr* self, intptr_t pos1, intptr_t pos2); +csview cstr_slice_ex(const cstr* self, intptr_t pos1, intptr_t pos2); // see csview_slice_ex() +csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n); +csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n); // see csview_substr_ex() +csview cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len); ``` +#### Iterate tokens with *c_fortoken*, *c_fortoken_sv* -#### UTF8 methods +To iterate tokens in an input string separated by a string: ```c -intptr_t csview_u8_size(csview sv); -bool csview_valid_utf8(csview sv); // depends on src/utf8code.c - -csview_iter csview_begin(const csview* self); -csview_iter csview_end(const csview* self); -void csview_next(csview_iter* it); // utf8 codepoint step, not byte! -csview_iter csview_advance(csview_iter it, intptr_t n); - - // from utf8.h -intptr_t utf8_size(const char *s); -intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes -const char* utf8_at(const char *s, intptr_t index); // from UTF8 index to char* position -intptr_t utf8_pos(const char* s, intptr_t index); // from UTF8 index to byte index position -unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4 - // implemented in src/utf8code.c: -bool utf8_valid(const char* s); -bool utf8_valid_n(const char* s, intptr_t nbytes); -uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, return state. -unsigned utf8_encode(char *out, uint32_t codepoint); // encode unicode cp into out buffer -uint32_t utf8_peek(const char* s); // codepoint value of character at s -uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative) +c_fortoken (i, "hello, one, two, three", ", ") + printf("token: %.*s\n", c_SV(i.token)); ``` #### Helper methods ```c -int csview_cmp(const csview* x, const csview* y); -int csview_icmp(const csview* x, const csview* y); // depends on src/utf8code.c: -bool csview_eq(const csview* x, const csview* y); -uint64_t csview_hash(const csview* x); +int csview_cmp(const csview* x, const csview* y); +int csview_icmp(const csview* x, const csview* y); +bool csview_eq(const csview* x, const csview* y); +uint64_t csview_hash(const csview* x); ``` ## Types @@ -78,36 +99,46 @@ uint64_t csview_hash(const csview* x); | `csview_value` | `char` | The string element type | | `csview_iter` | `struct { csview_value *ref; }` | UTF8 iterator | -## Example: UTF8 iteration and case conversion +## Constants and macros + +| Name | Value | Usage | +|:---------------|:---------------------|:---------------------------------------------| +| `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` | + +## Example ```c -#define i_import +#define i_implement #include #include int main(void) { - cstr str = cstr_from("Liberté, égalité, fraternité."); - csview sv = cstr_sv(&str); - - c_foreach (i, csview, sv) - printf("%.*s ", c_SS(i.u8.chr)); - puts(""); - - cstr_uppercase(&str); - printf("%s\n", cstr_str(&str)); - - cstr_drop(&str); + cstr str1 = cstr_from("We think in generalities, but we live in details."); + // (quoting Alfred N. Whitehead) + + csview ss1 = cstr_substr_ex(&str1, 3, 5); // "think" + intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1 + csview ss2 = cstr_substr_ex(&str1, pos, 4); // get "live" + csview ss3 = cstr_slice_ex(&str1, -8, -1); // get "details" + printf("%.*s %.*s %.*s\n", + c_SV(ss1), c_SV(ss2), c_SV(ss3)); + cstr s1 = cstr_lit("Apples are red"); + cstr s2 = cstr_from_sv(cstr_substr_ex(&s1, -3, 3)); // "red" + cstr s3 = cstr_from_sv(cstr_substr_ex(&s1, 0, 6)); // "Apples" + printf("%s %s\n", cstr_str(&s2), cstr_str(&s3)); + + c_drop(cstr, &str1, &s1, &s2, &s3); } ``` Output: ``` -L i b e r t é , é g a l i t é , f r a t e r n i t é . -LIBERTÉ, ÉGALITÉ, FRATERNITÉ. +think live details +red Apples ``` -### Example 2: UTF8 replace +### Example 2: UTF8 handling ```c -#define i_import // include dependent utf8 definitions. +#define i_import // include dependent cstr, utf8 and cregex function definitions. #include int main(void) @@ -118,7 +149,7 @@ int main(void) printf("%s\n", cstr_str(&s1)); c_foreach (i, cstr, s1) - printf("%.*s,", c_SS(i.u8.chr)); // u8.chr is a csubstr + printf("%.*s,", c_SV(i.u8.chr)); cstr_drop(&s1); } @@ -128,3 +159,63 @@ Output: hell😀 wørld h,e,l,l,😀, ,w,ø,r,l,d, ``` + +### Example 3: csview tokenizer (string split) +Splits strings into tokens. *print_split()* makes **no** memory allocations or *strlen()* calls, +and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr. +```c +#include +#include + +void print_split(csview input, const char* sep) +{ + c_fortoken_sv (i, input, sep) + printf("[%.*s]\n", c_SV(i.token)); + puts(""); +} +#define i_implement +#include +#define i_key_str +#include + +cstack_str string_split(csview input, const char* sep) +{ + cstack_str out = cstack_str_init(); + + c_fortoken_sv (i, input, sep) + cstack_str_push(&out, cstr_from_sv(i.token)); + + return out; +} + +int main(void) +{ + print_split(c_sv("//This is a//double-slash//separated//string"), "//"); + print_split(c_sv("This has no matching separator"), "xx"); + + cstack_str s = string_split(c_sv("Split,this,,string,now,"), ","); + + c_foreach (i, cstack_str, s) + printf("[%s]\n", cstr_str(i.ref)); + puts(""); + + cstack_str_drop(&s); +} +``` +Output: +``` +[] +[This is a] +[double-slash] +[separated] +[string] + +[This has no matching separator] + +[Split] +[this] +[] +[string] +[now] +[] +``` diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 1b4a2277..e5422adc 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -130,14 +130,13 @@ typedef const char* ccharptr; #define ccharptr_clone(s) (s) #define ccharptr_drop(p) ((void)p) -#define c_ss(...) c_MACRO_OVERLOAD(c_ss, __VA_ARGS__) -#define c_ss_1(literal) c_ss_2(literal, c_litstrlen(literal)) -#define c_ss_2(str, n) (c_LITERAL(csubstr){str, n}) -#define c_SS(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SS(ss)); - -#define c_sv(literal) c_sv_2(literal, c_litstrlen(literal)) +#define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__) +#define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal)) #define c_sv_2(str, n) (c_LITERAL(csview){str, n}) -#define c_SV(sv) c_SS(sv) // [deprecated] - unneeded +#define c_SV(ss) (int)(ss).size, (ss).str // printf("%.*s\n", c_SV(ss)); + +#define c_rs(literal) c_rs_2(literal, c_litstrlen(literal)) +#define c_rs_2(str, n) (c_LITERAL(crawstr){str, n}) #define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) diff --git a/include/stc/crawstr.h b/include/stc/crawstr.h new file mode 100644 index 00000000..7cf62e94 --- /dev/null +++ b/include/stc/crawstr.h @@ -0,0 +1,116 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#define _i_inc_utf8 +#include "utf8.h" + +#ifndef CRAWSTR_H_INCLUDED +#define CRAWSTR_H_INCLUDED + +#define crawstr_init() c_rs("") +#define crawstr_drop(p) c_default_drop(p) +#define crawstr_clone(rs) c_default_clone(rs) + +STC_INLINE crawstr crawstr_from(const char* str) + { return c_rs_2(str, c_strlen(str)); } +STC_INLINE void crawstr_clear(crawstr* self) { *self = crawstr_init(); } +STC_INLINE csview crawstr_sv(crawstr rs) { return c_sv_2(rs.str, rs.size); } + +STC_INLINE intptr_t crawstr_size(crawstr rs) { return rs.size; } +STC_INLINE bool crawstr_empty(crawstr rs) { return rs.size == 0; } + +STC_INLINE bool crawstr_equals(crawstr rs, const char* str) { + intptr_t n = c_strlen(str); + return rs.size == n && !c_memcmp(rs.str, str, n); +} + +STC_INLINE intptr_t crawstr_find(crawstr rs, const char* search) { + char* res = cstrnstrn(rs.str, search, rs.size, c_strlen(search)); + return res ? (res - rs.str) : c_NPOS; +} + +STC_INLINE bool crawstr_contains(crawstr rs, const char* str) + { return crawstr_find(rs, str) != c_NPOS; } + +STC_INLINE bool crawstr_starts_with(crawstr rs, const char* str) { + intptr_t n = c_strlen(str); + return n > rs.size ? false : !c_memcmp(rs.str, str, n); +} + +STC_INLINE bool crawstr_ends_with(crawstr rs, const char* str) { + intptr_t n = c_strlen(str); + return n > rs.size ? false : !c_memcmp(rs.str + rs.size - n, str, n); +} + +/* utf8 iterator */ +STC_INLINE crawstr_iter crawstr_begin(const crawstr* self) { + if (!self->size) return c_LITERAL(crawstr_iter){.ref = NULL}; + return c_LITERAL(crawstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}}; +} +STC_INLINE crawstr_iter crawstr_end(const crawstr* self) { + (void)self; return c_LITERAL(crawstr_iter){.ref = NULL}; +} +STC_INLINE void crawstr_next(crawstr_iter* it) { + it->ref += it->u8.chr.size; + it->u8.chr.size = utf8_chr_size(it->ref); + if (!*it->ref) it->ref = NULL; +} +STC_INLINE crawstr_iter crawstr_advance(crawstr_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (!*it.ref) it.ref = NULL; + return it; +} + +/* utf8 size */ +STC_INLINE intptr_t crawstr_u8_size(crawstr rs) + { return utf8_size_n(rs.str, rs.size); } + +/* utf8 validation: depends on src/utf8code.c */ +STC_INLINE bool crawstr_valid_utf8(crawstr rs) + { return utf8_valid_n(rs.str, rs.size); } + +/* utf8 ignore case cmp: depends on src/utf8code.c */ +STC_INLINE int crawstr_icmp(const crawstr* x, const crawstr* y) + { return utf8_icmp_sv(c_sv_2(x->str, x->size), c_sv_2(y->str, y->size)); } + + +STC_INLINE int crawstr_cmp(const crawstr* x, const crawstr* y) { + intptr_t n = x->size < y->size ? x->size : y->size; + int c = c_memcmp(x->str, y->str, n); + return c ? c : (int)(x->size - y->size); +} + +STC_INLINE bool crawstr_eq(const crawstr* x, const crawstr* y) + { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } + +STC_INLINE uint64_t crawstr_hash(const crawstr *self) + { return cfasthash(self->str, self->size); } + +#endif // CRAWSTR_H_INCLUDED +#undef i_static +#undef i_header +#undef i_implement +#undef i_import +#undef i_opt diff --git a/include/stc/cregex.h b/include/stc/cregex.h index 3aab3c8b..bce94b04 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -34,7 +34,7 @@ THE SOFTWARE. */ #include #include -#include "forward.h" // csubstr +#include "forward.h" // csview #include "ccommon.h" enum { @@ -82,7 +82,7 @@ typedef struct { typedef struct { const cregex* re; const char* input; - csubstr match[CREG_MAX_CAPTURES]; + csview match[CREG_MAX_CAPTURES]; } cregex_iter; #define c_formatch(it, Re, Input) \ @@ -115,11 +115,11 @@ int cregex_captures(const cregex* re); /* return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */ #define cregex_find(...) c_MACRO_OVERLOAD(cregex_find, __VA_ARGS__) #define cregex_find_3(re, input, match) cregex_find_4(re, input, match, CREG_DEFAULT) -int cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags); +int cregex_find_4(const cregex* re, const char* input, csview match[], int mflags); -/* find with csubstr as input. */ -STC_INLINE int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]) { - csubstr *mp = NULL; +/* find with csview as input. */ +STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) { + csview *mp = NULL; if (match) { match[0] = input; mp = match; } return cregex_find(re, input.str, mp, CREG_STARTEND); } @@ -129,27 +129,27 @@ STC_INLINE int cregex_find_ss(const cregex* re, csubstr input, csubstr match[]) #define cregex_find_pattern_3(pattern, input, match) \ cregex_find_pattern_4(pattern, input, match, CREG_DEFAULT) int cregex_find_pattern_4(const char* pattern, const char* input, - csubstr match[], int cmflags); + csview match[], int cmflags); STC_INLINE bool cregex_is_match(const cregex* re, const char* input) { return cregex_find_4(re, input, NULL, CREG_DEFAULT) == CREG_OK; } -/* replace csubstr input with replace using regular expression pattern */ -#define cregex_replace_ss(...) c_MACRO_OVERLOAD(cregex_replace_ss, __VA_ARGS__) -#define cregex_replace_ss_3(pattern, input, replace) \ - cregex_replace_ss_4(pattern, input, replace, INT32_MAX) -#define cregex_replace_ss_4(pattern, input, replace, count) \ - cregex_replace_ss_6(pattern, input, replace, count, NULL, CREG_DEFAULT) -cstr cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, - bool (*transform)(int group, csubstr match, cstr* result), int rflags); +/* replace csview input with replace using regular expression pattern */ +#define cregex_replace_sv(...) c_MACRO_OVERLOAD(cregex_replace_sv, __VA_ARGS__) +#define cregex_replace_sv_3(pattern, input, replace) \ + cregex_replace_sv_4(pattern, input, replace, INT32_MAX) +#define cregex_replace_sv_4(pattern, input, replace, count) \ + cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT) +cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, + bool (*transform)(int group, csview match, cstr* result), int rflags); /* replace input with replace using regular expression */ #define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__) #define cregex_replace_3(re, input, replace) cregex_replace_4(re, input, replace, INT32_MAX) STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char* replace, int count) { - csubstr ss = {input, c_strlen(input)}; - return cregex_replace_ss_4(re, ss, replace, count); + csview sv = {input, c_strlen(input)}; + return cregex_replace_sv_4(re, sv, replace, count); } /* replace + compile RE pattern, and extra arguments */ @@ -159,7 +159,7 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char #define cregex_replace_pattern_4(pattern, input, replace, count) \ cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*transform)(int group, csubstr match, cstr* result), int crflags); + bool (*transform)(int group, csview match, cstr* result), int crflags); /* destroy regex */ void cregex_drop(cregex* re); diff --git a/include/stc/cstr.h b/include/stc/cstr.h index ce398628..7f4bad97 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -75,7 +75,7 @@ STC_API char* cstr_reserve(cstr* self, intptr_t cap); STC_API void cstr_shrink_to_fit(cstr* self); STC_API char* cstr_resize(cstr* self, intptr_t size, char value); STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); -STC_API intptr_t cstr_find_ss(const cstr* self, csubstr search); +STC_API intptr_t cstr_find_sv(const cstr* self, csview search); STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_uninit(cstr *self, intptr_t len); @@ -85,7 +85,7 @@ STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); STC_API cstr cstr_from_fmt(const char* fmt, ...); STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...); -STC_API cstr cstr_replace_ss(csubstr sv, csubstr search, csubstr repl, int32_t count); +STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); STC_API uint64_t cstr_hash(const cstr *self); STC_INLINE cstr_buf cstr_buffer(cstr* s) { @@ -93,12 +93,12 @@ STC_INLINE cstr_buf cstr_buffer(cstr* s) { ? c_LITERAL(cstr_buf){s->lon.data, cstr_l_size(s), cstr_l_cap(s)} : c_LITERAL(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap}; } -STC_INLINE csview cstr_sv(const cstr* s) { - return cstr_is_long(s) ? c_sv_2(s->lon.data, cstr_l_size(s)) - : c_sv_2(s->sml.data, cstr_s_size(s)); +STC_INLINE crawstr cstr_rs(const cstr* s) { + return cstr_is_long(s) ? c_rs_2(s->lon.data, cstr_l_size(s)) + : c_rs_2(s->sml.data, cstr_s_size(s)); } -STC_INLINE csubstr cstr_ss(const cstr* s) - { csview sv = cstr_sv(s); return c_ss_2(sv.str, sv.size); } +STC_INLINE csview cstr_sv(const cstr* s) + { crawstr rs = cstr_rs(s); return c_sv_2(rs.str, rs.size); } STC_INLINE cstr cstr_init(void) { return cstr_null; } @@ -112,12 +112,12 @@ STC_INLINE cstr cstr_from_n(const char* str, const intptr_t len) { STC_INLINE cstr cstr_from(const char* str) { return cstr_from_n(str, c_strlen(str)); } -STC_INLINE cstr cstr_from_ss(csubstr sv) - { return cstr_from_n(sv.str, sv.size); } - STC_INLINE cstr cstr_from_sv(csview sv) { return cstr_from_n(sv.str, sv.size); } +STC_INLINE cstr cstr_from_rs(crawstr rs) + { return cstr_from_n(rs.str, rs.size); } + STC_INLINE cstr cstr_with_size(const intptr_t size, const char value) { cstr s; c_memset(_cstr_init(&s, size, size), value, size); @@ -144,8 +144,8 @@ STC_INLINE cstr cstr_move(cstr* self) { } STC_INLINE cstr cstr_clone(cstr s) { - csview sv = cstr_sv(&s); - return cstr_from_n(sv.str, sv.size); + crawstr rs = cstr_rs(&s); + return cstr_from_n(rs.str, rs.size); } STC_INLINE void cstr_drop(cstr* self) { @@ -175,9 +175,9 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self) // utf8 methods defined in/depending on src/utf8code.c: -extern cstr cstr_casefold_ss(csubstr sv); -extern cstr cstr_tolower_ss(csubstr sv); -extern cstr cstr_toupper_ss(csubstr sv); +extern cstr cstr_casefold_sv(csview sv); +extern cstr cstr_tolower_sv(csview sv); +extern cstr cstr_toupper_sv(csview sv); extern cstr cstr_tolower(const char* str); extern cstr cstr_toupper(const char* str); extern void cstr_lowercase(cstr* self); @@ -198,9 +198,9 @@ STC_INLINE intptr_t cstr_u8_to_pos(const cstr* self, intptr_t u8idx) STC_INLINE const char* cstr_u8_at(const cstr* self, intptr_t u8idx) { return utf8_at(cstr_str(self), u8idx); } -STC_INLINE csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx) { +STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) { const char* str = cstr_str(self); - csubstr sv; + csview sv; sv.str = utf8_at(str, u8idx); sv.size = utf8_chr_size(sv.str); return sv; @@ -209,9 +209,9 @@ STC_INLINE csubstr cstr_u8_chr(const cstr* self, intptr_t u8idx) { // utf8 iterator STC_INLINE cstr_iter cstr_begin(const cstr* self) { - csview sv = cstr_sv(self); - if (!sv.size) return c_LITERAL(cstr_iter){.ref = NULL}; - return c_LITERAL(cstr_iter){.u8 = {{sv.str, utf8_chr_size(sv.str)}}}; + crawstr rs = cstr_rs(self); + if (!rs.size) return c_LITERAL(cstr_iter){.ref = NULL}; + return c_LITERAL(cstr_iter){.u8 = {{rs.str, utf8_chr_size(rs.str)}}}; } STC_INLINE cstr_iter cstr_end(const cstr* self) { (void)self; return c_LITERAL(cstr_iter){NULL}; @@ -241,7 +241,7 @@ STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2) { return utf8_icmp(cstr_str(s1), cstr_str(s2)); } STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { - csview x = cstr_sv(s1), y = cstr_sv(s2); + crawstr x = cstr_rs(s1), y = cstr_rs(s2); return x.size == y.size && !c_memcmp(x.str, y.str, x.size); } @@ -249,7 +249,7 @@ STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { STC_INLINE bool cstr_equals(const cstr* self, const char* str) { return !strcmp(cstr_str(self), str); } -STC_INLINE bool cstr_equals_ss(const cstr* self, csubstr sv) +STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv) { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); } STC_INLINE bool cstr_equals_s(const cstr* self, cstr s) @@ -271,14 +271,14 @@ STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search) STC_INLINE bool cstr_contains(const cstr* self, const char* search) { return strstr((char*)cstr_str(self), search) != NULL; } -STC_INLINE bool cstr_contains_ss(const cstr* self, csubstr search) - { return cstr_find_ss(self, search) != c_NPOS; } +STC_INLINE bool cstr_contains_sv(const cstr* self, csview search) + { return cstr_find_sv(self, search) != c_NPOS; } STC_INLINE bool cstr_contains_s(const cstr* self, cstr search) { return strstr((char*)cstr_str(self), cstr_str(&search)) != NULL; } -STC_INLINE bool cstr_starts_with_ss(const cstr* self, csubstr sub) { +STC_INLINE bool cstr_starts_with_sv(const cstr* self, csview sub) { if (sub.size > cstr_size(self)) return false; return !c_memcmp(cstr_str(self), sub.str, sub.size); } @@ -290,43 +290,43 @@ STC_INLINE bool cstr_starts_with(const cstr* self, const char* sub) { } STC_INLINE bool cstr_starts_with_s(const cstr* self, cstr sub) - { return cstr_starts_with_ss(self, cstr_ss(&sub)); } + { return cstr_starts_with_sv(self, cstr_sv(&sub)); } STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) { - csubstr sv = cstr_ss(self); + csview sv = cstr_sv(self); intptr_t len = c_strlen(sub); - return len <= sv.size && !utf8_icmp_ss(sv, c_ss(sub, len)); + return len <= sv.size && !utf8_icmp_sv(sv, c_sv(sub, len)); } -STC_INLINE bool cstr_ends_with_ss(const cstr* self, csubstr sub) { - csview sv = cstr_sv(self); - if (sub.size > sv.size) return false; - return !c_memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); +STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) { + crawstr rs = cstr_rs(self); + if (sub.size > rs.size) return false; + return !c_memcmp(rs.str + rs.size - sub.size, sub.str, sub.size); } STC_INLINE bool cstr_ends_with_s(const cstr* self, cstr sub) - { return cstr_ends_with_ss(self, cstr_ss(&sub)); } + { return cstr_ends_with_sv(self, cstr_sv(&sub)); } STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub) - { return cstr_ends_with_ss(self, c_ss(sub, c_strlen(sub))); } + { return cstr_ends_with_sv(self, c_sv(sub, c_strlen(sub))); } STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) { - csview sv = cstr_sv(self); + crawstr rs = cstr_rs(self); intptr_t n = c_strlen(sub); - return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub); + return n <= rs.size && !utf8_icmp(rs.str + rs.size - n, sub); } STC_INLINE char* cstr_assign(cstr* self, const char* str) { return cstr_assign_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_assign_ss(cstr* self, csubstr sv) +STC_INLINE char* cstr_assign_sv(cstr* self, csview sv) { return cstr_assign_n(self, sv.str, sv.size); } STC_INLINE char* cstr_copy(cstr* self, cstr s) { - csview sv = cstr_sv(&s); - return cstr_assign_n(self, sv.str, sv.size); + crawstr rs = cstr_rs(&s); + return cstr_assign_n(self, rs.str, rs.size); } @@ -334,51 +334,51 @@ STC_INLINE char* cstr_push(cstr* self, const char* chr) { return cstr_append_n(self, chr, utf8_chr_size(chr)); } STC_INLINE void cstr_pop(cstr* self) { - csview sv = cstr_sv(self); - const char* s = sv.str + sv.size; + crawstr rs = cstr_rs(self); + const char* s = rs.str + rs.size; while ((*--s & 0xC0) == 0x80) ; - _cstr_set_size(self, (s - sv.str)); + _cstr_set_size(self, (s - rs.str)); } STC_INLINE char* cstr_append(cstr* self, const char* str) { return cstr_append_n(self, str, c_strlen(str)); } -STC_INLINE char* cstr_append_ss(cstr* self, csubstr sv) +STC_INLINE char* cstr_append_sv(cstr* self, csview sv) { return cstr_append_n(self, sv.str, sv.size); } STC_INLINE char* cstr_append_s(cstr* self, cstr s) - { return cstr_append_ss(self, cstr_ss(&s)); } + { return cstr_append_sv(self, cstr_sv(&s)); } #define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__) #define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, INT32_MAX) STC_INLINE void cstr_replace_4(cstr* self, const char* search, const char* repl, int32_t count) { - cstr_take(self, cstr_replace_ss(cstr_ss(self), c_ss(search, c_strlen(search)), - c_ss(repl, c_strlen(repl)), count)); + cstr_take(self, cstr_replace_sv(cstr_sv(self), c_sv(search, c_strlen(search)), + c_sv(repl, c_strlen(repl)), count)); } -STC_INLINE void cstr_replace_at_ss(cstr* self, intptr_t pos, intptr_t len, const csubstr repl) { +STC_INLINE void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl) { char* d = _cstr_internal_move(self, pos + len, pos + repl.size); c_memcpy(d + pos, repl.str, repl.size); } STC_INLINE void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl) - { cstr_replace_at_ss(self, pos, len, c_ss(repl, c_strlen(repl))); } + { cstr_replace_at_sv(self, pos, len, c_sv(repl, c_strlen(repl))); } STC_INLINE void cstr_replace_at_s(cstr* self, intptr_t pos, intptr_t len, cstr repl) - { cstr_replace_at_ss(self, pos, len, cstr_ss(&repl)); } + { cstr_replace_at_sv(self, pos, len, cstr_sv(&repl)); } -STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csubstr repl) - { cstr_replace_at_ss(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } +STC_INLINE void cstr_u8_replace_at(cstr* self, intptr_t bytepos, intptr_t u8len, csview repl) + { cstr_replace_at_sv(self, bytepos, utf8_pos(cstr_str(self) + bytepos, u8len), repl); } STC_INLINE void cstr_insert(cstr* self, intptr_t pos, const char* str) - { cstr_replace_at_ss(self, pos, 0, c_ss(str, c_strlen(str))); } + { cstr_replace_at_sv(self, pos, 0, c_sv(str, c_strlen(str))); } -STC_INLINE void cstr_insert_ss(cstr* self, intptr_t pos, csubstr sv) - { cstr_replace_at_ss(self, pos, 0, sv); } +STC_INLINE void cstr_insert_sv(cstr* self, intptr_t pos, csview sv) + { cstr_replace_at_sv(self, pos, 0, sv); } STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) - { cstr_replace_at_ss(self, pos, 0, cstr_ss(&s)); } + { cstr_replace_at_sv(self, pos, 0, cstr_sv(&s)); } STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } @@ -397,7 +397,7 @@ fn_tocase[] = {{tolower, utf8_casefold}, {tolower, utf8_tolower}, {toupper, utf8_toupper}}; -static cstr cstr_tocase(csubstr sv, int k) { +static cstr cstr_tocase(csview sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); const char *end = sv.str + sv.size; @@ -418,26 +418,26 @@ static cstr cstr_tocase(csubstr sv, int k) { return out; } -cstr cstr_casefold_ss(csubstr sv) +cstr cstr_casefold_sv(csview sv) { return cstr_tocase(sv, 0); } -cstr cstr_tolower_ss(csubstr sv) +cstr cstr_tolower_sv(csview sv) { return cstr_tocase(sv, 1); } -cstr cstr_toupper_ss(csubstr sv) +cstr cstr_toupper_sv(csview sv) { return cstr_tocase(sv, 2); } cstr cstr_tolower(const char* str) - { return cstr_tolower_ss(c_ss(str, c_strlen(str))); } + { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } cstr cstr_toupper(const char* str) - { return cstr_toupper_ss(c_ss(str, c_strlen(str))); } + { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } void cstr_lowercase(cstr* self) - { cstr_take(self, cstr_tolower_ss(cstr_ss(self))); } + { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } void cstr_uppercase(cstr* self) - { cstr_take(self, cstr_toupper_ss(cstr_ss(self))); } + { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } bool cstr_valid_utf8(const cstr* self) { return utf8_valid(cstr_str(self)); } @@ -449,14 +449,14 @@ bool cstr_valid_utf8(const cstr* self) #define CSTR_C_INCLUDED STC_DEF uint64_t cstr_hash(const cstr *self) { - csview sv = cstr_sv(self); - return cfasthash(sv.str, sv.size); + crawstr rs = cstr_rs(self); + return cfasthash(rs.str, rs.size); } -STC_DEF intptr_t cstr_find_ss(const cstr* self, csubstr search) { - csview sv = cstr_sv(self); - char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); - return res ? (res - sv.str) : c_NPOS; +STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) { + crawstr rs = cstr_rs(self); + char* res = cstrnstrn(rs.str, search.str, rs.size, search.size); + return res ? (res - rs.str) : c_NPOS; } STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) { @@ -530,10 +530,10 @@ STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) { } STC_DEF intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) { - csview sv = cstr_sv(self); - if (pos > sv.size) return c_NPOS; - const char* res = strstr((char*)sv.str + pos, search); - return res ? (res - sv.str) : c_NPOS; + crawstr rs = cstr_rs(self); + if (pos > rs.size) return c_NPOS; + const char* res = strstr((char*)rs.str + pos, search); + return res ? (res - rs.str) : c_NPOS; } STC_DEF char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) { @@ -583,7 +583,7 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { } } -STC_DEF cstr cstr_replace_ss(csubstr in, csubstr search, csubstr repl, int32_t count) { +STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) { cstr out = cstr_null; intptr_t from = 0; char* res; if (!count) count = INT32_MAX; diff --git a/include/stc/csubstr.h b/include/stc/csubstr.h deleted file mode 100644 index c7a43052..00000000 --- a/include/stc/csubstr.h +++ /dev/null @@ -1,211 +0,0 @@ -/* MIT License - * - * Copyright (c) 2023 Tyge Løvset - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#define i_header // external linkage by default. override with i_static. -#define _i_inc_utf8 -#include "utf8.h" - -#ifndef CSUBSTR_H_INCLUDED -#define CSUBSTR_H_INCLUDED - -#define csubstr_init() c_ss_1("") -#define csubstr_drop(p) c_default_drop(p) -#define csubstr_clone(ss) c_default_clone(ss) -#define csubstr_from_n(str, n) c_ss_2(str, n) - -STC_API csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos); -STC_API intptr_t csubstr_find_ss(csubstr ss, csubstr search); -STC_API uint64_t csubstr_hash(const csubstr *self); -STC_API csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2); -STC_API csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n); -STC_API csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start); - -STC_INLINE csubstr csubstr_from(const char* str) - { return c_LITERAL(csubstr){str, c_strlen(str)}; } -STC_INLINE void csubstr_clear(csubstr* self) { *self = csubstr_init(); } -STC_INLINE intptr_t csubstr_size(csubstr ss) { return ss.size; } -STC_INLINE bool csubstr_empty(csubstr ss) { return ss.size == 0; } - -STC_INLINE bool csubstr_equals_ss(csubstr ss1, csubstr ss2) - { return ss1.size == ss2.size && !c_memcmp(ss1.str, ss2.str, ss1.size); } - -STC_INLINE bool csubstr_equals(csubstr ss, const char* str) - { return csubstr_equals_ss(ss, c_ss_2(str, c_strlen(str))); } - -STC_INLINE intptr_t csubstr_find(csubstr ss, const char* str) - { return csubstr_find_ss(ss, c_ss_2(str, c_strlen(str))); } - -STC_INLINE bool csubstr_contains(csubstr ss, const char* str) - { return csubstr_find(ss, str) != c_NPOS; } - -STC_INLINE bool csubstr_starts_with(csubstr ss, const char* str) { - intptr_t n = c_strlen(str); - return n > ss.size ? false : !c_memcmp(ss.str, str, n); -} - -STC_INLINE bool csubstr_ends_with(csubstr ss, const char* str) { - intptr_t n = c_strlen(str); - return n > ss.size ? false : !c_memcmp(ss.str + ss.size - n, str, n); -} - -STC_INLINE csubstr csubstr_substr(csubstr ss, intptr_t pos, intptr_t n) { - if (pos + n > ss.size) n = ss.size - pos; - ss.str += pos, ss.size = n; - return ss; -} - -STC_INLINE csubstr csubstr_slice(csubstr ss, intptr_t p1, intptr_t p2) { - if (p2 > ss.size) p2 = ss.size; - ss.str += p1, ss.size = p2 > p1 ? p2 - p1 : 0; - return ss; -} - -/* utf8 iterator */ -STC_INLINE csubstr_iter csubstr_begin(const csubstr* self) { - if (!self->size) return c_LITERAL(csubstr_iter){NULL}; - return c_LITERAL(csubstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, - self->str + self->size}}; -} -STC_INLINE csubstr_iter csubstr_end(const csubstr* self) { - return c_LITERAL(csubstr_iter){.u8 = {{NULL}, self->str + self->size}}; -} -STC_INLINE void csubstr_next(csubstr_iter* it) { - it->ref += it->u8.chr.size; - it->u8.chr.size = utf8_chr_size(it->ref); - if (it->ref == it->u8.end) it->ref = NULL; -} - -/* utf8 */ -STC_INLINE intptr_t csubstr_u8_size(csubstr ss) - { return utf8_size_n(ss.str, ss.size); } - -STC_INLINE csubstr csubstr_u8_substr(csubstr ss, intptr_t bytepos, intptr_t u8len) { - ss.str += bytepos; - ss.size = utf8_pos(ss.str, u8len); - return ss; -} - -STC_INLINE bool csubstr_valid_utf8(csubstr ss) // depends on src/utf8code.c - { return utf8_valid_n(ss.str, ss.size); } - -#define c_fortoken_ss(it, inputss, sep) \ - for (struct { csubstr _inp, token, *ref; const char *_sep; intptr_t pos; } \ - it = {._inp=inputss, .token=it._inp, .ref=&it.token, ._sep=sep} \ - ; it.pos <= it._inp.size && (it.token = csubstr_token(it._inp, it._sep, &it.pos)).str ; ) - -#define c_fortoken(it, input, sep) \ - c_fortoken_ss(it, csubstr_from(input), sep) - -/* ---- Container helper functions ---- */ - -STC_INLINE int csubstr_cmp(const csubstr* x, const csubstr* y) { - intptr_t n = x->size < y->size ? x->size : y->size; - int c = c_memcmp(x->str, y->str, n); - return c ? c : (int)(x->size - y->size); -} - -STC_INLINE int csubstr_icmp(const csubstr* x, const csubstr* y) - { return utf8_icmp_ss(*x, *y); } - -STC_INLINE bool csubstr_eq(const csubstr* x, const csubstr* y) - { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } - -#endif // CSUBSTR_H_INCLUDED - -/* csubstr interaction with cstr: */ -#ifdef CSTR_H_INCLUDED - -STC_INLINE csubstr cstr_substr(const cstr* self, intptr_t pos, intptr_t n) - { return csubstr_substr(cstr_ss(self), pos, n); } - -STC_INLINE csubstr cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) - { return csubstr_slice(cstr_ss(self), p1, p2); } - -STC_INLINE csubstr cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n) - { return csubstr_substr_ex(cstr_ss(self), pos, n); } - -STC_INLINE csubstr cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) - { return csubstr_slice_ex(cstr_ss(self), p1, p2); } - -STC_INLINE csubstr cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) - { return csubstr_u8_substr(cstr_ss(self), bytepos, u8len); } -#endif - -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined i_implement || defined i_static -#ifndef CSUBSTR_C_INCLUDED -#define CSUBSTR_C_INCLUDED - -STC_DEF csubstr_iter csubstr_advance(csubstr_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (it.ref == it.u8.end) it.ref = NULL; - return it; -} - -STC_DEF intptr_t csubstr_find_ss(csubstr ss, csubstr search) { - char* res = cstrnstrn(ss.str, search.str, ss.size, search.size); - return res ? (res - ss.str) : c_NPOS; -} - -STC_DEF uint64_t csubstr_hash(const csubstr *self) - { return cfasthash(self->str, self->size); } - -STC_DEF csubstr csubstr_substr_ex(csubstr ss, intptr_t pos, intptr_t n) { - if (pos < 0) { - pos += ss.size; - if (pos < 0) pos = 0; - } - if (pos > ss.size) pos = ss.size; - if (pos + n > ss.size) n = ss.size - pos; - ss.str += pos, ss.size = n; - return ss; -} - -STC_DEF csubstr csubstr_slice_ex(csubstr ss, intptr_t p1, intptr_t p2) { - if (p1 < 0) { - p1 += ss.size; - if (p1 < 0) p1 = 0; - } - if (p2 < 0) p2 += ss.size; - if (p2 > ss.size) p2 = ss.size; - ss.str += p1, ss.size = (p2 > p1 ? p2 - p1 : 0); - return ss; -} - -STC_DEF csubstr csubstr_token(csubstr ss, const char* sep, intptr_t* start) { - intptr_t sep_size = c_strlen(sep); - csubstr slice = {ss.str + *start, ss.size - *start}; - const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); - csubstr tok = {slice.str, res ? (res - slice.str) : slice.size}; - *start += tok.size + sep_size; - return tok; -} -#endif // CSUBSTR_C_INCLUDED -#endif // i_implement -#undef i_static -#undef i_header -#undef i_implement -#undef i_import -#undef i_opt diff --git a/include/stc/csview.h b/include/stc/csview.h index 367258e4..2a051ddd 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,33 +20,39 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#define i_header // external linkage by default. override with i_static. #define _i_inc_utf8 #include "utf8.h" #ifndef CSVIEW_H_INCLUDED #define CSVIEW_H_INCLUDED -#define csview_init() c_sv("") +#define csview_init() c_sv_1("") #define csview_drop(p) c_default_drop(p) #define csview_clone(sv) c_default_clone(sv) +#define csview_from_n(str, n) c_sv_2(str, n) + +STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); +STC_API intptr_t csview_find_sv(csview sv, csview search); +STC_API uint64_t csview_hash(const csview *self); +STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); +STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); +STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); STC_INLINE csview csview_from(const char* str) - { return c_sv_2(str, c_strlen(str)); } + { return c_LITERAL(csview){str, c_strlen(str)}; } STC_INLINE void csview_clear(csview* self) { *self = csview_init(); } -STC_INLINE csubstr csview_ss(csview sv) { return c_ss_2(sv.str, sv.size); } - STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } -STC_INLINE bool csview_equals(csview sv, const char* str) { - intptr_t n = c_strlen(str); - return sv.size == n && !c_memcmp(sv.str, str, n); -} +STC_INLINE bool csview_equals_sv(csview sv1, csview sv2) + { return sv1.size == sv2.size && !c_memcmp(sv1.str, sv2.str, sv1.size); } -STC_INLINE intptr_t csview_find(csview sv, const char* search) { - char* res = cstrnstrn(sv.str, search, sv.size, c_strlen(search)); - return res ? (res - sv.str) : c_NPOS; -} +STC_INLINE bool csview_equals(csview sv, const char* str) + { return csview_equals_sv(sv, c_sv_2(str, c_strlen(str))); } + +STC_INLINE intptr_t csview_find(csview sv, const char* str) + { return csview_find_sv(sv, c_sv_2(str, c_strlen(str))); } STC_INLINE bool csview_contains(csview sv, const char* str) { return csview_find(sv, str) != c_NPOS; } @@ -61,40 +67,55 @@ STC_INLINE bool csview_ends_with(csview sv, const char* str) { return n > sv.size ? false : !c_memcmp(sv.str + sv.size - n, str, n); } +STC_INLINE csview csview_substr(csview sv, intptr_t pos, intptr_t n) { + if (pos + n > sv.size) n = sv.size - pos; + sv.str += pos, sv.size = n; + return sv; +} + +STC_INLINE csview csview_slice(csview sv, intptr_t p1, intptr_t p2) { + if (p2 > sv.size) p2 = sv.size; + sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; + return sv; +} + /* utf8 iterator */ STC_INLINE csview_iter csview_begin(const csview* self) { - if (!self->size) return c_LITERAL(csview_iter){.ref = NULL}; - return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}}; + if (!self->size) return c_LITERAL(csview_iter){NULL}; + return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)}, + self->str + self->size}}; } STC_INLINE csview_iter csview_end(const csview* self) { - (void)self; return c_LITERAL(csview_iter){.ref = NULL}; + return c_LITERAL(csview_iter){.u8 = {{NULL}, self->str + self->size}}; } STC_INLINE void csview_next(csview_iter* it) { it->ref += it->u8.chr.size; it->u8.chr.size = utf8_chr_size(it->ref); - if (!*it->ref) it->ref = NULL; -} -STC_INLINE csview_iter csview_advance(csview_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (!*it.ref) it.ref = NULL; - return it; + if (it->ref == it->u8.end) it->ref = NULL; } -/* utf8 size */ +/* utf8 */ STC_INLINE intptr_t csview_u8_size(csview sv) { return utf8_size_n(sv.str, sv.size); } -/* utf8 validation: depends on src/utf8code.c */ -STC_INLINE bool csview_valid_utf8(csview sv) +STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) { + sv.str += bytepos; + sv.size = utf8_pos(sv.str, u8len); + return sv; +} + +STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c { return utf8_valid_n(sv.str, sv.size); } -/* utf8 ignore case cmp: depends on src/utf8code.c */ -STC_INLINE int csview_icmp(const csview* x, const csview* y) - { return utf8_icmp_ss(c_ss_2(x->str, x->size), c_ss_2(y->str, y->size)); } +#define c_fortoken_sv(it, inputsv, sep) \ + for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \ + it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \ + ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).str ; ) +#define c_fortoken(it, input, sep) \ + c_fortoken_sv(it, csview_from(input), sep) + +/* ---- Container helper functions ---- */ STC_INLINE int csview_cmp(const csview* x, const csview* y) { intptr_t n = x->size < y->size ? x->size : y->size; @@ -102,13 +123,87 @@ STC_INLINE int csview_cmp(const csview* x, const csview* y) { return c ? c : (int)(x->size - y->size); } +STC_INLINE int csview_icmp(const csview* x, const csview* y) + { return utf8_icmp_sv(*x, *y); } + STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } -STC_INLINE uint64_t csview_hash(const csview *self) +#endif // CSVIEW_H_INCLUDED + +/* csview interaction with cstr: */ +#ifdef CSTR_H_INCLUDED + +STC_INLINE csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n) + { return csview_substr(cstr_sv(self), pos, n); } + +STC_INLINE csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2) + { return csview_slice(cstr_sv(self), p1, p2); } + +STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n) + { return csview_substr_ex(cstr_sv(self), pos, n); } + +STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) + { return csview_slice_ex(cstr_sv(self), p1, p2); } + +STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) + { return csview_u8_substr(cstr_sv(self), bytepos, u8len); } +#endif + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined i_implement || defined i_static +#ifndef CSVIEW_C_INCLUDED +#define CSVIEW_C_INCLUDED + +STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) { + int inc = -1; + if (pos > 0) pos = -pos, inc = 1; + while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; + it.u8.chr.size = utf8_chr_size(it.ref); + if (it.ref == it.u8.end) it.ref = NULL; + return it; +} + +STC_DEF intptr_t csview_find_sv(csview sv, csview search) { + char* res = cstrnstrn(sv.str, search.str, sv.size, search.size); + return res ? (res - sv.str) : c_NPOS; +} + +STC_DEF uint64_t csview_hash(const csview *self) { return cfasthash(self->str, self->size); } -#endif // CSVIEW_H_INCLUDED +STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) { + if (pos < 0) { + pos += sv.size; + if (pos < 0) pos = 0; + } + if (pos > sv.size) pos = sv.size; + if (pos + n > sv.size) n = sv.size - pos; + sv.str += pos, sv.size = n; + return sv; +} + +STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { + if (p1 < 0) { + p1 += sv.size; + if (p1 < 0) p1 = 0; + } + if (p2 < 0) p2 += sv.size; + if (p2 > sv.size) p2 = sv.size; + sv.str += p1, sv.size = (p2 > p1 ? p2 - p1 : 0); + return sv; +} + +STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { + intptr_t sep_size = c_strlen(sep); + csview slice = {sv.str + *start, sv.size - *start}; + const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size); + csview tok = {slice.str, res ? (res - slice.str) : slice.size}; + *start += tok.size + sep_size; + return tok; +} +#endif // CSVIEW_C_INCLUDED +#endif // i_implement #undef i_static #undef i_header #undef i_implement diff --git a/include/stc/forward.h b/include/stc/forward.h index 5c9c4f4d..839be012 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -39,21 +39,8 @@ #define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL) #define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL) -// csubstr : non-null terminated string view -typedef const char csubstr_value; -typedef struct csubstr { - csubstr_value* str; - intptr_t size; -} csubstr; - -typedef union { - csubstr_value* ref; - struct { csubstr chr; csubstr_value* end; } u8; -} csubstr_iter; - - -// csview : null-terminated string view -typedef csubstr_value csview_value; +// csview : non-null terminated string view +typedef const char csview_value; typedef struct csview { csview_value* str; intptr_t size; @@ -61,10 +48,23 @@ typedef struct csview { typedef union { csview_value* ref; - struct { csubstr chr; } u8; + struct { csview chr; csview_value* end; } u8; } csview_iter; +// crawstr : null-terminated string view +typedef csview_value crawstr_value; +typedef struct crawstr { + crawstr_value* str; + intptr_t size; +} crawstr; + +typedef union { + crawstr_value* ref; + struct { csview chr; } u8; +} crawstr_iter; + + // cstr : null-terminated string (short string optimized - sso) typedef char cstr_value; typedef struct { cstr_value* data; intptr_t size, cap; } cstr_buf; @@ -75,7 +75,7 @@ typedef union cstr { typedef union { cstr_value* ref; - struct { csubstr chr; } u8; + struct { csview chr; } u8; } cstr_iter; diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 47225ec8..65dee203 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -114,10 +114,10 @@ #endif #elif defined i_key_ssv #define i_keyclass cstr - #define i_rawclass csubstr - #define i_keyfrom cstr_from_ss - #define i_keyto cstr_ss - #define i_eq csubstr_eq + #define i_rawclass csview + #define i_keyfrom cstr_from_sv + #define i_keyto cstr_sv + #define i_eq csview_eq #ifndef i_tag #define i_tag ssv #endif @@ -232,9 +232,9 @@ #define i_valraw const char* #elif defined i_val_ssv #define i_valclass cstr - #define i_valraw csubstr - #define i_valfrom cstr_from_ss - #define i_valto cstr_ss + #define i_valraw csview + #define i_valfrom cstr_from_sv + #define i_valto cstr_sv #elif defined i_valboxed #define i_valclass i_valboxed #define i_valraw c_PASTE(i_valboxed, _raw) diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 7d2adee0..6d12856f 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -48,7 +48,7 @@ extern uint32_t utf8_toupper(uint32_t c); extern bool utf8_iscased(uint32_t c); extern bool utf8_isword(uint32_t c); extern bool utf8_valid_n(const char* s, intptr_t nbytes); -extern int utf8_icmp_ss(csubstr s1, csubstr s2); +extern int utf8_icmp_sv(csview s1, csview s2); extern int utf8_encode(char *out, uint32_t c); extern uint32_t utf8_peek_off(const char *s, int offset); @@ -92,7 +92,7 @@ STC_INLINE uint32_t utf8_peek(const char* s) { /* case-insensitive utf8 string comparison */ STC_INLINE int utf8_icmp(const char* s1, const char* s2) { - return utf8_icmp_ss(c_ss(s1, INTPTR_MAX), c_ss(s2, INTPTR_MAX)); + return utf8_icmp_sv(c_sv(s1, INTPTR_MAX), c_sv(s2, INTPTR_MAX)); } STC_INLINE bool utf8_valid(const char* s) { diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp index 9173d4b6..a5dfd901 100644 --- a/misc/benchmarks/various/string_bench_STC.cpp +++ b/misc/benchmarks/various/string_bench_STC.cpp @@ -7,16 +7,16 @@ #define i_implement #include // string #define i_implement -#include // string_view +#include // string_view #include #define i_key_str #include // vec of cstr with const char* lookup -#define i_type cvec_ss // override default type name (cvec_csubstr) -#define i_key csubstr -#define i_cmp csubstr_cmp -#include // cvec_vs: vec of csubstr +#define i_type cvec_sv // override default type name (cvec_csview) +#define i_key csview +#define i_cmp csview_cmp +#include // cvec_vs: vec of csview #define i_key_str #define i_val size_t @@ -24,7 +24,7 @@ #define i_key_ssv #define i_val size_t -#include // sorted map of cstr, csubstr lookup +#include // sorted map of cstr, csview lookup #define i_key_str #define i_val size_t @@ -32,7 +32,7 @@ #define i_key_ssv #define i_val size_t -#include // unordered map of cstr, csubstr lookup +#include // unordered map of cstr, csview lookup cvec_str read_file(const char* name) @@ -67,7 +67,7 @@ private: std::chrono::high_resolution_clock::time_point begin; }; -void initShortStringVec(cvec_str* vs, cvec_ss* vsv) +void initShortStringVec(cvec_str* vs, cvec_sv* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -101,14 +101,14 @@ void initShortStringVec(cvec_str* vs, cvec_ss* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_ss(i.ref)); + cvec_sv_push_back(vsv, cstr_sv(i.ref)); num += cstr_size(i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; std::cout << "avg str len: " << num / (float)cvec_sv_size(vsv) << std::endl; } -void initLongStringVec(cvec_str* vs, cvec_ss* vsv) +void initLongStringVec(cvec_str* vs, cvec_sv* vsv) { cvec_str_drop(vs); cvec_sv_clear(vsv); @@ -147,7 +147,7 @@ void initLongStringVec(cvec_str* vs, cvec_ss* vsv) size_t num = 0; c_foreach (i, cvec_str, *vs) { - cvec_sv_push_back(vsv, cstr_ss(i.ref)); + cvec_sv_push_back(vsv, cstr_sv(i.ref)); num += cstr_size(i.ref); } std::cout << "num strings: " << cvec_sv_size(vsv) << std::endl; @@ -175,7 +175,7 @@ void initMaps(const cvec_str* vs, csmap_str* mapTrans, csmap_ssv* mapSview, void benchmark( const cvec_str* vec_string, - const cvec_ss* vec_stringview, + const cvec_sv* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -187,7 +187,7 @@ const size_t MAX_LOOP = 2000; int main(void) { c_auto (cvec_str, vec_string) - c_auto (cvec_ss, vec_stringview) + c_auto (cvec_sv, vec_stringview) c_auto (csmap_str, mapTrans) c_auto (csmap_ssv, mapSview) c_auto (cmap_str, unordmapTrans) @@ -229,7 +229,7 @@ int main(void) void benchmark( const cvec_str* vec_string, - const cvec_ss* vec_stringview, + const cvec_sv* vec_stringview, const csmap_str* mapTrans, const csmap_ssv* mapSview, const cmap_str* unordmapTrans, @@ -258,7 +258,7 @@ void benchmark( stopwatch.start("Trans Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_ss, *vec_stringview) + c_foreach (j, cvec_sv, *vec_stringview) { const csmap_ssv_value* v = csmap_ssv_get(mapSview, *j.ref); if (v) @@ -286,7 +286,7 @@ void benchmark( stopwatch.start("Trans Unord Map with string_view"); for (size_t i = 0; i < MAX_LOOP; ++i) { - c_foreach (j, cvec_ss, *vec_stringview) + c_foreach (j, cvec_sv, *vec_stringview) { const cmap_ssv_value* v = cmap_ssv_get(unordmapSview, *j.ref); if (v) diff --git a/misc/examples/algorithms/forfilter.c b/misc/examples/algorithms/forfilter.c index d058660d..c1426045 100644 --- a/misc/examples/algorithms/forfilter.c +++ b/misc/examples/algorithms/forfilter.c @@ -2,7 +2,7 @@ #define i_import #include #define i_implement -#include +#include #include #define i_type IVec @@ -82,7 +82,7 @@ fn main() { } */ #define i_type SVec -#define i_keyclass csubstr +#define i_keyclass csview #include void demo3(void) @@ -94,11 +94,11 @@ void demo3(void) SVec words_containing_i = {0}; c_forfilter (w, SVec, words, - csubstr_contains(*w.ref, "i")) + csview_contains(*w.ref, "i")) SVec_push(&words_containing_i, *w.ref); c_foreach (w, SVec, words_containing_i) - printf(" %.*s", c_SS(*w.ref)); + printf(" %.*s", c_SV(*w.ref)); puts(""); c_drop(SVec, &words, &words_containing_i); @@ -107,10 +107,10 @@ void demo3(void) void demo4(void) { // Keep only uppercase letters and convert them to lowercase: - csubstr s = c_ss("ab123cReAghNGnΩoEp"); // Ω = multi-byte + csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte cstr out = {0}; - c_forfilter (i, csubstr, s, utf8_isupper(utf8_peek(i.ref))) { + c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) { char chr[4]; utf8_encode(chr, utf8_tolower(utf8_peek(i.ref))); cstr_push(&out, chr); diff --git a/misc/examples/regularexpressions/regex2.c b/misc/examples/regularexpressions/regex2.c index 85890070..a798b1a1 100644 --- a/misc/examples/regularexpressions/regex2.c +++ b/misc/examples/regularexpressions/regex2.c @@ -27,7 +27,7 @@ int main(void) c_formatch (j, &re, s[i].input) { c_forrange (k, cregex_captures(&re) + 1) - printf(" submatch %lld: %.*s\n", k, c_SS(j.match[k])); + printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); } } cregex_drop(&re); diff --git a/misc/examples/regularexpressions/regex_match.c b/misc/examples/regularexpressions/regex_match.c index 6eaea781..11426d2d 100644 --- a/misc/examples/regularexpressions/regex_match.c +++ b/misc/examples/regularexpressions/regex_match.c @@ -1,7 +1,7 @@ #define i_import #include #define i_implement -#include +#include #define i_key float #include @@ -28,7 +28,7 @@ int main(void) printf(" %g\n", (double)*i.ref); // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_ss(&re, csubstr_from(str), " $0,", 0, NULL, CREG_STRIP); + cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); printf("\n%s\n", cstr_str(&nums)); cstr_drop(&nums); diff --git a/misc/examples/regularexpressions/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c index f5fd8691..f1ea2711 100644 --- a/misc/examples/regularexpressions/regex_replace.c +++ b/misc/examples/regularexpressions/regex_replace.c @@ -1,8 +1,8 @@ #define i_import #include -#include +#include -bool add_10_years(int i, csubstr match, cstr* out) { +bool add_10_years(int i, csview match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -47,7 +47,7 @@ int main(void) printf("euros: %s\n", cstr_str(&str)); /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); printf("strip: %s\n", cstr_str(&str)); /* Wrap all words in ${} */ diff --git a/misc/examples/strings/cstr_match.c b/misc/examples/strings/cstr_match.c index 3c41bd43..80013019 100644 --- a/misc/examples/strings/cstr_match.c +++ b/misc/examples/strings/cstr_match.c @@ -1,6 +1,6 @@ #define i_implement #include -#include +#include #include int main(void) @@ -16,11 +16,11 @@ int main(void) printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); cstr s1 = cstr_lit("hell😀 w😀rl🐨"); - csubstr ch1 = cstr_u8_chr(&s1, 7); - csubstr ch2 = cstr_u8_chr(&s1, 10); + csview ch1 = cstr_u8_chr(&s1, 7); + csview ch2 = cstr_u8_chr(&s1, 10); printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); - printf("ch1: %.*s\n", c_SS(ch1)); - printf("ch2: %.*s\n", c_SS(ch2)); + printf("ch1: %.*s\n", c_SV(ch1)); + printf("ch2: %.*s\n", c_SV(ch2)); c_drop(cstr, &ss, &s1); } diff --git a/misc/examples/strings/replace.c b/misc/examples/strings/replace.c index 2411f1a7..59a56bf7 100644 --- a/misc/examples/strings/replace.c +++ b/misc/examples/strings/replace.c @@ -20,13 +20,13 @@ int main(void) cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) printf("(1) %s\n", cstr_str(&s)); - cstr_replace_at_ss(&s, 19, 6, c_ss(s3+7, 6)); // "this is an example phrase." (2) + cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) printf("(2) %s\n", cstr_str(&s)); cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) printf("(3) %s\n", cstr_str(&s)); - cstr_replace_at_ss(&s, 8, 6, c_ss("a shorty", 7)); // "this is a short phrase." (4) + cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) printf("(4) %s\n", cstr_str(&s)); cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) diff --git a/misc/examples/strings/splitstr.c b/misc/examples/strings/splitstr.c index 6fa76d34..ef7ed174 100644 --- a/misc/examples/strings/splitstr.c +++ b/misc/examples/strings/splitstr.c @@ -2,20 +2,20 @@ #define i_import // cstr + utf8 functions #include #define i_implement -#include +#include int main(void) { - puts("Split with c_fortoken (csubstr):"); + puts("Split with c_fortoken (csview):"); c_fortoken (i, "Hello World C99!", " ") - printf("'%.*s'\n", c_SS(i.token)); + printf("'%.*s'\n", c_SV(i.token)); puts("\nSplit with c_formatch (regex):"); cregex re = cregex_from("[^ ]+"); c_formatch (i, &re, " Hello World C99! ") - printf("'%.*s'\n", c_SS(i.match[0])); + printf("'%.*s'\n", c_SV(i.match[0])); cregex_drop(&re); } diff --git a/misc/examples/strings/sso_substr.c b/misc/examples/strings/sso_substr.c index 2262e349..70d34440 100644 --- a/misc/examples/strings/sso_substr.c +++ b/misc/examples/strings/sso_substr.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { cstr str = cstr_from("We think in generalities, but we live in details."); - csubstr sv1 = cstr_substr_ex(&str, 3, 5); // "think" + csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" intptr_t pos = cstr_find(&str, "live"); // position of "live" - csubstr sv2 = cstr_substr_ex(&str, pos, 4); // "live" - csubstr sv3 = cstr_slice_ex(&str, -8, -1); // "details" - printf("%.*s, %.*s, %.*s\n", c_SS(sv1), c_SS(sv2), c_SS(sv3)); + csview sv2 = cstr_substr_ex(&str, pos, 4); // "live" + csview sv3 = cstr_slice_ex(&str, -8, -1); // "details" + printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); cstr_assign(&str, "apples are green or red"); - cstr s2 = cstr_from_ss(cstr_substr_ex(&str, -3, 3)); // "red" - cstr s3 = cstr_from_ss(cstr_substr_ex(&str, 0, 6)); // "apples" + cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red" + cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples" printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), cstr_is_long(&str), cstr_is_long(&s2)); c_drop (cstr, &str, &s2, &s3); diff --git a/misc/examples/strings/sview_split.c b/misc/examples/strings/sview_split.c index 6abbf5e7..ac275da0 100644 --- a/misc/examples/strings/sview_split.c +++ b/misc/examples/strings/sview_split.c @@ -1,20 +1,20 @@ #define i_implement #include #define i_implement -#include +#include int main(void) { // No memory allocations or string length calculations! - const csubstr date = c_ss("2021/03/12"); + const csview date = c_sv("2021/03/12"); intptr_t pos = 0; - const csubstr year = csubstr_token(date, "/", &pos); - const csubstr month = csubstr_token(date, "/", &pos); - const csubstr day = csubstr_token(date, "/", &pos); + const csview year = csview_token(date, "/", &pos); + const csview month = csview_token(date, "/", &pos); + const csview day = csview_token(date, "/", &pos); - printf("%.*s, %.*s, %.*s\n", c_SS(year), c_SS(month), c_SS(day)); + printf("%.*s, %.*s, %.*s\n", c_SV(year), c_SV(month), c_SV(day)); - cstr y = cstr_from_ss(year), m = cstr_from_ss(month), d = cstr_from_ss(day); + cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); c_drop(cstr, &y, &m, &d); } diff --git a/misc/examples/strings/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c index 03a0442f..1d54486f 100644 --- a/misc/examples/strings/utf8replace_c.c +++ b/misc/examples/strings/utf8replace_c.c @@ -10,12 +10,12 @@ int main(void) cstr_u8_replace_at(&hello, cstr_u8_to_pos(&hello, 7), 1, - c_ss("🐨") + c_sv("🐨") ); printf("%s\n", cstr_str(&hello)); c_foreach (c, cstr, hello) - printf("%.*s,", c_SS(c.u8.chr)); + printf("%.*s,", c_SV(c.u8.chr)); cstr str = cstr_lit("scooby, dooby doo"); cstr_replace(&str, "oo", "00"); diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index 7cd03930..4e192de6 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -1,6 +1,6 @@ #define i_import #include -#include +#include #include #include "ctest.h" @@ -14,7 +14,7 @@ CTEST(cregex, compile_match_char) cregex re = cregex_from("äsdf"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_FULLMATCH), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); // ä is two bytes wide @@ -32,7 +32,7 @@ CTEST(cregex, compile_match_anchors) cregex re = cregex_from(inp="^äs.f$"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="äsdf", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -50,7 +50,7 @@ CTEST(cregex, compile_match_quantifiers1) re = cregex_from("ä+"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="ääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 4); @@ -70,7 +70,7 @@ CTEST(cregex, compile_match_quantifiers2) re = cregex_from("bä*"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, inp="bääb", &match), CREG_OK); ASSERT_EQ(M_START(match), 0); ASSERT_EQ(M_END(match), 5); @@ -90,7 +90,7 @@ CTEST(cregex, compile_match_escaped_chars) cregex re = cregex_from("\\n\\r\\t\\{"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, "\n\r\t{", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "\n\r\t", &match), CREG_NOMATCH); @@ -108,7 +108,7 @@ CTEST(cregex, compile_match_class_simple) re3 = cregex_from("\\D"); ASSERT_EQ(re3.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re1, " " , &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\r", &match), CREG_OK); ASSERT_EQ(cregex_find(&re1, "\n", &match), CREG_OK); @@ -129,7 +129,7 @@ CTEST(cregex, compile_match_or) re = cregex_from("as|df"); ASSERT_EQ(re.error, 0); - csubstr match[4]; + csview match[4]; ASSERT_EQ(cregex_find(&re, "as", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "df", match), CREG_OK); @@ -146,7 +146,7 @@ CTEST(cregex, compile_match_class_complex_0) cregex re = cregex_from("[asdf]"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "s", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "d", &match), CREG_OK); @@ -160,7 +160,7 @@ CTEST(cregex, compile_match_class_complex_1) cregex re = cregex_from("[a-zä0-9öA-Z]"); ASSERT_EQ(re.error, 0); - csubstr match; + csview match; ASSERT_EQ(cregex_find(&re, "a", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "5", &match), CREG_OK); ASSERT_EQ(cregex_find(&re, "A", &match), CREG_OK); @@ -175,7 +175,7 @@ CTEST(cregex, compile_match_cap) cregex re = cregex_from("(abc)d"); ASSERT_EQ(re.error, 0); - csubstr match[4]; + csview match[4]; ASSERT_EQ(cregex_find(&re, "abcd", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "llljabcdkk", match), CREG_OK); ASSERT_EQ(cregex_find(&re, "abc", match), CREG_NOMATCH); @@ -189,7 +189,7 @@ CTEST(cregex, search_all) c_auto (cregex, re) { re = cregex_from("ab"); - csubstr m = {0}; + csview m = {0}; int res; ASSERT_EQ(re.error, CREG_OK); inp="ab,ab,ab"; @@ -220,9 +220,9 @@ CTEST(cregex, captures_cap) re = cregex_from("(ab)((cd)+)"); ASSERT_EQ(cregex_captures(&re), 3); - csubstr cap[5]; + csview cap[5]; ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap), CREG_OK); - ASSERT_TRUE(csubstr_equals(cap[0], "abcdcd")); + ASSERT_TRUE(csview_equals(cap[0], "abcdcd")); ASSERT_EQ(M_END(cap[0]), 8); ASSERT_EQ(M_START(cap[1]), 2); @@ -235,7 +235,7 @@ CTEST(cregex, captures_cap) } } -static bool add_10_years(int i, csubstr match, cstr* out) { +static bool add_10_years(int i, csview match, cstr* out) { if (i == 1) { // group 1 matches year int year; sscanf(match.str, "%4d", &year); // scan 4 chars only @@ -280,7 +280,7 @@ CTEST(cregex, replace) ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022"); // Strip out everything but the matches - cstr_take(&str, cregex_replace_ss(&re, csubstr_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;"); } } diff --git a/src/cregex.c b/src/cregex.c index c045b9f3..e6da66b2 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -100,7 +100,7 @@ typedef struct _Reprog /* * Sub expression matches */ -typedef csubstr _Resub; +typedef csview _Resub; /* * substitution list @@ -1215,8 +1215,8 @@ _regexec(const _Reprog *progp, /* program to run */ static void -_build_subst(const char* replace, int nmatch, const csubstr match[], - bool (*mfun)(int, csubstr, cstr*), cstr* subst) { +_build_subst(const char* replace, int nmatch, const csview match[], + bool (*mfun)(int, csview, cstr*), cstr* subst) { cstr_buf buf = cstr_buffer(subst); intptr_t len = 0, cap = buf.cap; char* dst = buf.data; @@ -1233,7 +1233,7 @@ _build_subst(const char* replace, int nmatch, const csubstr match[], if (replace[1] >= '0' && replace[1] <= '9' && replace[2] == ';') { g = g*10 + (replace[1] - '0'); replace += 2; } if (g < nmatch) { - csubstr m = mfun && mfun(g, match[g], &mstr) ? cstr_ss(&mstr) : match[g]; + csview m = mfun && mfun(g, match[g], &mstr) ? cstr_sv(&mstr) : match[g]; if (len + m.size > cap) dst = cstr_reserve(subst, cap += cap/2 + m.size); for (int i = 0; i < m.size; ++i) @@ -1270,7 +1270,7 @@ cregex_captures(const cregex* self) { } int -cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags) { +cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { int res = _regexec(re->prog, input, cregex_captures(re) + 1, match, mflags); switch (res) { case 1: return CREG_OK; @@ -1281,7 +1281,7 @@ cregex_find_4(const cregex* re, const char* input, csubstr match[], int mflags) int cregex_find_pattern_4(const char* pattern, const char* input, - csubstr match[], int cmflags) { + csview match[], int cmflags) { cregex re = cregex_init(); int res = cregex_compile(&re, pattern, cmflags); if (res != CREG_OK) return res; @@ -1291,16 +1291,16 @@ cregex_find_pattern_4(const char* pattern, const char* input, } cstr -cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int count, - bool (*mfun)(int, csubstr, cstr*), int rflags) { +cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, + bool (*mfun)(int, csview, cstr*), int rflags) { cstr out = cstr_init(); cstr subst = cstr_init(); - csubstr match[CREG_MAX_CAPTURES]; + csview match[CREG_MAX_CAPTURES]; int nmatch = cregex_captures(re) + 1; if (!count) count = INT32_MAX; bool copy = !(rflags & CREG_STRIP); - while (count-- && cregex_find_ss(re, input, match) == CREG_OK) { + while (count-- && cregex_find_sv(re, input, match) == CREG_OK) { _build_subst(replace, nmatch, match, mfun, &subst); const intptr_t mpos = (match[0].str - input.str); if (copy & (mpos > 0)) cstr_append_n(&out, input.str, mpos); @@ -1308,19 +1308,19 @@ cregex_replace_ss_6(const cregex* re, csubstr input, const char* replace, int co input.str = match[0].str + match[0].size; input.size -= mpos + match[0].size; } - if (copy) cstr_append_ss(&out, input); + if (copy) cstr_append_sv(&out, input); cstr_drop(&subst); return out; } cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*mfun)(int, csubstr, cstr*), int crflags) { + bool (*mfun)(int, csview, cstr*), int crflags) { cregex re = cregex_init(); if (cregex_compile(&re, pattern, crflags) != CREG_OK) assert(0); - csubstr ss = c_ss(input, c_strlen(input)); - cstr out = cregex_replace_ss(&re, ss, replace, count, mfun, crflags); + csview sv = c_sv(input, c_strlen(input)); + cstr out = cregex_replace_sv(&re, sv, replace, count, mfun, crflags); cregex_drop(&re); return out; } diff --git a/src/libstc.c b/src/libstc.c index b0d27350..462c97c4 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -1,7 +1,7 @@ #define i_import #include "../include/stc/cregex.h" /* cstr. utf8, and cregex */ #define i_implement -#include "../include/stc/csubstr.h" +#include "../include/stc/csview.h" #define i_implement #include "../include/stc/crand.h" #if __STDC_VERSION__ >= 201112L diff --git a/src/singleupdate.sh b/src/singleupdate.sh index be99d4a7..8c2bba45 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -22,8 +22,8 @@ python singleheader.py $d/include/stc/cspan.h $d/../stcsingle/stc/cspan.h python singleheader.py $d/include/stc/csset.h $d/../stcsingle/stc/csset.h python singleheader.py $d/include/stc/cstack.h $d/../stcsingle/stc/cstack.h python singleheader.py $d/include/stc/cstr.h $d/../stcsingle/stc/cstr.h -python singleheader.py $d/include/stc/csubstr.h $d/../stcsingle/stc/csubstr.h python singleheader.py $d/include/stc/csview.h $d/../stcsingle/stc/csview.h +python singleheader.py $d/include/stc/crawstr.h $d/../stcsingle/stc/crawstr.h python singleheader.py $d/include/stc/cvec.h $d/../stcsingle/stc/cvec.h python singleheader.py $d/include/stc/extend.h $d/../stcsingle/stc/extend.h python singleheader.py $d/include/stc/forward.h $d/../stcsingle/stc/forward.h diff --git a/src/utf8code.c b/src/utf8code.c index ddc4cb97..4abf10ea 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -101,7 +101,7 @@ uint32_t utf8_toupper(uint32_t c) { return c; } -int utf8_icmp_ss(const csubstr s1, const csubstr s2) { +int utf8_icmp_sv(const csview s1, const csview s2) { utf8_decode_t d1 = {.state=0}, d2 = {.state=0}; intptr_t j1 = 0, j2 = 0; while ((j1 < s1.size) & (j2 < s2.size)) { -- cgit v1.2.3