diff options
| author | Tyge Løvset <[email protected]> | 2023-07-18 02:36:04 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-07-18 02:36:04 +0200 |
| commit | da70303c149b37dbf442e41038a00836132562ee (patch) | |
| tree | 06d795c66d6759e06de5f2d166215b461ac40d1d | |
| parent | 071b41c0fe95cb3f9a72bbe0417d856e7989ca08 (diff) | |
| parent | 23eeedb3fc298602732f394adba6a43c876ca7d8 (diff) | |
| download | STC-modified-da70303c149b37dbf442e41038a00836132562ee.tar.gz STC-modified-da70303c149b37dbf442e41038a00836132562ee.zip | |
Merge branch 'dev43' into master
150 files changed, 4160 insertions, 3336 deletions
diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 5ceacd43..b1443a0d 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -7,8 +7,8 @@ jobs: build_and_test: runs-on: ubuntu-latest env: - CFLAGS: -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract - CXXFLAGS: -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract + CFLAGS: -DSTC_STATIC -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract + CXXFLAGS: -DSTC_STATIC -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract steps: - name: 'Checkout' uses: actions/checkout@v2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 87662318..3edd39cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ if(BUILD_TESTING) get_filename_component(name "${file}" NAME_WE) add_executable(${name} ${file}) #target_compile_options(${name} PRIVATE "-pthread") + target_compile_options(${name} PRIVATE "-DSTC_STATIC") if(CMAKE_THREAD_LIBS_INIT) target_link_libraries(${name} PRIVATE "${CMAKE_THREAD_LIBS_INIT}") endif() @@ -3,7 +3,7 @@ STC - Smart Template Containers =============================== -### [Version 4.2](#version-history) +### [Version 4.3 RC3](#version-history) --- Description @@ -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) @@ -81,9 +81,9 @@ 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. +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 @@ -117,8 +117,8 @@ 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`. -- Template parameter macros are prefixed by `i_`, e.g. `i_val`, `i_type`. +- Public STC macros are prefixed by `c_`, e.g. `c_foreach`, `c_init`. +- 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 @@ -147,10 +147,10 @@ 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_val float // Container element type +#define i_type Floats // Container type name (optional); if not defined name would be cvec_float +#define i_key float // Container element type #include <stc/cvec.h> // "instantiate" the desired container type #include <stdio.h> @@ -164,39 +164,39 @@ 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 #define i_type Floats -#define i_val float +#define i_key float #include <stc/csset.h> // Use a sorted set instead #include <stdio.h> -int main() +int main(void) { Floats nums = {0}; Floats_push(&nums, 30.f); 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 `==` -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. +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.* Let's make a vector of vectors, which can be cloned. All of its element vectors will be destroyed when destroying the Vec2D. @@ -206,12 +206,12 @@ Let's make a vector of vectors, which can be cloned. All of its element vectors #include <stdio.h> #define i_type Vec -#define i_val float +#define i_key float #include <stc/cvec.h> #define i_type Vec2D -#define i_valclass Vec // Use i_valclass 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 <stc/cvec.h> int main(void) @@ -242,16 +242,17 @@ This example uses four different container types: #include <stdio.h> #define i_key int -#include <stc/cset.h> // cset_int: unordered set +#include <stc/cset.h> // 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_val struct Point -#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) +#define i_key struct Point +#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 <stc/cvec.h> // cvec_pnt: vector of struct Point -#define i_val int +#define i_key int +#define i_native_cmp // enable sort/search. Use native `<` and `==` operators #include <stc/clist.h> // clist_int: singly linked list #define i_key int @@ -333,6 +334,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,18 +347,17 @@ 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`. 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 +#define i_implement #include <stc/cstr.h> #include "Point.h" @@ -369,10 +370,10 @@ or define your own as descibed above. #define i_tag ix #include <stc/cset.h> // cset_ix -#define i_val int +#define i_key int #include <stc/cvec.h> // cvec_int -#define i_val Point +#define i_key Point #define i_tag pnt #include <stc/clist.h> // clist_pnt ``` @@ -383,8 +384,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 +459,7 @@ and non-emplace methods: #define i_implement // define in ONE file to implement longer functions in cstr #include <stc/cstr.h> -#define i_val_str // special macro to enable container of cstr +#define i_key_str // special macro to enable container of cstr #include <stc/cvec.h> // vector of string (cstr) ... cvec_str vec = {0}; @@ -518,7 +519,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 <stc/cvec.h> myvec vec = MyVec_init(); @@ -543,7 +544,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 <stc/cstack.h> ``` @@ -564,8 +565,8 @@ It adds a MemoryContext to each container by defining the `i_extend` template pa the by inclusion of `<stc/extend.h>`. ```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 +575,12 @@ the by inclusion of `<stc/extend.h>`. #define i_extend MemoryContext memctx; #include <stc/extend.h> ``` -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 @@ -611,6 +612,25 @@ 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: 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 (<, ==). +- 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 <stc/cstr.h> will also define utf8 case conversions. + - Define i_import before #include <stc/cregex.h> 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. + ## Version 4.2 - New home! And online single headers for https://godbolt.org - Library: https://github.com/stclib/STC @@ -636,7 +656,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/carc_api.md b/docs/carc_api.md index 48b64ff0..8b7b67a1 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 <stc/carc.h> ``` `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,19 +58,19 @@ 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 | Type name | Type definition | Used to represent... | |:------------------|:--------------------------------------------------|:-----------------------| -| `carc_NULL` | `{NULL, NULL}` | Init nullptr const | +| `carc_null` | `{0}` | Init nullptr const | | `carc_X` | `struct { carc_X_value* get; long* use_count; }` | The carc type | -| `carc_X_value` | `i_val` | The carc element type | -| `carc_X_raw` | `i_valraw` | Convertion type | +| `carc_X_value` | `i_key` | The carc element type | +| `carc_X_raw` | `i_keyraw` | Convertion type | ## Example @@ -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 <stc/cstr.h> #define i_type Map @@ -88,15 +89,15 @@ bool carc_X_value_eq(const i_val* x, const i_val* y); #include <stc/csmap.h> #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 <stc/carc.h> #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 <stc/cstack.h> -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 ca4d90da..b6c76d2f 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 <stc/cbox.h> ``` `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,18 +55,18 @@ 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 | Type name | Type definition | Used to represent... | |:-------------------|:--------------------------------|:------------------------| -| `cbox_NULL` | `{NULL}` | Init nullptr const | +| `cbox_null` | `{0}` | Init nullptr const | | `cbox_X` | `struct { cbox_X_value* get; }` | The cbox type | -| `cbox_X_value` | `i_val` | The cbox element type | +| `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 <stc/cbox.h> #define i_type ISet @@ -87,12 +87,12 @@ void int_drop(int* x) { #include <stc/csset.h> // ISet : std::set<std::unique_ptr<int>> #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 <stc/cvec.h> // IVec : std::vector<std::unique_ptr<int>> -int main() +int main(void) { - 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 7a3c3196..e053f743 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -18,7 +18,7 @@ #define i_tag ii #include <stc/csmap.h> ... -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); @@ -40,7 +40,7 @@ c_forpair (id, count, csmap_ii, map) ``` ### c_forlist -Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element. +Iterate compound literal array elements. Additional to `i.ref`, you can access `i.size` and `i.index` for the input list/element. ```c // apply multiple push_backs c_forlist (i, int, {1, 2, 3}) @@ -82,7 +82,6 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i); ### crange A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: ```c -crange& crange_obj(...) // create a compound literal crange object crange crange_make(stop); // will generate 0, 1, ..., stop-1 crange crange_make(start, stop); // will generate start, start+1, ... stop-1 crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop @@ -100,7 +99,8 @@ c_forfilter (i, crange, r1, isPrime(*i.ref)) // 2. The first 11 primes: printf("2"); -c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2), +crange range = crange_make(3, INT64_MAX, 2); +c_forfilter (i, crange, range, isPrime(*i.ref) && c_flt_take(10) ){ @@ -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, ... @@ -158,11 +158,11 @@ 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 -#define i_val_str // owned cstr string value type +#define i_key_str // owned cstr string value type #include <stc/cset.h> #define i_key int @@ -170,11 +170,10 @@ Make any container from an initializer list: #include <stc/cmap.h> ... // Initializes with const char*, internally converted to cstr! -cset_str myset = c_make(cset_str, {"This", "is", "the", "story"}); -cset_str myset2 = c_clone(myset); +cset_str myset = c_init(cset_str, {"This", "is", "the", "story"}); 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 @@ -204,22 +203,40 @@ if (it.ref) cmap_str_erase_at(&map, it); c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello")); ``` -### csort - two times faster qsort +### sort_n_ - two times faster qsort -When very fast array sorting is required, **csort** is about twice as fast as *qsort()*, and often simpler to use. +The **sort_n**, **sort_ij** algorithm is about twice as fast as *qsort()*, and often simpler to use. You may customize `i_tag` and the comparison function `i_cmp` or `i_less`. There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c). ```c -#define i_val int -#include <stc/algo/csort.h> +#define i_key int +#include <stc/algo/sort.h> +#include <stdio.h> -int main() { - int array[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4}; - csort_int(array, c_arraylen(array)); +int 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 <stc/cdeq.h> // deque +#include <stc/algo/sort.h> +#include <stdio.h> +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 @@ -256,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); @@ -295,6 +312,7 @@ the gcd() function. It also ensures that it stops when the diagonal size >= 100: [ [Run this code](https://godbolt.org/z/coqqrfbd5) ] ```c #include <stc/calgo.h> +#include <stdio.h> struct triples { int n; // input: max number of triples to be generated. @@ -302,21 +320,23 @@ struct triples { int cco_state; // required member }; -bool triples_next(struct triples* i) { // coroutine - cco_begin(i); +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(true); - if (--i->n == 0) cco_return; + cco_yield(); + if (--i->n == 0) + cco_return; } } } } - cco_final: // required label + cco_cleanup: puts("done"); - cco_end(false); + } + return 0; } int gcd(int a, int b) { // greatest common denominator @@ -328,12 +348,12 @@ 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; - while (triples_next(&t)) { + while (triples(&t)) { // Skip triples with GCD(a,b) > 1 if (gcd(t.a, t.b) > 1) continue; @@ -347,25 +367,54 @@ int main() } ``` ### Coroutine API -**Note**: *cco_yield()* may not be called inside a `switch` statement. Use `if-else-if` constructs instead. -To resume the coroutine from where it was suspended with *cco_yield()*, simply call the coroutine again. +To resume the coroutine from where it was suspended with *cco_yield()*: call the coroutine again. + +**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement from a +cco_routine scope; Use `if-else-if` constructs instead. | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| -| | `cco_final:` | Obligatory label in coroutine | -| | `cco_return;` | Early return from the coroutine | -| `bool` | `cco_alive(ctx)` | Is coroutine in initial or suspended state? | -| `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? | -| `void` | `cco_begin(ctx)` | Begin coroutine block | -| `rettype` | `cco_end(retval)` | End coroutine block with return value | -| `void` | `cco_end()` | End coroutine block | -| `rettype` | `cco_yield(retval)` | Suspend execution and return a value | -| `void` | `cco_yield()` | Suspend execution | -| `rettype` | `cco_yield(corocall2, ctx2, retval)` | Yield from another coroutine and return val | -| `void` | `cco_yield(corocall2, ctx2)` | Yield from another coroutine | -| | From the caller side: | | -| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | -| `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | +| | Function / 'keywords': | | +|`cco_result` | Enum `CCO_DONE=0`, `CCO_YIELD`, `CCO_AWAIT` | Recommended return values in coroutines | +| | Function / 'keywords': | | +| | `cco_cleanup:` | Label for cleanup position in coroutine | +| `bool` | `cco_done(co)` | Is coroutine done? | +| | `cco_routine(co) { }` | The coroutine scope | +| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)| +| | `cco_yield_v();` | Yield/suspend execution (return void) | +| | `cco_yield_v(ret);` | Yield/suspend execution (return ret) | +| | `cco_yield_final();` | Yield final time, enables cleanup-state | +| | `cco_yield_final(ret);` | Yield a final value (e.g. CCO_ERROR) | +| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| +| | `cco_await_v(condition);` | Suspend until condition is true (return void) | +| | `cco_await_v(condition, ret);` | Suspend until condition is true (return ret)| +| | `cco_await_on(cocall);` | Await on sub-coroutine to finish (return its ret) | +| | `cco_return;` | Return from coroutine (inside cco_routine) | +| | `cco_closure(Closure, ...);` | Define a coroutine closure struct (optional) | +| | Semaphores: | | +| | `cco_sem` | Semaphore type | +| `cco_sem` | `cco_sem_from(long value)` | Create semaphore | +| | `cco_sem_set(sem, long value)` | Set semaphore value | +| | `cco_sem_await(sem)` | Await for the semaphore count > 0 | +| | `cco_sem_await(sem, ret)` | Await with ret on the semaphore | +| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | +| | Timers: | | +| | `cco_timer` | Timer type | +| | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)| +| | `cco_timer_await(tm, double sec, ret)`| Await secs for timer with ret value | +| | `cco_timer_start(tm, double sec)` | Start timer for secs duration | +| | `cco_timer_restart(tm)` | Restart timer with same duration | +| `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | +| `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_block_on(cocall) { }` | Run blocking until cocall is finished | +| `void` | `cco_block_on(cocall, int *result) { }`| Run blocking until cocall is finished | +| | Time functions: | | +| `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | +| | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | --- ## RAII scope macros @@ -384,7 +433,10 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are | `continue` | Exit a defer-block without resource leak | ```c +#include <stc/algo/raii.h> // or <stc/calgo.h> +... // `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)) { @@ -431,9 +483,10 @@ return ok; **Example 2**: Load each line of a text file into a vector of strings: ```c #include <errno.h> +#define i_implement #include <stc/cstr.h> -#define i_val_str +#define i_key_str #include <stc/cvec.h> // receiver should check errno variable @@ -447,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 fc11fe66..c6de6cd6 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -1,7 +1,9 @@ # STC [cdeq](../include/stc/cdeq.h): Double Ended Queue  -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. @@ -9,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 <stc/cdeq.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -32,81 +34,74 @@ 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_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_value* cdeq_X_at_mut(cdeq_X* self, intptr_t idx); +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(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_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_keyraw[] arr, intptr_t n); +cdeq_X_iter cdeq_X_emplace_at(cdeq_X* self, cdeq_X_iter it, i_keyraw raw); -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_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); +bool cdeq_X_eq(const cdeq_X* c1, const cdeq_X* c2); // require i_eq/i_cmp/i_less. cdeq_X_value cdeq_X_value_clone(cdeq_X_value val); +cdeq_X_raw cdeq_X_value_toraw(const cdeq_X_value* pval); +void cdeq_X_value_drop(cdeq_X_value* pval); ``` ## Types | 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 <stc/cdeq.h> #include <stdio.h> -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 a1dbe105..3d785789 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 <stc/clist.h> ``` @@ -53,50 +53,53 @@ 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); 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); +bool clist_X_eq(const clist_X* c1, const clist_X* c2); // equality test clist_X_value clist_X_value_clone(clist_X_value val); +clist_X_raw clist_X_value_toraw(const clist_X_value* pval); +void clist_X_value_drop(clist_X_value* pval); ``` ## Types @@ -105,8 +108,8 @@ clist_X_value clist_X_value_clone(clist_X_value val); |:--------------------|:------------------------------------|:-----------------------------------------| | `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 @@ -114,14 +117,13 @@ clist_X_value clist_X_value_clone(clist_X_value val); Interleave *push_front()* / *push_back()* then *sort()*: ```c #define i_type DList -#define i_val double -#define i_extern // link with sort() fn. +#define i_key double #include <stc/clist.h> #include <stdio.h> -int main() { - DList list = c_make(DList, {10., 20., 30., 40., 50., 60., 70., 80., 90.}); +int main(void) { + 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); @@ -152,14 +154,14 @@ Use of *erase_at()* and *erase_range()*: ```c // erasing from clist #define i_tag i -#define i_val int +#define i_key int #include <stc/clist.h> #include <stdio.h> -int main () +int main(void) { - 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); @@ -187,14 +189,14 @@ 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 <stc/clist.h> #include <stdio.h> -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}); +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}); 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 d2a94ee8..eca350b4 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -9,8 +9,8 @@ hashing (aka open addressing) with linear probing, and without leaving tombstone ***Iterator invalidation***: References and iterators are invalidated after erase. No iterators are invalidated after insert, unless the hash-table need to be extended. The hash table size can be reserved prior to inserts if the total max size is known. -The order of elements is preserved after erase and insert. This makes it possible to erase individual elements while iterating -through the container by using the returned iterator from *erase_at()*, which references the next element. +The order of elements may not be preserved after erase. It is still possible to erase elements when iterating through +the container by setting the iterator to the value returned from *erase_at()*, which references the next element. Note that a small number of elements may be visited twice when doing this, but all elements will be visited. See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/container/unordered_map) for a functional description. @@ -36,7 +36,7 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain #define i_valto // convertion func i_val* => i_valraw #define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val -#define i_ssize // internal; default int32_t. If defined, table expand 2x (else 1.5x) +#define i_expandby // default 1. If 2, table expand 2x (else 1.5x) #include <stc/cmap.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -114,16 +114,17 @@ bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // ! ## Examples ```c +#define i_implement #include <stc/cstr.h> #define i_key_str #define i_val_str #include <stc/cmap.h> -int main() +int main(void) { // 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"} @@ -157,13 +158,14 @@ The HEX of color BLACK is:[#000000] ### Example 2 This example uses a cmap with cstr as mapped value. ```c +#define i_implement #include <stc/cstr.h> #define i_type IDMap #define i_key int #define i_val_str #include <stc/cmap.h> -int main() +int main(void) { uint32_t col = 0xcc7744ff; @@ -206,7 +208,7 @@ typedef struct { int x, y, z; } Vec3i; #define i_tag vi #include <stc/cmap.h> -int main() +int main(void) { // Define map with defered destruct cmap_vi vecs = {0}; @@ -241,7 +243,7 @@ typedef struct { int x, y, z; } Vec3i; #define i_tag iv #include <stc/cmap.h> -int main() +int main(void) { cmap_iv vecs = {0} @@ -267,6 +269,7 @@ Output: ### Example 5: Advanced Key type is struct. ```c +#define i_implement #include <stc/cstr.h> typedef struct { @@ -274,7 +277,7 @@ typedef struct { cstr country; } Viking; -#define Viking_init() ((Viking){cstr_NULL, cstr_NULL}) +#define Viking_init() ((Viking){cstr_null, cstr_null}) static inline int Viking_cmp(const Viking* a, const Viking* b) { int c = cstr_cmp(&a->name, &b->name); @@ -301,7 +304,7 @@ static inline void Viking_drop(Viking* vk) { #define i_val int #include <stc/cmap.h> -int main() +int main(void) { // Use a HashMap to store the vikings' health points. Vikings vikings = {0}; @@ -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 <stc/cstr.h> typedef struct Viking { @@ -376,7 +380,7 @@ static inline RViking Viking_toraw(const Viking* vp) { #define i_val int #include <stc/cmap.h> -int main() +int main(void) { Vikings vikings = {0}; diff --git a/docs/cpque_api.md b/docs/cpque_api.md index 962ee162..5b63dfd1 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 <stc/cpque.h> ``` `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,19 +56,19 @@ 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 <stc/crand.h> #include <stdio.h> -#define i_val int64_t +#define i_key int64_t #define i_cmp -c_default_cmp // min-heap #define i_tag i #include <stc/cpque.h> -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 9ea4b148..b324e5fc 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 <stc/cqueue.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -26,27 +26,35 @@ 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); - +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); 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); +bool cqueue_X_eq(const cqueue_X* c1, const cqueue_X* c2); // require i_eq/i_cmp/i_less. +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); ``` ## Types @@ -54,19 +62,19 @@ i_val cqueue_X_value_clone(i_val value); | 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 <stc/cqueue.h> #include <stdio.h> -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 7281b2d7..22a4f4dd 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 <time.h> #include <stc/crand.h> +#define i_implement #include <stc/cstr.h> // Declare int -> int sorted map. Uses typetag 'i' for ints. @@ -75,7 +76,7 @@ double crand_norm(crand_t* rng, crand_norm_t* dist); #define i_tag i #include <stc/csmap.h> -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 9a15a869..52476e09 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); @@ -29,7 +29,7 @@ cregex cregex_from(const char* pattern, int cflags = CREG_DEFAULT); // return CREG_OK, or negative error code on failure int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_DEFAULT); - // num. of capture groups in regex. 0 if RE is invalid. First group is the full match + // num. of capture groups in regex, excluding the 0th group which is the full match int cregex_captures(const cregex* self); // return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR @@ -44,15 +44,15 @@ bool cregex_is_match(const cregex* re, const char* input); // Replace all matches in input cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX); - // Replace count matches in input string-view. Optionally transform replacement with mfun. + // Replace count matches in input string-view. Optionally transform replacement. cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX); cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count, - bool(*mfun)(int capgrp, csview match, cstr* mstr), int rflags); + bool(*transform)(int group, csview match, cstr* result), int rflags); // All-in-one replacement (compile + find/replace + drop) cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX); cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count, - bool(*mfun)(int capgrp, csview match, cstr* mstr), int rflags); + bool(*transform)(int group, csview match, cstr* result), int rflags); // destroy void cregex_drop(cregex* self); ``` @@ -99,10 +99,10 @@ 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 <stc/cregex.h> -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"; @@ -138,20 +138,20 @@ 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) - c_forrange (k, cregex_captures(&re)) - printf("submatch %lld: %.*s\n", k, c_SV(match[k])); +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])); ``` There is also a for-loop macro to simplify it: ```c c_formatch (it, &re, input) - c_forrange (k, cregex_captures(&re)) - printf("submatch %lld: %.*s\n", k, c_SV(it.match[k])); + for (int k = 1; i <= cregex_captures(&re); ++k) + printf("submatch %d: %.*s\n", k, c_SV(it.match[k])); ``` ## Using cregex in a project -The easiest is to `#define i_extern` before `#include <stc/cregex.h>`. Make sure to do that in one translation unit only. +The easiest is to `#define i_import` before `#include <stc/cregex.h>`. 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` @@ -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/docs/cset_api.md b/docs/cset_api.md index 026d7462..e894ad4f 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -18,8 +18,8 @@ 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_ssize // default int32_t. If defined, table expand 2x (else 1.5x) +#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 <stc/cset.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -77,16 +77,17 @@ cset_X_value cset_X_value_clone(cset_X_value val); ## Example ```c +#define i_implement #include <stc/cstr.h> #define i_type Strset #define i_key_str #include <stc/cset.h> -int main () +int main(void) { 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 93faa4f9..099d7dfc 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -33,7 +33,6 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo #define i_valto // convertion func i_val* => i_valraw #define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val -#define i_ssize // internal size rep. defaults to int32_t #include <stc/csmap.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -84,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 @@ -102,16 +102,16 @@ csmap_X_raw csmap_X_value_toraw(csmap_X_value* pval); ## Examples ```c +#define i_implement #include <stc/cstr.h> - #define i_key_str // special macro for i_key = cstr, i_tag = str #define i_val_str // ditto #include <stc/csmap.h> -int main() +int main(void) { // 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"} @@ -150,6 +150,7 @@ Translate a [ [Run this code](https://godbolt.org/z/9d1PP77Pa) ] ```c +#define i_implement #include <stc/cstr.h> #define i_type strmap #define i_key_str @@ -165,7 +166,7 @@ static void print_result(strmap_result result) { print_node(result.ref); } -int main() +int main(void) { strmap m = {0}; @@ -182,6 +183,7 @@ int main() ### Example 3 This example uses a csmap with cstr as mapped value. ```c +#define i_implement #include <stc/cstr.h> #define i_type IDSMap @@ -189,10 +191,10 @@ This example uses a csmap with cstr as mapped value. #define i_val_str #include <stc/csmap.h> -int main() +int main(void) { 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"); @@ -235,7 +237,7 @@ static int Vec3i_cmp(const Vec3i* a, const Vec3i* b) { #include <stc/csmap.h> #include <stdio.h> -int main() +int main(void) { csmap_vi vmap = {0}; diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 10565b0f..09821450 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -22,15 +22,14 @@ using_cspan4(S, ValueType); // define span types S, S2, S3, S4 with ## Methods All functions are type-safe. Note that the span argument itself is generally not side-effect safe, -i.e., it may be expanded multiple times. However, all integer arguments are safe, e.g. +i.e., it may be expanded multiple times. However, all index arguments are safe, e.g. `cspan_at(&ms3, i++, j++, k++)` is allowed. If the number of arguments does not match the span rank, a compile error is issued. Runtime bounds checks are enabled by default (define `STC_NDEBUG` or `NDEBUG` to disable). ```c -SpanType cspan_make(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values +SpanType cspan_init(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from compatible STC container SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from C array -SpanTypeN cspan_md(ValueType* data, intptr_t xdim, ...); // make a multi-dimensional cspan - + intptr_t cspan_size(const SpanTypeN* self); // return number of elements intptr_t cspan_rank(const SpanTypeN* self); // dimensions; compile time constant intptr_t cspan_index(const SpanTypeN* self, intptr_t x, ..); // index of element @@ -39,32 +38,38 @@ ValueType* cspan_at(const SpanTypeN* self, intptr_t x, ...); // #args mus ValueType* cspan_front(const SpanTypeN* self); ValueType* cspan_back(const SpanTypeN* self); - // general index slicing to create a subspan. - // {i} reduces rank. {i,c_END} slice to end. {c_ALL} use the full extent. -SpanTypeR cspan_slice(T SpanTypeR, const SpanTypeN* self, {x0,x1}, {y0,y1}.., {N0,N1}); - - // create a subspan of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); -SpanType cspan_submd2(const SpanType2* self, intptr_t x); // return a 1d subspan from a 2d span. -SpanTypeN cspan_submd3(const SpanType3* self, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span. -SpanTypeN cspan_submd4(const SpanType4* self, intptr_t x, ...); // number of args determines rank of output span. - - // create a subspan of same rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); -SpanType cspan_subspan(const SpanType* self, intptr_t offset, intptr_t count); -SpanType2 cspan_subspan2(const SpanType2 self, intptr_t offset, intptr_t count); -SpanType3 cspan_subspan3(const SpanType3 self, intptr_t offset, intptr_t count); - SpanTypeN_iter SpanType_begin(const SpanTypeN* self); SpanTypeN_iter SpanType_end(const SpanTypeN* self); void SpanType_next(SpanTypeN_iter* it); -``` -## Types -| Type name | Type definition | Used to represent... | +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 subspan of input span rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); +SpanType cspan_subspan(const SpanType* span, intptr_t offset, intptr_t count); +SpanType2 cspan_subspan2(const SpanType2* span, intptr_t offset, intptr_t count); +SpanType3 cspan_subspan3(const SpanType3* span, intptr_t offset, intptr_t count); + + // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); +OutSpan1 cspan_submd2(const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span. +OutSpanN cspan_submd3(const SpanType3* parent, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span. +OutSpanN cspan_submd4(const SpanType4* parent, intptr_t x, ...); // number of args decides rank of output span. + + // general slicing of an md span. + // {i}: reduce rank. {i,c_END}: slice to end. {c_ALL}: use full extent. +OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeN* parent, {x0,x1}, {y0,y1}.., {N0,N1}); +``` +## TypesPd +| Type name | Type definition / usage | Used to represent... | |:------------------|:----------------------------------------------------|:---------------------| | SpanTypeN | `struct { ValueType *data; uint32_t shape[N]; .. }` | SpanType with rank N | | SpanTypeN`_value` | `ValueType` | The ValueType | -| `c_ALL` | | Full extent | -| `c_END` | | End of extent | +| `c_ALL` | Use with `cspan_slice()`. | Full extent | +| `c_END` | " | End of extent | ## Example 1 @@ -96,10 +101,10 @@ if __name__ == '__main__': #include <stc/cspan.h> 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); + myspan3 ms3 = cspan_md(arr, 2, 3, 4); // C-order, i.e. row-major. myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {1,3}, {2,c_END}); myspan2 ss2 = cspan_submd3(&ss3, 1); @@ -118,7 +123,7 @@ int main() { #include <mdspan> #include <tuple> -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); @@ -136,15 +141,16 @@ int main() { ## Example 2 Slicing cspan without and with reducing the rank: ```c -#include <c11/print.h> +#define i_implement +#include <c11/fmt.h> #include <stc/cspan.h> using_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3 -int main() +int main(void) { - // 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); @@ -154,7 +160,7 @@ int main() puts("\niterate span2 flat:"); c_foreach (i, Span2, span2) - print(" {}", *i.ref); + fmt_print(" {}", *i.ref); puts(""); // slice without reducing rank: @@ -164,8 +170,8 @@ int main() c_forrange (i, ss3.shape[0]) { c_forrange (j, ss3.shape[1]) { c_forrange (k, ss3.shape[2]) - print(" {:2}", *cspan_at(&ss3, i, j, k)); - print(" |"); + fmt_print(" {:2}", *cspan_at(&ss3, i, j, k)); + fmt_print(" |"); } } // slice and reduce rank: @@ -174,13 +180,13 @@ int main() puts("\niterate ss2 by dimensions:"); c_forrange (i, ss2.shape[0]) { c_forrange (j, ss2.shape[1]) - print(" {:2}", *cspan_at(&ss2, i, j)); - print(" |"); + fmt_print(" {:2}", *cspan_at(&ss2, i, j)); + fmt_print(" |"); } puts("\niterate ss2 flat:"); c_foreach (i, Span2, ss2) - print(" {:2}", *i.ref); + fmt_print(" {:2}", *i.ref); puts(""); } ``` diff --git a/docs/csset_api.md b/docs/csset_api.md index e83ab857..aef3af3c 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -18,8 +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_ssize // defaults to int32_t +#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_key #include <stc/csset.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -77,17 +76,18 @@ csset_X_value csset_X_value_clone(csset_X_value val); ## Example ```c +#define i_implement #include <stc/cstr.h> #define i_type SSet #define i_key_str #include <stc/csset.h> -int main () +int main(void) { 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/docs/cstack_api.md b/docs/cstack_api.md index b1371f4e..e799b152 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 <stc/cstack.h> ``` `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); @@ -54,8 +54,10 @@ 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); +bool cstack_X_eq(const cstack_X* c1, const cstack_X* c2); // require i_eq/i_cmp/i_less. +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); ``` ## Types @@ -63,19 +65,19 @@ i_val cstack_X_value_clone(i_val value); | 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 <stc/cstack.h> #include <stdio.h> -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 64ad002c..dae5669f 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -18,7 +18,7 @@ All cstr definitions and prototypes are available by including a single header f ## Methods ```c -cstr cstr_init(void); // constructor; same as cstr_NULL. +cstr cstr_init(void); // constructor; same as cstr_null. cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call. cstr cstr_from(const char* str); // constructor using strlen() cstr cstr_from_n(const char* str, intptr_t n); // constructor with n first bytes of str @@ -153,13 +153,14 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt | Name | Value | |:------------------|:------------------| | `c_NPOS` | `INTPTR_MAX` | -| `cstr_NULL` | cstr null value | +| `cstr_null` | empty cstr value | ## Example ```c +#define i_implement #include <stc/cstr.h> -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 ec3bf121..79a5c07b 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 <stc/cstr.h> // optional, include cstr+csview functionality -#include <stc/csview.h> +#define i_implement +#include <stc/cstr.h> +#include <stc/csview.h> // after cstr.h: include extra cstr-csview functions ``` ## Methods @@ -111,28 +112,29 @@ uint64_t csview_hash(const csview* x); | Name | Value | Usage | |:---------------|:---------------------|:---------------------------------------------| -| `csview_NULL` | same as `c_sv("")` | `sview = csview_NULL;` | +| `csview_null` | same as `c_sv("")` | `sview = csview_null;` | | `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` | ## Example ```c +#define i_implement #include <stc/cstr.h> #include <stc/csview.h> -int main () +int main(void) { 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,10 +148,10 @@ red Apples ### Example 2: UTF8 handling ```c +#define i_import // include dependent cstr, utf8 and cregex function definitions. #include <stc/cstr.h> -#include <stc/csview.h> -int main() +int main(void) { cstr s1 = cstr_lit("hell😀 w😀rld"); @@ -181,9 +183,9 @@ void print_split(csview input, const char* sep) printf("[%.*s]\n", c_SV(i.token)); puts(""); } - +#define i_implement #include <stc/cstr.h> -#define i_val_str +#define i_key_str #include <stc/cstack.h> cstack_str string_split(csview input, const char* sep) @@ -196,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 5879bc1f..d38ef23f 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 <stc/cvec.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -31,16 +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_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_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); -cvec_X_iter cvec_X_insert_uninit(cvec_X* self, i_val* pos, intptr_t n); // return pos iter +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 @@ -49,55 +48,52 @@ 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 -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_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 +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_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(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_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_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[] arr, intptr_t n); // clone values -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_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); 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, - 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); 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); +bool cvec_X_eq(const cvec_X* c1, const cvec_X* c2); // equality comp. cvec_X_value cvec_X_value_clone(cvec_X_value val); +cvec_X_raw cvec_X_value_toraw(const cvec_X_value* pval); +cvec_X_raw cvec_X_value_drop(cvec_X_value* pval); ``` ## Types @@ -105,18 +101,18 @@ cvec_X_value cvec_X_value_clone(cvec_X_value val); | 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 <stc/cvec.h> #include <stdio.h> -int main() +int main(void) { // Create a vector containing integers cvec_int vec = {0}; @@ -151,12 +147,13 @@ sorted: 5 7 8 13 16 25 ``` ### Example 2 ```c +#define i_implement #include <stc/cstr.h> -#define i_val_str +#define i_key_str #include <stc/cvec.h> -int main() { +int main(void) { cvec_str names = cvec_str_init(); cvec_str_emplace(&names, "Mary"); @@ -187,6 +184,7 @@ item: 2 elements so far Container with elements of structs: ```c +#define i_implement #include <stc/cstr.h> typedef struct { @@ -208,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 <stc/cvec.h> int main(void) { diff --git a/include/c11/print.h b/include/c11/fmt.h index 7c155875..d2eab8bc 100644 --- a/include/c11/print.h +++ b/include/c11/fmt.h @@ -1,39 +1,39 @@ #ifndef FMT_H_INCLUDED
#define FMT_H_INCLUDED
/*
-VER 2.1: NEW API:
-void print(fmt, ...);
-void println(fmt, ...);
-void printd(dest, fmt, ...);
-
+VER 2.2: NEW API:
void fmt_print(fmt, ...);
void fmt_println(fmt, ...);
void fmt_printd(dest, fmt, ...);
-void fmt_destroy(fmt_buffer* buf);
+const char* fmt_tm(fmt, struct tm* tp);
+void fmt_close(fmt_stream* ss);
dest - destination, one of:
FILE* fp Write to a file
char* strbuf Write to a pre-allocated string buffer
- fmt_buffer* buf Auto realloc the needed memory (safe).
- Set buf->stream=1 for stream-mode.
- Call fmt_destroy(buf) after usage.
+ fmt_stream* ss Write to a string-stream (auto allocated).
+ Set ss->overwrite=1 for overwrite-mode.
+ Call fmt_close(ss) after usage.
- fmt - format string
+ fmt - format string (const char*)
{} Auto-detected format. If :MOD is not specified,
float will use ".8g" format, and double ".16g".
- {:MOD} Format modifiers: < left align (replaces -), default for char*, char.
- > right align, default for numbers.
- Other than that MOD can be normal printf format modifiers.
- {{, }} Print chars {, and }. (note: a single % prints %).
+ {:MODS} Format modifiers: '<' left align (replaces '-'). Default for char* and char.
+ '>' right align. Default for numbers.
+ Other than that MODS can be regular printf() format modifiers.
+ {{ }} % Print the '{', '}', and '%' characters.
* C11 or higher required.
* MAX 255 chars fmt string by default. MAX 12 arguments after fmt string.
-* Static linking by default, shared symbols by defining FMT_HEADER / FMT_IMPLEMENT.
+* Define FMT_IMPLEMENT or i_implement prior to #include in one translation unit.
+* Define FMT_SHORTS to add print(), println() and printd() macros, without fmt_ prefix.
* (c) operamint, 2022, MIT License.
-----------------------------------------------------------------------------------
-#include "c11/print.h"
+#define FMT_IMPLEMENT
+#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";
@@ -50,19 +50,26 @@ int main() { printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World");
printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x);
printd(buffer, "Precision: {} {:.10} {}", string, pi, x);
- println("{}", buffer);
- println("Vector: ({}, {}, {})", 3.2, 3.3, pi);
+ fmt_println("{}", buffer);
+ fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi);
- fmt_buffer out[1] = {{.stream=1}};
- printd(out, "{} {}", "Pi is:", pi);
- print("{}, len={}, cap={}\n", out->data, out->len, out->cap);
- printd(out, "{} {}", ", Pi squared is:", pi*pi);
- print("{}, len={}, cap={}\n", out->data, out->len, out->cap);
- fmt_destroy(out);
+ fmt_stream ss[1] = {0};
+ printd(ss, "{} {}", "Pi is:", pi);
+ print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap);
+ printd(ss, "{} {}", ", Pi squared is:", pi*pi);
+ print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap);
+ fmt_close(ss);
+
+ time_t now = time(NULL);
+ struct tm t1 = *localtime(&now), t2 = t1;
+ t2.tm_year += 2;
+ fmt_print(1, "Dates:\n {}\n {}\n", fmt_tm("%Y-%m-%d %X %Z", &t1),
+ fmt_tm("%Y-%m-%d %X %Z", &t2));
}
*/
#include <stdio.h>
#include <stdint.h>
+#include <stddef.h>
#include <assert.h>
#define fmt_OVERLOAD(name, ...) \
@@ -77,11 +84,6 @@ int main() { #define _fmt_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
_14, _15, _16, N, ...) N
-#if defined FMT_HEADER || defined FMT_IMPLEMENT
-# define FMT_API
-#else
-# define FMT_API static inline
-#endif
#if defined FMT_NDEBUG || defined NDEBUG
# define fmt_OK(exp) (void)(exp)
#else
@@ -91,25 +93,27 @@ int main() { typedef struct {
char* data;
intptr_t cap, len;
- _Bool stream;
-} fmt_buffer;
+ _Bool overwrite;
+} fmt_stream;
-FMT_API void fmt_destroy(fmt_buffer* buf);
-FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...);
-FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...);
+struct tm; /* Max 2 usages. Buffer = 64 chars. */
+const char* fmt_tm(const char *fmt, const struct tm *tp);
+void fmt_close(fmt_stream* ss);
+int _fmt_parse(char* p, int nargs, const char *fmt, ...);
+void _fmt_bprint(fmt_stream*, const char* fmt, ...);
#ifndef FMT_MAX
-#define FMT_MAX 256
+#define FMT_MAX 128
#endif
-#ifndef FMT_NOSHORTS
+#ifdef FMT_SHORTS
#define print(...) fmt_printd(stdout, __VA_ARGS__)
-#define println(...) fmt_printd((fmt_buffer*)0, __VA_ARGS__)
+#define println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__)
#define printd fmt_printd
#endif
#define fmt_print(...) fmt_printd(stdout, __VA_ARGS__)
-#define fmt_println(...) fmt_printd((fmt_buffer*)0, __VA_ARGS__)
+#define fmt_println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__)
#define fmt_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__)
/* Primary function. */
@@ -161,7 +165,7 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...); #define _fmt_fn(x) _Generic ((x), \
FILE*: fprintf, \
char*: sprintf, \
- fmt_buffer*: _fmt_bprint)
+ fmt_stream*: _fmt_bprint)
#if defined(_MSC_VER) && !defined(__clang__)
# define _signed_char_hhd
@@ -192,38 +196,46 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...); const wchar_t*: "ls", \
const void*: "p")
-#if defined FMT_IMPLEMENT || !(defined FMT_HEADER || defined FMT_IMPLEMENT)
+#if defined FMT_IMPLEMENT || defined i_implement
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
+#include <time.h>
+
+void fmt_close(fmt_stream* ss) {
+ free(ss->data);
+}
-FMT_API void fmt_destroy(fmt_buffer* buf) {
- free(buf->data);
+const char* fmt_tm(const char *fmt, const struct tm *tp) {
+ static char buf[2][64], i = 0;
+ i = !i;
+ strftime(buf[i], 64, fmt, tp);
+ return buf[i];
}
-FMT_API void _fmt_bprint(fmt_buffer* buf, const char* fmt, ...) {
+void _fmt_bprint(fmt_stream* ss, const char* fmt, ...) {
va_list args, args2;
va_start(args, fmt);
- if (buf == NULL) {
+ if (ss == NULL) {
vprintf(fmt, args); putchar('\n');
goto done1;
}
va_copy(args2, args);
const int n = vsnprintf(NULL, 0U, fmt, args);
if (n < 0) goto done2;
- const intptr_t pos = buf->stream ? buf->len : 0;
- buf->len = pos + n;
- if (buf->len > buf->cap) {
- buf->cap = buf->len + buf->cap/2;
- buf->data = (char*)realloc(buf->data, (size_t)buf->cap + 1U);
+ const intptr_t pos = ss->overwrite ? 0 : ss->len;
+ ss->len = pos + n;
+ if (ss->len > ss->cap) {
+ ss->cap = ss->len + ss->cap/2;
+ ss->data = (char*)realloc(ss->data, (size_t)ss->cap + 1U);
}
- vsprintf(buf->data + pos, fmt, args2);
+ vsprintf(ss->data + pos, fmt, args2);
done2: va_end(args2);
done1: va_end(args);
}
-FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) {
+int _fmt_parse(char* p, int nargs, const char *fmt, ...) {
char *arg, *p0, ch;
int n = 0, empty;
va_list args;
@@ -273,3 +285,4 @@ FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) { }
#endif
#endif
+#undef i_implement
diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index b0ecd6b7..3a5382f3 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -26,92 +26,226 @@ #include <stdio.h> #include <stc/algo/coroutine.h> -struct iterate { +struct iterpair { int max_x, max_y; int x, y; int cco_state; // required member }; -bool iterate(struct iterate* I) { - cco_begin(I); +int iterpair(struct iterpair* I) { + cco_routine(I) { for (I->x = 0; I->x < I->max_x; I->x++) for (I->y = 0; I->y < I->max_y; I->y++) - cco_yield(true); + cco_yield(); - cco_final: - puts("final"); - cco_end(false); + cco_cleanup: // required if there is cleanup code + puts("final"); + } + return 0; // CCO_DONE } int main(void) { - struct iterate it = {.max_x=3, .max_y=3}; + struct iterpair it = {.max_x=3, .max_y=3}; int n = 0; - while (iterate(&it)) + while (iterpair(&it)) { printf("%d %d\n", it.x, it.y); // example of early stop: - if (++n == 20) cco_stop(&it); // signal to stop at next + if (++n == 7) cco_stop(&it); // signal to stop/finalize in next } return 0; } */ -#include <stc/ccommon.h> +#include "../ccommon.h" enum { - cco_state_final = -1, - cco_state_done = -2, + CCO_STATE_CLEANUP = -1, + CCO_STATE_DONE = -2, }; +typedef enum { + CCO_DONE = 0, + CCO_YIELD = 1, + CCO_AWAIT = 2, + CCO_ERROR = -1, +} cco_result; + +#define cco_initial(co) ((co)->cco_state == 0) +#define cco_suspended(co) ((co)->cco_state > 0) +#define cco_done(co) ((co)->cco_state == CCO_STATE_DONE) + +#define cco_routine(co) \ + for (int *_state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ + _resume: switch (*_state) case 0: // thanks, @liigo! + +#define cco_yield() cco_yield_v(CCO_YIELD) +#define cco_yield_v(ret) \ + do { \ + *_state = __LINE__; return ret; goto _resume; \ + case __LINE__:; \ + } while (0) + +#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT) +#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__) +#define cco_await_v_1(promise) cco_await_v_2(promise, ) +#define cco_await_v_2(promise, ret) \ + do { \ + *_state = __LINE__; \ + case __LINE__: if (!(promise)) {return ret; goto _resume;} \ + } while (0) -#define cco_suspended(ctx) ((ctx)->cco_state > 0) -#define cco_alive(ctx) ((ctx)->cco_state != cco_state_done) +/* cco_await_on(): assumes coroutine returns a cco_result value (int) */ +#define cco_await_on(corocall) \ + do { \ + *_state = __LINE__; \ + case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \ + } while (0) -#define cco_begin(ctx) \ - int *_state = &(ctx)->cco_state; \ - switch (*_state) { \ - case 0: +/* cco_block_on(): assumes coroutine returns a cco_result value (int) */ +#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) +#define cco_block_on_1(corocall) while ((corocall) != CCO_DONE) +#define cco_block_on_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) -#define cco_end(retval) \ - *_state = cco_state_done; break; \ - case -99: goto _cco_final_; \ - } \ - return retval +#define cco_cleanup \ + *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP -#define cco_yield(...) c_MACRO_OVERLOAD(cco_yield, __VA_ARGS__) -#define cco_yield_1(retval) \ +#define cco_return \ do { \ - *_state = __LINE__; return retval; \ - case __LINE__:; \ + *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ + goto _resume; \ } while (0) -#define cco_yield_2(corocall2, ctx2) \ - cco_yield_3(corocall2, ctx2, ) +#define cco_yield_final() cco_yield_final_v(CCO_YIELD) +#define cco_yield_final_v(value) \ + do { \ + *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ + return value; \ + } while (0) -#define cco_yield_3(corocall2, ctx2, retval) \ +#define cco_stop(co) \ do { \ - *_state = __LINE__; \ - do { \ - corocall2; if (cco_suspended(ctx2)) return retval; \ - case __LINE__:; \ - } while (cco_alive(ctx2)); \ + int* _s = &(co)->cco_state; \ + if (*_s > 0) *_s = CCO_STATE_CLEANUP; \ + else if (*_s == 0) *_s = CCO_STATE_DONE; \ } while (0) -#define cco_final \ - case cco_state_final: \ - _cco_final_ +#define cco_reset(co) \ + (void)((co)->cco_state = 0) -#define cco_return \ - goto _cco_final_ +/* + * Closure (optional) + */ + +#define cco_closure(Name, ...) \ + struct Name { \ + int (*cco_fn)(struct Name*); \ + int cco_state; \ + __VA_ARGS__ \ + } + +typedef struct cco_base { + int (*cco_fn)(struct cco_base*); + int cco_state; +} cco_base; + +#define cco_resume(closure) \ + (closure)->cco_fn(closure) + +#define cco_cast(closure) \ + ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state))) + +/* + * Semaphore + */ -#define cco_stop(ctx) \ +typedef struct { intptr_t count; } cco_sem; + +#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT) +#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__) +#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, ) +#define cco_sem_await_v_2(sem, ret) \ do { \ - int* _state = &(ctx)->cco_state; \ - if (*_state > 0) *_state = cco_state_final; \ + cco_await_v_2((sem)->count > 0, ret); \ + --(sem)->count; \ } while (0) -#define cco_reset(ctx) \ +#define cco_sem_release(sem) ++(sem)->count +#define cco_sem_from(value) ((cco_sem){value}) +#define cco_sem_set(sem, value) ((sem)->count = value) + +/* + * Timer + */ + +#ifdef _WIN32 + #ifdef __cplusplus + #define _c_LINKC extern "C" __declspec(dllimport) + #else + #define _c_LINKC __declspec(dllimport) + #endif + struct _FILETIME; + _c_LINKC void GetSystemTimePreciseAsFileTime(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); + return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */ + } + + static inline void cco_sleep(double sec) { + Sleep((unsigned long)(sec*1000.0)); + } +#else + #include <sys/time.h> + static inline double cco_time(void) { /* seconds since epoch */ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec*1e-6; + } + + static inline void cco_sleep(double sec) { + struct timeval tv; + tv.tv_sec = (time_t)sec; + tv.tv_usec = (suseconds_t)((sec - (double)(long)sec)*1e6); + select(0, NULL, NULL, NULL, &tv); + } +#endif + +typedef struct { double interval, start; } cco_timer; + +#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT) +#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__) +#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, ) +#define cco_timer_await_v_3(tm, sec, ret) \ do { \ - int* _state = &(ctx)->cco_state; \ - if (*_state == cco_state_done) *_state = 0; \ + cco_timer_start(tm, sec); \ + cco_await_v_2(cco_timer_expired(tm), ret); \ } while (0) +static inline void cco_timer_start(cco_timer* tm, double sec) { + tm->interval = sec; + tm->start = cco_time(); +} + +static inline cco_timer cco_timer_from(double sec) { + cco_timer tm = {.interval=sec, .start=cco_time()}; + return tm; +} + +static inline void cco_timer_restart(cco_timer* tm) { + tm->start = cco_time(); +} + +static inline bool cco_timer_expired(cco_timer* tm) { + return cco_time() - tm->start >= tm->interval; +} + +static inline double cco_timer_elapsed(cco_timer* tm) { + return cco_time() - tm->start; +} + +static inline double cco_timer_remaining(cco_timer* tm) { + return tm->start + tm->interval - cco_time(); +} + #endif diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h index ca06c258..03162a2d 100644 --- a/include/stc/algo/crange.h +++ b/include/stc/algo/crange.h @@ -25,7 +25,7 @@ #include <stc/algo/filter.h> #include <stc/algo/crange.h> -int main() +int main(void) { crange r1 = crange_make(80, 90); c_foreach (i, crange, r1) @@ -34,7 +34,8 @@ int main() // use a temporary crange object. int a = 100, b = INT32_MAX; - c_forfilter (i, crange, crange_obj(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)) printf(" %lld", *i.ref); @@ -44,10 +45,7 @@ int main() #ifndef STC_CRANGE_H_INCLUDED #define STC_CRANGE_H_INCLUDED -#include <stc/ccommon.h> - -#define crange_obj(...) \ - (*(crange[]){crange_make(__VA_ARGS__)}) +#include "../ccommon.h" typedef long long crange_value; typedef struct { crange_value start, end, step, value; } crange; @@ -63,10 +61,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 deleted file mode 100644 index 53fe9fcc..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. - */ -#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] -#define i_less - less function. default: *x < *y -#define i_tag NAME - define csort_NAME(). default {i_val} - -// test: -#include <stdio.h> -#define i_val int -#include <stc/algo/csort.h> - -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(""); -} -*/ - -typedef i_val c_PASTE(c_CONCAT(csort_, i_tag), _value); - -static inline void c_PASTE(cisort_, i_tag)(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 c_PASTE(cqsort_, i_tag)(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) c_PASTE(cqsort_, i_tag)(arr, lo, j); - else if (j > lo) c_PASTE(cisort_, i_tag)(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); } - -#include "../priv/template2.h" diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h index e133577c..4a227927 100644 --- a/include/stc/algo/filter.h +++ b/include/stc/algo/filter.h @@ -26,9 +26,9 @@ #include <stc/cstack.h> #include <stc/calgo.h> -int main() +int main(void) { - 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); @@ -47,7 +47,7 @@ int main() #ifndef STC_FILTER_H_INCLUDED #define STC_FILTER_H_INCLUDED -#include <stc/ccommon.h> +#include "../ccommon.h" // c_forfilter: @@ -89,8 +89,7 @@ int main() // Use with: clist, cmap, cset, csmap, csset: #define c_erase_if(it, C, cnt, pred) do { \ C* _cnt = &cnt; \ - intptr_t _index = 0; \ - for (C##_iter it = C##_begin(_cnt); it.ref; ++_index) { \ + for (C##_iter it = C##_begin(_cnt); it.ref; ) { \ if (pred) it = C##_erase_at(_cnt, it); \ else C##_next(&it); \ } \ @@ -100,14 +99,14 @@ int main() // Use with: cstack, cvec, cdeq, cqueue: #define c_eraseremove_if(it, C, cnt, pred) do { \ C* _cnt = &cnt; \ - intptr_t _n = 0, _index = 0; \ + intptr_t _n = 0; \ C##_iter it = C##_begin(_cnt), _i; \ while (it.ref && !(pred)) \ - C##_next(&it), ++_index; \ - for (_i = it; it.ref; C##_next(&it), ++_index) \ + C##_next(&it); \ + for (_i = it; it.ref; C##_next(&it)) \ if (pred) C##_value_drop(it.ref), ++_n; \ else *_i.ref = *it.ref, C##_next(&_i); \ - _cnt->_len -= _n; \ + C##_adjust_end_(_cnt, -_n); \ } while (0) // ------------------------ private ------------------------- diff --git a/include/stc/algo/raii.h b/include/stc/algo/raii.h new file mode 100644 index 00000000..584f5c59 --- /dev/null +++ b/include/stc/algo/raii.h @@ -0,0 +1,51 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ +#ifndef STC_RAII_INCLUDED +#define STC_RAII_INCLUDED + +#define c_with(...) c_MACRO_OVERLOAD(c_with, __VA_ARGS__) +#define c_with_2(declvar, drop) \ + for (declvar, *_i, **_ip = &_i; _ip; _ip = 0, drop) +#define c_with_3(declvar, pred, drop) \ + for (declvar, *_i, **_ip = &_i; _ip && (pred); _ip = 0, drop) + +#define c_scope(...) c_MACRO_OVERLOAD(c_scope, __VA_ARGS__) +#define c_scope_2(init, drop) \ + for (int _i = (init, 1); _i; _i = 0, drop) +#define c_scope_3(init, pred, drop) \ + for (int _i = (init, 1); _i && (pred); _i = 0, drop) + +#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__) +#define c_auto_2(C, a) \ + c_with_2(C a = C##_init(), C##_drop(&a)) +#define c_auto_3(C, a, b) \ + c_with_2(c_EXPAND(C a = C##_init(), b = C##_init()), \ + (C##_drop(&b), C##_drop(&a))) +#define c_auto_4(C, a, b, c) \ + c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init()), \ + (C##_drop(&c), C##_drop(&b), C##_drop(&a))) +#define c_auto_5(C, a, b, c, d) \ + c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \ + (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a))) + +#endif diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h new file mode 100644 index 00000000..06d7395f --- /dev/null +++ b/include/stc/algo/sort.h @@ -0,0 +1,123 @@ +/* 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_key - value type [required] +#define i_less - less function. default: *x < *y +#define i_type name - define {{name}}_sort_n(), else {{i_key}}array_sort_n(). + +// ex1: +#include <stdio.h> +#define i_key int +#include <stc/algo/sort.h> + +int main(void) { + int nums[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21}; + + intarray_sort_n(nums, c_arraylen(nums)); + + for (int i = 0; i < c_arraylen(nums); i++) + printf(" %d", nums[i]); + puts(""); +} + +// ex2: +#define i_key int +#define i_type IDeq +#define i_more // retain input template params to be reused by sort.h +#include <stc/cdeq.h> +#include <stc/algo/sort.h> + +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); + + IDeq_sort_n(&nums, IDeq_size(&nums)); + + c_foreach (i, IDeq, nums) + printf(" %d", *i.ref); + IDeq_drop(&nums); +} +*/ +#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_key + #endif + #define i_type c_PASTE(i_tag, array) + typedef i_key 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_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; + } + *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_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_key, 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/calgo.h b/include/stc/calgo.h index 21e73faf..63ef97b9 100644 --- a/include/stc/calgo.h +++ b/include/stc/calgo.h @@ -1,6 +1,7 @@ #ifndef STC_CALGO_INCLUDED #define STC_CALGO_INCLUDED +#include "algo/raii.h" #include "algo/crange.h" #include "algo/filter.h" #include "algo/coroutine.h" diff --git a/include/stc/carc.h b/include/stc/carc.h index 8ef80b12..9ba2ddd1 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 <stc/cstr.h> typedef struct { cstr name, last; } Person; @@ -29,6 +30,11 @@ typedef struct { cstr name, last; } Person; Person Person_make(const char* name, const char* last) { return (Person){.name = cstr_from(name), .last = cstr_from(last)}; } +Person Person_clone(Person p) { + p.name = cstr_clone(p.name); + p.last = cstr_clone(p.last); + return p; +} void Person_drop(Person* p) { printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); cstr_drop(&p->name); @@ -36,11 +42,11 @@ void Person_drop(Person* p) { } #define i_type ArcPers -#define i_key Person -#define i_keydrop Person_drop +#define i_valclass Person // clone, drop, cmp, hash +#define i_opt c_no_cmp|c_no_hash // exclude cmp, hash #include <stc/carc.h> -int main() { +int main(void) { ArcPers p = ArcPers_from(Person_make("John", "Smiths")); ArcPers q = ArcPers_clone(p); // share the pointer @@ -48,10 +54,11 @@ int main() { c_drop(ArcPers, &p, &q); } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CARC_H_INCLUDED #define CARC_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include <stdlib.h> @@ -71,15 +78,11 @@ int main() { #define c_atomic_dec_and_test(v) (atomic_fetch_sub(v, 1) == 1) #endif -#define carc_NULL {NULL, NULL} +#define carc_null {0} #endif // CARC_H_INCLUDED -#ifndef _i_prefix #define _i_prefix carc_ -#endif -#ifdef i_eq -#define _i_eq -#endif +#define _i_carc #include "priv/template.h" typedef i_keyraw _cx_raw; @@ -91,123 +94,135 @@ typedef i_keyraw _cx_raw; #define _i_atomic_dec_and_test(v) !(--*(v)) #endif #ifndef i_is_forward -_cx_deftypes(_c_carc_types, _cx_self, i_key); +_cx_DEFTYPES(_c_carc_types, _cx_Self, i_key); #endif -struct _cx_memb(_rep_) { catomic_long counter; i_key value; }; +struct _cx_MEMB(_rep_) { catomic_long counter; i_key value; }; -STC_INLINE _cx_self _cx_memb(_init)(void) - { return c_LITERAL(_cx_self){NULL, NULL}; } +STC_INLINE _cx_Self _cx_MEMB(_init)(void) + { return c_LITERAL(_cx_Self){NULL, NULL}; } -STC_INLINE long _cx_memb(_use_count)(const _cx_self* self) +STC_INLINE long _cx_MEMB(_use_count)(const _cx_Self* self) { return self->use_count ? *self->use_count : 0; } -STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) { - _cx_self ptr = {p}; +STC_INLINE _cx_Self _cx_MEMB(_from_ptr)(_cx_value* p) { + _cx_Self ptr = {p}; if (p) *(ptr.use_count = _i_alloc(catomic_long)) = 1; return ptr; } // c++: std::make_shared<_cx_value>(val) -STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) { - _cx_self ptr; - struct _cx_memb(_rep_)* rep = _i_alloc(struct _cx_memb(_rep_)); +STC_INLINE _cx_Self _cx_MEMB(_make)(_cx_value val) { + _cx_Self ptr; + struct _cx_MEMB(_rep_)* rep = _i_alloc(struct _cx_MEMB(_rep_)); *(ptr.use_count = &rep->counter) = 1; *(ptr.get = &rep->value) = val; return ptr; } -STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self) +STC_INLINE _cx_raw _cx_MEMB(_toraw)(const _cx_Self* self) { return i_keyto(self->get); } -STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) { - _cx_self ptr = *self; +STC_INLINE _cx_Self _cx_MEMB(_move)(_cx_Self* self) { + _cx_Self ptr = *self; self->get = NULL, self->use_count = NULL; return ptr; } -STC_INLINE void _cx_memb(_drop)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) { if (self->use_count && _i_atomic_dec_and_test(self->use_count)) { i_keydrop(self->get); - if ((char *)self->get != (char *)self->use_count + offsetof(struct _cx_memb(_rep_), value)) + if ((char *)self->get != (char *)self->use_count + offsetof(struct _cx_MEMB(_rep_), value)) i_free(self->get); i_free((long*)self->use_count); } } -STC_INLINE void _cx_memb(_reset)(_cx_self* self) { - _cx_memb(_drop)(self); +STC_INLINE void _cx_MEMB(_reset)(_cx_Self* self) { + _cx_MEMB(_drop)(self); self->use_count = NULL, self->get = NULL; } -STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) { - _cx_memb(_drop)(self); - *self = _cx_memb(_from_ptr)(p); +STC_INLINE void _cx_MEMB(_reset_to)(_cx_Self* self, _cx_value* p) { + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_from_ptr)(p); } #ifndef i_no_emplace -STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw) - { return _cx_memb(_make)(i_keyfrom(raw)); } +STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_raw raw) + { return _cx_MEMB(_make)(i_keyfrom(raw)); } #else -STC_INLINE _cx_self _cx_memb(_from)(_cx_value val) - { return _cx_memb(_make)(val); } +STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_value val) + { return _cx_MEMB(_make)(val); } #endif // does not use i_keyclone, so OK to always define. -STC_INLINE _cx_self _cx_memb(_clone)(_cx_self ptr) { +STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self ptr) { if (ptr.use_count) _i_atomic_inc(ptr.use_count); return ptr; } // take ownership of unowned -STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) { - _cx_memb(_drop)(self); +STC_INLINE void _cx_MEMB(_take)(_cx_Self* self, _cx_Self unowned) { + _cx_MEMB(_drop)(self); *self = unowned; } // share ownership with ptr -STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self ptr) { +STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) { if (ptr.use_count) _i_atomic_inc(ptr.use_count); - _cx_memb(_drop)(self); + _cx_MEMB(_drop)(self); *self = ptr; } -#ifndef i_no_cmp -STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) - { return i_cmp(rx, ry); } +#if defined _i_has_cmp + STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) + { return i_cmp(rx, ry); } -STC_INLINE int _cx_memb(_cmp)(const _cx_self* self, const _cx_self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); -} -#endif + 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); } -#ifdef _i_eq -STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return i_eq(rx, ry); } + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } +#endif +#if defined _i_has_eq || defined _i_has_cmp + STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) + { return i_eq(rx, ry); } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); -} -#elif !defined i_no_cmp -STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return i_cmp(rx, ry) == 0; } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _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 _cx_memb(_cmp)(self, other) == 0; } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } #endif +#if defined i_hash + STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) + { return i_hash(rx); } -#ifndef i_no_hash -STC_INLINE uint64_t _cx_memb(_raw_hash)(const _cx_raw* rx) - { return i_hash(rx); } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { _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) - { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } #endif -#undef _i_eq #undef _i_atomic_inc #undef _i_atomic_dec_and_test #include "priv/template2.h" +#undef _i_carc diff --git a/include/stc/cbits.h b/include/stc/cbits.h index 9463c82c..3b5785d3 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -26,7 +26,7 @@ Similar to boost::dynamic_bitset / std::bitset #include <stdio.h> #include "cbits.h" -int main() { +int main(void) { cbits bset = cbits_with_size(23, true); cbits_reset(&bset, 9); cbits_resize(&bset, 43, false); @@ -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/cbox.h b/include/stc/cbox.h index ca88fc66..25d41b92 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -23,7 +23,9 @@ */ /* cbox: heap allocated boxed type +#define i_implement #include <stc/cstr.h> +#include <stc/algo/raii.h> // c_auto typedef struct { cstr name, email; } Person; @@ -40,11 +42,12 @@ void Person_drop(Person* p) { c_drop(cstr, &p->name, &p->email); } -#define i_keyclass Person // bind Person clone+drop fn's #define i_type PBox +#define i_valclass Person // bind Person clone+drop fn's +#define i_no_cmp // no cmp/hash is defined #include <stc/cbox.h> -int main() { +int main(void) { c_auto (PBox, p, q) { p = PBox_from(Person_from("John Smiths", "[email protected]")); @@ -56,142 +59,150 @@ int main() { } } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CBOX_H_INCLUDED #define CBOX_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include <stdlib.h> #include <string.h> -#define cbox_NULL {NULL} +#define cbox_null {0} #endif // CBOX_H_INCLUDED -#ifndef _i_prefix #define _i_prefix cbox_ -#endif -#ifdef i_eq -#define _i_eq -#endif +#define _i_cbox #include "priv/template.h" typedef i_keyraw _cx_raw; #ifndef i_is_forward -_cx_deftypes(_c_cbox_types, _cx_self, i_key); +_cx_DEFTYPES(_c_cbox_types, _cx_Self, i_key); #endif // constructors (take ownership) -STC_INLINE _cx_self _cx_memb(_init)(void) - { return c_LITERAL(_cx_self){NULL}; } +STC_INLINE _cx_Self _cx_MEMB(_init)(void) + { return c_LITERAL(_cx_Self){NULL}; } -STC_INLINE long _cx_memb(_use_count)(const _cx_self* self) +STC_INLINE long _cx_MEMB(_use_count)(const _cx_Self* self) { return (long)(self->get != NULL); } -STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) - { return c_LITERAL(_cx_self){p}; } +STC_INLINE _cx_Self _cx_MEMB(_from_ptr)(_cx_value* p) + { return c_LITERAL(_cx_Self){p}; } // c++: std::make_unique<i_key>(val) -STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) { - _cx_self ptr = {_i_alloc(_cx_value)}; +STC_INLINE _cx_Self _cx_MEMB(_make)(_cx_value val) { + _cx_Self ptr = {_i_alloc(_cx_value)}; *ptr.get = val; return ptr; } -STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self) +STC_INLINE _cx_raw _cx_MEMB(_toraw)(const _cx_Self* self) { return i_keyto(self->get); } // destructor -STC_INLINE void _cx_memb(_drop)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) { if (self->get) { i_keydrop(self->get); i_free(self->get); } } -STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) { - _cx_self ptr = *self; +STC_INLINE _cx_Self _cx_MEMB(_move)(_cx_Self* self) { + _cx_Self ptr = *self; self->get = NULL; return ptr; } -STC_INLINE _cx_value* _cx_memb(_release)(_cx_self* self) - { return _cx_memb(_move)(self).get; } +STC_INLINE _cx_value* _cx_MEMB(_release)(_cx_Self* self) + { return _cx_MEMB(_move)(self).get; } -STC_INLINE void _cx_memb(_reset)(_cx_self* self) { - _cx_memb(_drop)(self); +STC_INLINE void _cx_MEMB(_reset)(_cx_Self* self) { + _cx_MEMB(_drop)(self); self->get = NULL; } // take ownership of p -STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) { - _cx_memb(_drop)(self); +STC_INLINE void _cx_MEMB(_reset_to)(_cx_Self* self, _cx_value* p) { + _cx_MEMB(_drop)(self); self->get = p; } #ifndef i_no_emplace -STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw) - { return _cx_memb(_make)(i_keyfrom(raw)); } +STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_raw raw) + { return _cx_MEMB(_make)(i_keyfrom(raw)); } #else -STC_INLINE _cx_self _cx_memb(_from)(_cx_value val) - { return _cx_memb(_make)(val); } +STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_value val) + { return _cx_MEMB(_make)(val); } #endif #if !defined i_no_clone - STC_INLINE _cx_self _cx_memb(_clone)(_cx_self other) { + STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self other) { if (!other.get) return other; - _cx_self out = {_i_alloc(i_key)}; + _cx_Self out = {_i_alloc(i_key)}; *out.get = i_keyclone((*other.get)); return out; } #endif // !i_no_clone // take ownership of unowned -STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) { - _cx_memb(_drop)(self); +STC_INLINE void _cx_MEMB(_take)(_cx_Self* self, _cx_Self unowned) { + _cx_MEMB(_drop)(self); *self = unowned; } // transfer ownership from moved; set moved to NULL -STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self* moved) { +STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) { if (moved->get == self->get) return; - _cx_memb(_drop)(self); + _cx_MEMB(_drop)(self); *self = *moved; moved->get = NULL; } -#ifndef i_no_cmp -STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) - { return i_cmp(rx, ry); } +#if defined _i_has_cmp + STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) + { return i_cmp(rx, ry); } -STC_INLINE int _cx_memb(_cmp)(const _cx_self* self, const _cx_self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_cmp((&rx), (&ry)); -} -#endif + 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); } -#ifdef _i_eq -STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return i_eq(rx, ry); } + STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) { + return c_default_cmp(&self->get, &other->get); + } +#endif +#if defined _i_has_eq || defined _i_has_cmp + STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) + { return i_eq(rx, ry); } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); - return i_eq((&rx), (&ry)); -} -#elif !defined i_no_cmp -STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) - { return i_cmp(rx, ry) == 0; } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _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 _cx_memb(_cmp)(self, other) == 0; } + STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + return self->get == other->get; + } #endif +#if defined i_hash + STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx) + { return i_hash(rx); } -#ifndef i_no_hash -STC_INLINE uint64_t _cx_memb(_raw_hash)(const _cx_raw* rx) - { return i_hash(rx); } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { _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) - { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } + STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self) + { return c_default_hash(&self->get); } #endif - -#undef _i_eq #include "priv/template2.h" +#undef _i_cbox diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 38dc2bd9..1f9ea80d 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -29,18 +29,11 @@ #include <stdbool.h> #include <string.h> #include <assert.h> -#include "priv/altnames.h" -#include "priv/raii.h" typedef long long _llong; #define c_NPOS INTPTR_MAX #define c_ZI PRIiPTR #define c_ZU PRIuPTR -#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 @@ -64,7 +57,7 @@ typedef long long _llong; #define _c_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ _14, _15, _16, N, ...) N -#ifdef __cplusplus +#ifdef __cplusplus #include <new> #define _i_alloc(T) static_cast<T*>(i_malloc(c_sizeof(T))) #define _i_new(T, ...) new (_i_alloc(T)) T(__VA_ARGS__) @@ -76,27 +69,35 @@ 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)) #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_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 #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_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*: @@ -116,13 +117,10 @@ typedef long long _llong; #define c_no_clone (1<<2) #define c_no_emplace (1<<3) #define c_no_cmp (1<<4) -#define c_no_hash (1<<5) - +#define c_native_cmp (1<<5) +#define c_no_hash (1<<6) /* Function macros and others */ -#define c_make(C, ...) \ - C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) - #define c_litstrlen(literal) (c_sizeof("" literal) - 1) #define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a]) @@ -148,14 +146,14 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) { case 0: return 1; } const uint8_t *x = (const uint8_t*)key; - uint64_t h = *x, n = (uint64_t)len >> 3; + uint64_t h = (uint64_t)*x << 7, n = (uint64_t)len >> 3; len &= 7; while (n--) { memcpy(&u8, x, 8), x += 8; - h += u8*0xc6a4a7935bd1e99d; + h = (h ^ u8)*0xc6a4a7935bd1e99d; } - while (len--) h = (h << 10) - h - *x++; - return c_ROTL(h, 26) ^ h; + while (len--) h = (h ^ *x++)*0x100000001b3; + return h ^ c_ROTL(h, 26); } STC_INLINE uint64_t cstrhash(const char *str) @@ -174,6 +172,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_MAX == INT64_MAX + n |= n >> 32; + #endif + return n + 1; +} /* Control block macros */ #define c_foreach(...) c_MACRO_OVERLOAD(c_foreach, __VA_ARGS__) @@ -196,44 +204,46 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle, #define c_forrange_1(stop) c_forrange_3(_c_i, 0, stop) #define c_forrange_2(i, stop) c_forrange_3(i, 0, stop) #define c_forrange_3(i, start, stop) \ - for (long long i=start, _end=(long long)(stop); i < _end; ++i) + for (_llong i=start, _end=(_llong)(stop); i < _end; ++i) #define c_forrange_4(i, start, stop, step) \ - for (long long i=start, _inc=step, _end=(long long)(stop) - (_inc > 0) \ + for (_llong i=start, _inc=step, _end=(_llong)(stop) - (_inc > 0) \ ; (_inc > 0) ^ (i > _end); i += _inc) #ifndef __cplusplus + #define c_init(C, ...) \ + C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) #define c_forlist(it, T, ...) \ - for (struct {T* ref; int size, index;} \ - it = {.ref=(T[])__VA_ARGS__, .size=(int)(sizeof((T[])__VA_ARGS__)/sizeof(T))} \ - ; it.index < it.size; ++it.ref, ++it.index) + for (struct {T* ref; int size, index;} \ + it = {.ref=(T[])__VA_ARGS__, .size=(int)(sizeof((T[])__VA_ARGS__)/sizeof(T))} \ + ; it.index < it.size; ++it.ref, ++it.index) #else - #include <initializer_list> - #define c_forlist(it, T, ...) \ - for (struct {std::initializer_list<T> _il; std::initializer_list<T>::iterator data, ref; size_t size, index;} \ - it = {._il=__VA_ARGS__, .data=it._il.begin(), .ref=it.data, .size=it._il.size()} \ - ; it.index < it.size; ++it.ref, ++it.index) + #include <initializer_list> + template <class C, class T> + inline C _from_n(C (*func)(const T[], intptr_t), std::initializer_list<T> il) + { return func(&*il.begin(), il.size()); } + + #define c_init(C, ...) _from_n<C,C##_raw>(C##_from_n, __VA_ARGS__) + #define c_forlist(it, T, ...) \ + for (struct {std::initializer_list<T> _il; std::initializer_list<T>::iterator ref; size_t size, index;} \ + it = {._il=__VA_ARGS__, .ref=it._il.begin(), .size=it._il.size()} \ + ; it.index < it.size; ++it.ref, ++it.index) #endif +#define c_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) -#endif // CCOMMON_H_INCLUDED - -#undef STC_API -#undef STC_DEF - -#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \ - defined(i_implement) || defined(STC_IMPLEMENT)) - #define STC_API extern - #define STC_DEF -#else - #define i_static - #define STC_API static inline - #define STC_DEF static inline -#endif -#if defined(STC_EXTERN) - #define i_extern -#endif -#if defined(i_static) || defined(STC_IMPLEMENT) - #define i_implement +#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 <intrin.h> + #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi))) +#elif defined(__x86_64__) + #define c_umul128(a, b, lo, hi) \ + asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) #endif + +#endif // CCOMMON_H_INCLUDED diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index ff6e744f..056ef005 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -20,427 +20,176 @@ * 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 <stdlib.h> -#include <string.h> - -#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 +#define _pull _pull_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; +#undef _pop -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 +STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value); +STC_API _cx_iter _cx_MEMB(_insert_n)(_cx_Self* self, intptr_t idx, const _cx_value* arr, intptr_t n); +STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n); +STC_API void _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n); -#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_INLINE const _cx_value* +_cx_MEMB(_at)(const _cx_Self* self, intptr_t idx) + { return self->data + _cdeq_topos(self, idx); } -#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 _cx_value* +_cx_MEMB(_at_mut)(_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(_push_back)(_cx_Self* self, _cx_value val) + { return _cx_MEMB(_push)(self, val); } -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 void +_cx_MEMB(_pop_back)(_cx_Self* self) { + c_assert(!_cx_MEMB(_empty)(self)); + self->end = (self->end - 1) & self->capmask; + i_keydrop((self->data + self->end)); } -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 _cx_value _cx_MEMB(_pull_back)(_cx_Self* self) { // move back out of deq + c_assert(!_cx_MEMB(_empty)(self)); + self->end = (self->end - 1) & self->capmask; + return 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_at)(_cx_Self* self, _cx_iter it) { + _cx_MEMB(_erase_n)(self, _cdeq_toidx(self, it.pos), 1); + if (it.pos == self->end) it.ref = NULL; + return it; } + STC_INLINE _cx_iter -_cx_memb(_erase_range)(_cx_self* self, _cx_iter 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_API _cx_iter +_cx_MEMB(_emplace_n)(_cx_Self* self, intptr_t idx, const _cx_raw* raw, intptr_t n); + STC_INLINE _cx_value* -_cx_memb(_emplace_front)(_cx_self* self, _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_INLINE _cx_iter -_cx_memb(_find)(const _cx_self* self, _cx_raw raw) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw); +_cx_MEMB(_find)(const _cx_Self* self, _cx_raw raw) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw); } STC_INLINE const _cx_value* -_cx_memb(_get)(const _cx_self* self, _cx_raw raw) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw).ref; +_cx_MEMB(_get)(const _cx_Self* self, _cx_raw raw) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw).ref; } STC_INLINE _cx_value* -_cx_memb(_get_mut)(_cx_self* self, _cx_raw raw) - { return (_cx_value *) _cx_memb(_get)(self, raw); } - -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; -} +_cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw raw) + { return (_cx_value *) _cx_MEMB(_get)(self, raw); } #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); -} +#if defined(i_implement) || defined(i_static) 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 i = len - 1, j = i + n; i >= idx; --i, --j) + *_cx_MEMB(_at_mut)(self, j) = *_cx_MEMB(_at)(self, i); + + self->end = (self->end + n) & self->capmask; + it.pos = _cdeq_topos(self, idx); + it.ref = self->data + it.pos; return it; } 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 +#endif -#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) { +_cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { + for (; i1.pos != i2.pos; _cx_MEMB(_next)(&i1)) { const _cx_raw r = i_keyto(i1.ref); if (i_eq((&raw), (&r))) - 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)); -} -#endif // !c_no_cmp -#endif // !_i_queue #endif // IMPLEMENTATION #define CDEQ_H_INCLUDED #include "priv/template2.h" diff --git a/include/stc/clist.h b/include/stc/clist.h index f7fb4152..d7cf30b9 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -32,7 +32,7 @@ #define i_tag ix #include <stc/clist.h> - int main() + int main(void) { c_auto (clist_ix, list) { @@ -51,9 +51,10 @@ } } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CLIST_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include <stdlib.h> #include <string.h> @@ -77,82 +78,81 @@ #endif // CLIST_H_INCLUDED -#ifndef _i_prefix #define _i_prefix clist_ -#endif #include "priv/template.h" #ifndef i_is_forward - _cx_deftypes(_c_clist_types, _cx_self, i_key); + _cx_DEFTYPES(_c_clist_types, _cx_Self, i_key); #endif -_cx_deftypes(_c_clist_complete_types, _cx_self, dummy); +_cx_DEFTYPES(_c_clist_complete_types, _cx_Self, dummy); typedef i_keyraw _cx_raw; -STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value); -STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value); -STC_API _cx_iter _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value); -STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it); -STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2); -#if !defined i_no_cmp || defined _i_has_eq -STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val); -STC_API intptr_t _cx_memb(_remove)(_cx_self* self, _cx_raw val); +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API _cx_value* _cx_MEMB(_push_back)(_cx_Self* self, i_key value); +STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value); +STC_API _cx_iter _cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, i_key value); +STC_API _cx_iter _cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it); +STC_API _cx_iter _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2); +#if defined _i_has_eq || defined _i_has_cmp +STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val); +STC_API intptr_t _cx_MEMB(_remove)(_cx_Self* self, _cx_raw val); #endif -#ifndef i_no_cmp -STC_API bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, const _cx_value*)); -STC_API int _cx_memb(_sort_cmp_)(const _cx_value*, const _cx_value*); -STC_INLINE bool _cx_memb(_sort)(_cx_self* self) - { return _cx_memb(_sort_with)(self, _cx_memb(_sort_cmp_)); } +#if defined _i_has_cmp +STC_API bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*)); +STC_API int _cx_MEMB(_sort_cmp_)(const _cx_value*, const _cx_value*); +STC_INLINE bool _cx_MEMB(_sort)(_cx_Self* self) + { return _cx_MEMB(_sort_with)(self, _cx_MEMB(_sort_cmp_)); } #endif -STC_API void _cx_memb(_reverse)(_cx_self* self); -STC_API _cx_iter _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other); -STC_API _cx_self _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2); -STC_API _cx_value* _cx_memb(_push_back_node)(_cx_self* self, _cx_node* node); -STC_API _cx_value* _cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node); -STC_API _cx_node* _cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref); -STC_API void _cx_memb(_erase_after_node)(_cx_self* self, _cx_node* ref); -STC_INLINE _cx_node* _cx_memb(_get_node)(_cx_value* vp) { return _clist_tonode(vp); } - +STC_API void _cx_MEMB(_reverse)(_cx_Self* self); +STC_API _cx_iter _cx_MEMB(_splice)(_cx_Self* self, _cx_iter it, _cx_Self* other); +STC_API _cx_Self _cx_MEMB(_split_off)(_cx_Self* self, _cx_iter it1, _cx_iter it2); +STC_API _cx_value* _cx_MEMB(_push_back_node)(_cx_Self* self, _cx_node* node); +STC_API _cx_value* _cx_MEMB(_insert_after_node)(_cx_Self* self, _cx_node* ref, _cx_node* node); +STC_API _cx_node* _cx_MEMB(_unlink_after_node)(_cx_Self* self, _cx_node* ref); +STC_API void _cx_MEMB(_erase_after_node)(_cx_Self* self, _cx_node* ref); +STC_INLINE _cx_node* _cx_MEMB(_get_node)(_cx_value* pval) { return _clist_tonode(pval); } +STC_INLINE _cx_node* _cx_MEMB(_unlink_front_node)(_cx_Self* self) + { return _cx_MEMB(_unlink_after_node)(self, self->last); } #if !defined i_no_clone -STC_API _cx_self _cx_memb(_clone)(_cx_self cx); -STC_INLINE i_key _cx_memb(_value_clone)(i_key val) { return i_keyclone(val); } +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); +STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val) { return i_keyclone(val); } STC_INLINE void -_cx_memb(_copy)(_cx_self *self, const _cx_self* other) { +_cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { if (self->last == other->last) return; - _cx_memb(_drop)(self); *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); *self = _cx_MEMB(_clone)(*other); } #endif // !i_no_clone #if !defined i_no_emplace -STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push_back)(self, i_keyfrom(raw)); } -STC_INLINE _cx_value* _cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push_front)(self, i_keyfrom(raw)); } -STC_INLINE _cx_iter _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) - { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); } -STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) - { return _cx_memb(_push_back)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_MEMB(_emplace_back)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push_back)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_MEMB(_emplace_front)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push_front)(self, i_keyfrom(raw)); } +STC_INLINE _cx_iter _cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, _cx_raw raw) + { return _cx_MEMB(_insert_at)(self, it, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push_back)(self, i_keyfrom(raw)); } #endif // !i_no_emplace -STC_INLINE _cx_self _cx_memb(_init)(void) { return c_LITERAL(_cx_self){NULL}; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_memb(_push_back)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } -STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) { (void)(self + n); return true; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return self->last == NULL; } -STC_INLINE void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_drop)(self); } -STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, i_key value) - { return _cx_memb(_push_back)(self, value); } -STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) - { assert(!_cx_memb(_empty)(self)); _cx_memb(_erase_after_node)(self, self->last); } -STC_INLINE _cx_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_Self _cx_MEMB(_init)(void) { return c_LITERAL(_cx_Self){NULL}; } +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push_back)(self, i_keyfrom(*raw++)); } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } +STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t n) { (void)(self + n); return true; } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return self->last == NULL; } +STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) { _cx_MEMB(_drop)(self); } +STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value) + { return _cx_MEMB(_push_back)(self, value); } +STC_INLINE void _cx_MEMB(_pop_front)(_cx_Self* self) + { 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); } +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* pval) { i_keydrop(pval); } STC_INLINE intptr_t -_cx_memb(_count)(const _cx_self* self) { +_cx_MEMB(_count)(const _cx_Self* self) { intptr_t n = 1; const _cx_node *node = self->last; if (!node) return 0; while ((node = node->next) != self->last) ++n; @@ -160,53 +160,53 @@ _cx_memb(_count)(const _cx_self* self) { } STC_INLINE _cx_iter -_cx_memb(_begin)(const _cx_self* self) { +_cx_MEMB(_begin)(const _cx_Self* self) { _cx_value* head = self->last ? &self->last->next->value : NULL; return c_LITERAL(_cx_iter){head, &self->last, self->last}; } STC_INLINE _cx_iter -_cx_memb(_end)(const _cx_self* self) +_cx_MEMB(_end)(const _cx_Self* self) { return c_LITERAL(_cx_iter){NULL}; } STC_INLINE void -_cx_memb(_next)(_cx_iter* it) { +_cx_MEMB(_next)(_cx_iter* it) { _cx_node* node = it->prev = _clist_tonode(it->ref); it->ref = (node == *it->_last ? NULL : &node->next->value); } STC_INLINE _cx_iter -_cx_memb(_advance)(_cx_iter it, size_t n) { - while (n-- && it.ref) _cx_memb(_next)(&it); +_cx_MEMB(_advance)(_cx_iter it, size_t n) { + while (n-- && it.ref) _cx_MEMB(_next)(&it); return it; } STC_INLINE _cx_iter -_cx_memb(_splice_range)(_cx_self* self, _cx_iter it, - _cx_self* other, _cx_iter it1, _cx_iter it2) { - _cx_self tmp = _cx_memb(_split_off)(other, it1, it2); - return _cx_memb(_splice)(self, it, &tmp); +_cx_MEMB(_splice_range)(_cx_Self* self, _cx_iter it, + _cx_Self* other, _cx_iter it1, _cx_iter it2) { + _cx_Self tmp = _cx_MEMB(_split_off)(other, it1, it2); + return _cx_MEMB(_splice)(self, it, &tmp); } -#if !defined i_no_cmp || defined _i_has_eq +#if defined _i_has_eq || defined _i_has_cmp STC_INLINE _cx_iter -_cx_memb(_find)(const _cx_self* self, _cx_raw val) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val); +_cx_MEMB(_find)(const _cx_Self* self, _cx_raw val) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val); } STC_INLINE const _cx_value* -_cx_memb(_get)(const _cx_self* self, _cx_raw val) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref; +_cx_MEMB(_get)(const _cx_Self* self, _cx_raw val) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val).ref; } STC_INLINE _cx_value* -_cx_memb(_get_mut)(_cx_self* self, _cx_raw val) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref; +_cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw val) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val).ref; } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - _cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other); - for (; i.ref && j.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) { +STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + _cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other); + for (; i.ref && j.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) { const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); if (!(i_eq((&_rx), (&_ry)))) return false; } @@ -215,32 +215,32 @@ STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { #endif // -------------------------- IMPLEMENTATION ------------------------- -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) #if !defined i_no_clone -STC_DEF _cx_self -_cx_memb(_clone)(_cx_self cx) { - _cx_self out = _cx_memb(_init)(); - c_foreach (it, _cx_self, cx) - _cx_memb(_push_back)(&out, i_keyclone((*it.ref))); +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self cx) { + _cx_Self out = _cx_MEMB(_init)(); + c_foreach (it, _cx_Self, cx) + _cx_MEMB(_push_back)(&out, i_keyclone((*it.ref))); return out; } #endif STC_DEF void -_cx_memb(_drop)(_cx_self* self) { - while (self->last) _cx_memb(_erase_after_node)(self, self->last); +_cx_MEMB(_drop)(_cx_Self* self) { + while (self->last) _cx_MEMB(_erase_after_node)(self, self->last); } STC_DEF _cx_value* -_cx_memb(_push_back)(_cx_self* self, i_key value) { +_cx_MEMB(_push_back)(_cx_Self* self, i_key value) { _c_clist_insert_entry_after(self->last, value); self->last = entry; return &entry->value; } STC_DEF _cx_value* -_cx_memb(_push_front)(_cx_self* self, i_key value) { +_cx_MEMB(_push_front)(_cx_Self* self, i_key value) { _c_clist_insert_entry_after(self->last, value); if (!self->last) self->last = entry; @@ -248,14 +248,14 @@ _cx_memb(_push_front)(_cx_self* self, i_key value) { } STC_DEF _cx_value* -_cx_memb(_push_back_node)(_cx_self* self, _cx_node* node) { +_cx_MEMB(_push_back_node)(_cx_Self* self, _cx_node* node) { _c_clist_insert_after_node(self->last, node); self->last = node; return &node->value; } STC_DEF _cx_value* -_cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node) { +_cx_MEMB(_insert_after_node)(_cx_Self* self, _cx_node* ref, _cx_node* node) { _c_clist_insert_after_node(ref, node); if (!self->last) self->last = node; @@ -263,7 +263,7 @@ _cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node) { } STC_DEF _cx_iter -_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) { +_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, i_key value) { _cx_node* node = it.ref ? it.prev : self->last; _c_clist_insert_entry_after(node, value); if (!self->last || !it.ref) { @@ -275,32 +275,32 @@ _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) { } STC_DEF _cx_iter -_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { +_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) { _cx_node *node = _clist_tonode(it.ref); it.ref = (node == self->last) ? NULL : &node->next->value; - _cx_memb(_erase_after_node)(self, it.prev); + _cx_MEMB(_erase_after_node)(self, it.prev); return it; } STC_DEF _cx_iter -_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { +_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) { _cx_node *end = it2.ref ? _clist_tonode(it2.ref) : self->last->next; if (it1.ref != it2.ref) do { - _cx_memb(_erase_after_node)(self, it1.prev); + _cx_MEMB(_erase_after_node)(self, it1.prev); if (!self->last) break; } while (it1.prev->next != end); return it2; } STC_DEF void -_cx_memb(_erase_after_node)(_cx_self* self, _cx_node* ref) { - _cx_node* node = _cx_memb(_unlink_after_node)(self, ref); +_cx_MEMB(_erase_after_node)(_cx_Self* self, _cx_node* ref) { + _cx_node* node = _cx_MEMB(_unlink_after_node)(self, ref); i_keydrop((&node->value)); i_free(node); } STC_DEF _cx_node* -_cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref) { +_cx_MEMB(_unlink_after_node)(_cx_Self* self, _cx_node* ref) { _cx_node* node = ref->next, *next = node->next; ref->next = next; if (node == next) @@ -311,17 +311,17 @@ _cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref) { } STC_DEF void -_cx_memb(_reverse)(_cx_self* self) { - _cx_self rev = {NULL}; +_cx_MEMB(_reverse)(_cx_Self* self) { + _cx_Self rev = {NULL}; while (self->last) { - _cx_node* node = _cx_memb(_unlink_after_node)(self, self->last); - _cx_memb(_insert_after_node)(&rev, rev.last, node); + _cx_node* node = _cx_MEMB(_unlink_after_node)(self, self->last); + _cx_MEMB(_insert_after_node)(&rev, rev.last, node); } *self = rev; } STC_DEF _cx_iter -_cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) { +_cx_MEMB(_splice)(_cx_Self* self, _cx_iter it, _cx_Self* other) { if (!self->last) self->last = other->last; else if (other->last) { @@ -335,9 +335,9 @@ _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) { return it; } -STC_DEF _cx_self -_cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) { - _cx_self lst = {NULL}; +STC_DEF _cx_Self +_cx_MEMB(_split_off)(_cx_Self* self, _cx_iter it1, _cx_iter it2) { + _cx_Self lst = {NULL}; if (it1.ref == it2.ref) return lst; _cx_node *p1 = it1.prev, @@ -350,11 +350,10 @@ _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) { return lst; } -#if !defined i_no_cmp || defined _i_has_eq - +#if defined _i_has_eq || defined _i_has_cmp STC_DEF _cx_iter -_cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) { - c_foreach (it, _cx_self, it1, it2) { +_cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) { + c_foreach (it, _cx_Self, it1, it2) { _cx_raw r = i_keyto(it.ref); if (i_eq((&r), (&val))) return it; @@ -363,14 +362,14 @@ _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) { } STC_DEF intptr_t -_cx_memb(_remove)(_cx_self* self, _cx_raw val) { +_cx_MEMB(_remove)(_cx_Self* self, _cx_raw val) { intptr_t n = 0; _cx_node *prev = self->last, *node; if (prev) do { node = prev->next; _cx_raw r = i_keyto((&node->value)); if (i_eq((&r), (&val))) { - _cx_memb(_erase_after_node)(self, prev), ++n; + _cx_MEMB(_erase_after_node)(self, prev), ++n; if (!self->last) break; } else prev = node; @@ -379,17 +378,17 @@ _cx_memb(_remove)(_cx_self* self, _cx_raw val) { } #endif -#ifndef i_no_cmp -STC_DEF int _cx_memb(_sort_cmp_)(const _cx_value* x, const _cx_value* y) { +#if defined _i_has_cmp +STC_DEF int _cx_MEMB(_sort_cmp_)(const _cx_value* x, const _cx_value* y) { const _cx_raw a = i_keyto(x), b = i_keyto(y); return i_cmp((&a), (&b)); } -STC_DEF bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, const _cx_value*)) { +STC_DEF bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*)) { size_t len = 0, cap = 0; _cx_value *a = NULL, *p = NULL; _cx_iter i; - for (i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i)) { + for (i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i)) { if (len == cap) { if ((p = (_cx_value *)i_realloc(a, (cap += cap/2 + 4)*sizeof *a))) a = p; else { i_free(a); return false; } @@ -397,11 +396,11 @@ STC_DEF bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, co a[len++] = *i.ref; } qsort(a, len, sizeof *a, (int(*)(const void*, const void*))cmp); - for (i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i), ++p) + for (i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i), ++p) *i.ref = *p; i_free(a); return true; } -#endif // !c_no_cmp +#endif // _i_has_cmp #endif // i_implement #define CLIST_H_INCLUDED #include "priv/template2.h" diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 14782b71..513a8b93 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -47,43 +47,32 @@ int main(void) { cmap_ichar_drop(&m); } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CMAP_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include <stdlib.h> #include <string.h> -typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t; +struct chash_slot { uint8_t hashx; }; +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) -#endif -#define _i_ishash -#ifndef i_max_load_factor - #define i_max_load_factor 0.85f -#endif -#ifndef i_ssize - #define i_ssize int32_t - #define _i_size intptr_t - #define _i_expandby 1 #else - #define _i_expandby 2 - #define _i_size i_ssize + #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 - _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); + _cx_DEFTYPES(_c_chash_types, _cx_Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); #endif _i_MAP_ONLY( struct _cx_value { @@ -92,61 +81,60 @@ _i_MAP_ONLY( struct _cx_value { }; ) typedef i_keyraw _cx_keyraw; -typedef i_valraw _cx_memb(_rmapped); +typedef i_valraw _cx_MEMB(_rmapped); typedef _i_SET_ONLY( i_keyraw ) _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } ) _cx_raw; -STC_API _cx_self _cx_memb(_with_capacity)(_i_size cap); +STC_API _cx_Self _cx_MEMB(_with_capacity)(intptr_t cap); #if !defined i_no_clone -STC_API _cx_self _cx_memb(_clone)(_cx_self map); +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self map); #endif -STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API void _cx_memb(_clear)(_cx_self* self); -STC_API bool _cx_memb(_reserve)(_cx_self* self, _i_size capacity); -STC_API chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr); -STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey); -STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val); - -STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self map = {0}; return map; } -STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, self->size); } -STC_INLINE float _cx_memb(_max_load_factor)(const _cx_self* self) { return (float)(i_max_load_factor); } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* map) { return !map->size; } -STC_INLINE _i_size _cx_memb(_size)(const _cx_self* map) { return map->size; } -STC_INLINE _i_size _cx_memb(_bucket_count)(_cx_self* map) { return map->bucket_count; } -STC_INLINE _i_size _cx_memb(_capacity)(const _cx_self* map) - { return (_i_size)((float)map->bucket_count * (i_max_load_factor)); } -STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) - { return self->size && self->_hashx[_cx_memb(_bucket_)(self, &rkey).idx]; } +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API void _cx_MEMB(_clear)(_cx_Self* self); +STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t capacity); +STC_API chash_bucket _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr); +STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey); +STC_API void _cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* val); +STC_API float _cx_MEMB(_max_load_factor)(const _cx_Self* self); +STC_API intptr_t _cx_MEMB(_capacity)(const _cx_Self* map); + +STC_INLINE _cx_Self _cx_MEMB(_init)(void) { _cx_Self map = {0}; return map; } +STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self) { _cx_MEMB(_reserve)(self, (intptr_t)self->size); } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* map) { return !map->size; } +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* map) { return (intptr_t)map->size; } +STC_INLINE intptr_t _cx_MEMB(_bucket_count)(_cx_Self* map) { return map->bucket_count; } +STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey) + { return self->size && _cx_MEMB(_bucket_)(self, &rkey).found; } #ifndef _i_isset - STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped); + STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped); #if !defined i_no_emplace - STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped); + STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped); #endif STC_INLINE const _cx_mapped* - _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey) { - chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); - assert(self->_hashx[b.idx]); - return &self->table[b.idx].second; + _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; } STC_INLINE _cx_mapped* - _cx_memb(_at_mut)(_cx_self* self, _cx_keyraw rkey) - { return (_cx_mapped*)_cx_memb(_at)(self, rkey); } + _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey) + { return (_cx_mapped*)_cx_MEMB(_at)(self, rkey); } #endif // !_i_isset #if !defined i_no_clone -STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) { - if (self->table == other->table) +STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { + if (self->data == other->data) return; - _cx_memb(_drop)(self); - *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); } STC_INLINE _cx_value -_cx_memb(_value_clone)(_cx_value _val) { +_cx_MEMB(_value_clone)(_cx_value _val) { *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val))); _i_MAP_ONLY( _val.second = i_valclone(_val.second); ) return _val; @@ -155,8 +143,8 @@ _cx_memb(_value_clone)(_cx_value _val) { #if !defined i_no_emplace STC_INLINE _cx_result -_cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { - _cx_result _res = _cx_memb(_insert_entry_)(self, rkey); +_cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey); if (_res.inserted) { *_i_keyref(_res.ref) = i_keyfrom(rkey); _i_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); ) @@ -165,21 +153,19 @@ _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe } #endif // !i_no_emplace -STC_INLINE _cx_raw -_cx_memb(_value_toraw)(const _cx_value* val) { +STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) { return _i_SET_ONLY( i_keyto(val) ) _i_MAP_ONLY( c_LITERAL(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} ); } -STC_INLINE void -_cx_memb(_value_drop)(_cx_value* _val) { +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* _val) { i_keydrop(_i_keyref(_val)); _i_MAP_ONLY( i_valdrop((&_val->second)); ) } STC_INLINE _cx_result -_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); +_cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); if (_res.inserted) { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} else @@ -187,157 +173,150 @@ _cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { return _res; } -STC_INLINE _cx_result -_cx_memb(_push)(_cx_self* self, _cx_value _val) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); +STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value _val) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); if (_res.inserted) *_res.ref = _val; else - _cx_memb(_value_drop)(&_val); - return _res; + _cx_MEMB(_value_drop)(&_val); + return _res.ref; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) { +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) { while (n--) #if defined _i_isset && defined i_no_emplace - _cx_memb(_insert)(self, *raw++); + _cx_MEMB(_insert)(self, *raw++); #elif defined _i_isset - _cx_memb(_emplace)(self, *raw++); + _cx_MEMB(_emplace)(self, *raw++); #elif defined i_no_emplace - _cx_memb(_insert_or_assign)(self, raw->first, raw->second), ++raw; + _cx_MEMB(_insert_or_assign)(self, raw->first, raw->second), ++raw; #else - _cx_memb(_emplace_or_assign)(self, raw->first, raw->second), ++raw; + _cx_MEMB(_emplace_or_assign)(self, raw->first, raw->second), ++raw; #endif } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, _i_size n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } -STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { - _cx_iter it = {self->table, self->table+self->bucket_count, self->_hashx}; - if (it._hx) - while (*it._hx == 0) - ++it.ref, ++it._hx; - if (it.ref == it._end) it.ref = NULL; - return it; -} +STC_API _cx_iter _cx_MEMB(_begin)(const _cx_Self* self); -STC_INLINE _cx_iter -_cx_memb(_end)(const _cx_self* self) +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) { return c_LITERAL(_cx_iter){NULL}; } -STC_INLINE void -_cx_memb(_next)(_cx_iter* it) { - while ((++it->ref, *++it->_hx == 0)) ; +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { + while ((++it->ref, (++it->sref)->hashx == 0)) ; if (it->ref == it->_end) it->ref = NULL; } -STC_INLINE _cx_iter -_cx_memb(_advance)(_cx_iter it, size_t n) { - while (n-- && it.ref) _cx_memb(_next)(&it); +STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) { + while (n-- && it.ref) _cx_MEMB(_next)(&it); return it; } STC_INLINE _cx_iter -_cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) { - int64_t idx; - if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]) - return c_LITERAL(_cx_iter){self->table + idx, - self->table + self->bucket_count, - self->_hashx + idx}; - return _cx_memb(_end)(self); +_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, + self->data + self->bucket_count, + self->slot + b.idx}; + return _cx_MEMB(_end)(self); } STC_INLINE const _cx_value* -_cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey) { - int64_t idx; - if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]) - return self->table + idx; +_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; return NULL; } STC_INLINE _cx_value* -_cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey) - { return (_cx_value*)_cx_memb(_get)(self, rkey); } +_cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey) + { return (_cx_value*)_cx_MEMB(_get)(self, rkey); } STC_INLINE int -_cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { - if (self->size == 0) - return 0; - chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); - return self->_hashx[b.idx] ? _cx_memb(_erase_entry)(self, self->table + b.idx), 1 : 0; +_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; } STC_INLINE _cx_iter -_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { - _cx_memb(_erase_entry)(self, it.ref); - if (*it._hx == 0) - _cx_memb(_next)(&it); +_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) { + _cx_MEMB(_erase_entry)(self, it.ref); + if (it.sref->hashx == 0) + _cx_MEMB(_next)(&it); return it; } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; - for (_cx_iter i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i)) { +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; + for (_cx_iter i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i)) { const _cx_keyraw _raw = i_keyto(_i_keyref(i.ref)); - if (!_cx_memb(_contains)(other, _raw)) return false; + if (!_cx_MEMB(_contains)(other, _raw)) return false; } return true; } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) +#ifndef i_max_load_factor + #define i_max_load_factor 0.80f +#endif +#define fastrange_2(x, n) (intptr_t)((x) & (size_t)((n) - 1)) // n power of 2. -#ifndef CMAP_H_INCLUDED -STC_INLINE int64_t fastrange_1(uint64_t x, uint64_t n) - { return (int64_t)((uint32_t)x*n >> 32); } // n < 2^32 - -STC_INLINE int64_t fastrange_2(uint64_t x, uint64_t n) - { return (int64_t)(x & (n - 1)); } // n power of 2. - -STC_INLINE uint64_t next_power_of_2(uint64_t n) { - n--; - n |= n >> 1, n |= n >> 2; - n |= n >> 4, n |= n >> 8; - n |= n >> 16, n |= n >> 32; - return n + 1; +STC_DEF _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { + _cx_iter it = {self->data, self->data+self->bucket_count, self->slot}; + if (it.sref) + while (it.sref->hashx == 0) + ++it.ref, ++it.sref; + if (it.ref == it._end) it.ref = NULL; + return it; +} + +STC_DEF float _cx_MEMB(_max_load_factor)(const _cx_Self* self) { + return (float)(i_max_load_factor); +} + +STC_DEF intptr_t _cx_MEMB(_capacity)(const _cx_Self* map) { + return (intptr_t)((float)map->bucket_count * (i_max_load_factor)); } -#endif // CMAP_H_INCLUDED -STC_DEF _cx_self -_cx_memb(_with_capacity)(const _i_size cap) { - _cx_self h = {0}; - _cx_memb(_reserve)(&h, cap); - return h; +STC_DEF _cx_Self _cx_MEMB(_with_capacity)(const intptr_t cap) { + _cx_Self map = {0}; + _cx_MEMB(_reserve)(&map, cap); + return map; } -STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_wipe_)(_cx_Self* self) { if (self->size == 0) return; - _cx_value* e = self->table, *end = e + self->bucket_count; - uint8_t *hx = self->_hashx; - for (; e != end; ++e) - if (*hx++) - _cx_memb(_value_drop)(e); + _cx_value* d = self->data, *_end = d + self->bucket_count; + chash_slot* s = self->slot; + for (; d != _end; ++d) + if ((s++)->hashx) + _cx_MEMB(_value_drop)(d); } -STC_DEF void _cx_memb(_drop)(_cx_self* self) { - _cx_memb(_wipe_)(self); - i_free(self->_hashx); - i_free((void *) self->table); +STC_DEF void _cx_MEMB(_drop)(_cx_Self* self) { + _cx_MEMB(_wipe_)(self); + i_free(self->slot); + i_free(self->data); } -STC_DEF void _cx_memb(_clear)(_cx_self* self) { - _cx_memb(_wipe_)(self); +STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) { + _cx_MEMB(_wipe_)(self); self->size = 0; - c_memset(self->_hashx, 0, self->bucket_count); + c_memset(self->slot, 0, c_sizeof(chash_slot)*self->bucket_count); } #ifndef _i_isset STC_DEF _cx_result - _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); + _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); _cx_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped; if (_res.inserted) _res.ref->first = _key; @@ -349,8 +328,8 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) { #if !defined i_no_emplace STC_DEF _cx_result - _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped) { - _cx_result _res = _cx_memb(_insert_entry_)(self, rkey); + _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey); if (_res.inserted) _res.ref->first = i_keyfrom(rkey); else { @@ -363,120 +342,118 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) { #endif // !i_no_emplace #endif // !_i_isset -STC_DEF chash_bucket_t -_cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { +STC_DEF chash_bucket +_cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); - int64_t _cap = self->bucket_count; - chash_bucket_t b = {c_PASTE(fastrange_,_i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; - const uint8_t* _hx = self->_hashx; - while (_hx[b.idx]) { - if (_hx[b.idx] == b.hx) { - const _cx_keyraw _raw = i_keyto(_i_keyref(self->table + b.idx)); - if (i_eq((&_raw), rkeyptr)) + intptr_t _cap = self->bucket_count; + chash_bucket b = {fastrange_2(_hash, _cap), (uint8_t)(_hash | 0x80)}; + const chash_slot* s = self->slot; + while (s[b.idx].hashx) { + if (s[b.idx].hashx == b.hashx) { + const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + b.idx)); + if (i_eq((&_raw), rkeyptr)) { + b.found = true; break; + } } - if (++b.idx == _cap) - b.idx = 0; + if (++b.idx == _cap) b.idx = 0; } return b; } STC_DEF _cx_result -_cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { _cx_result res = {NULL}; - if (self->size + 2 > (i_ssize)((float)self->bucket_count * (i_max_load_factor))) - if (!_cx_memb(_reserve)(self, self->size*3/2)) + if (self->size >= (intptr_t)((float)self->bucket_count * (i_max_load_factor))) + if (!_cx_MEMB(_reserve)(self, (intptr_t)(self->size*3/2 + 2))) return res; - chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); - res.ref = &self->table[b.idx]; - if ((res.inserted = !self->_hashx[b.idx])) { - self->_hashx[b.idx] = b.hx; + chash_bucket b = _cx_MEMB(_bucket_)(self, &rkey); + res.ref = &self->data[b.idx]; + if (!b.found) { + self->slot[b.idx].hashx = b.hashx; + res.inserted = true; ++self->size; } return res; } #if !defined i_no_clone -STC_DEF _cx_self -_cx_memb(_clone)(_cx_self m) { - if (m.table) { - _cx_value *t = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count), - *dst = t, *m_end = m.table + m.bucket_count; - uint8_t *h = (uint8_t *)c_memcpy(i_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1); - if (!(t && h)) - { i_free(t), i_free(h), t = 0, h = 0, m.bucket_count = 0; } +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self m) { + if (m.data) { + _cx_value *d = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count), + *_dst = d, *_end = m.data + m.bucket_count; + const intptr_t _mem = c_sizeof(chash_slot)*(m.bucket_count + 1); + chash_slot *s = (chash_slot *)c_memcpy(i_malloc(_mem), m.slot, _mem); + if (!(d && s)) + { i_free(d), i_free(s), d = 0, s = 0, m.bucket_count = 0; } else - for (; m.table != m_end; ++m.table, ++m._hashx, ++dst) - if (*m._hashx) - *dst = _cx_memb(_value_clone)(*m.table); - m.table = t, m._hashx = h; + for (; m.data != _end; ++m.data, ++m.slot, ++_dst) + if (m.slot->hashx) + *_dst = _cx_MEMB(_value_clone)(*m.data); + m.data = d, m.slot = s; } return m; } #endif STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const _i_size newcap) { - const i_ssize _oldbuckets = self->bucket_count, _newcap = (i_ssize)newcap; - if (_newcap != self->size && _newcap <= _oldbuckets) +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) { + const intptr_t _oldbucks = self->bucket_count; + if (_newcap != self->size && _newcap <= _oldbucks) return true; - i_ssize _nbuckets = (i_ssize)((float)_newcap / (i_max_load_factor)) + 4; - #if _i_expandby == 2 - _nbuckets = (i_ssize)next_power_of_2(_nbuckets); - #else - _nbuckets |= 1; - #endif - _cx_self m = { - (_cx_value *)i_malloc(c_sizeof(_cx_value)*_nbuckets), - (uint8_t *)i_calloc(_nbuckets + 1, 1), - self->size, _nbuckets, + intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4; + _newbucks = cnextpow2(_newbucks); + _cx_Self m = { + (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), + (chash_slot *)i_calloc(_newbucks + 1, sizeof(chash_slot)), + self->size, _newbucks }; - bool ok = m.table && m._hashx; - if (ok) { /* Rehash: */ - m._hashx[_nbuckets] = 0xff; - const _cx_value* e = self->table; - const uint8_t* h = self->_hashx; - for (i_ssize i = 0; i < _oldbuckets; ++i, ++e) if (*h++) { - _cx_keyraw r = i_keyto(_i_keyref(e)); - chash_bucket_t b = _cx_memb(_bucket_)(&m, &r); - m.table[b.idx] = *e; - m._hashx[b.idx] = b.hx; + bool ok = m.data && m.slot; + if (ok) { // Rehash: + m.slot[_newbucks].hashx = 0xff; + const _cx_value* d = self->data; + 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 } - c_swap(_cx_self, self, &m); + c_swap(_cx_Self, self, &m); } - i_free(m._hashx); - i_free(m.table); + i_free(m.slot); + i_free(m.data); return ok; } STC_DEF void -_cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { - i_ssize i = (i_ssize)(_val - self->table), j = i, k; - const i_ssize _cap = self->bucket_count; - _cx_value* _slot = self->table; - uint8_t* _hashx = self->_hashx; - _cx_memb(_value_drop)(_val); - for (;;) { /* delete without leaving tombstone */ - if (++j == _cap) - j = 0; - if (! _hashx[j]) +_cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* _val) { + _cx_value* d = self->data; + chash_slot* s = self->slot; + intptr_t i = _val - d, j = i, k; + const intptr_t _cap = self->bucket_count; + _cx_MEMB(_value_drop)(_val); + for (;;) { // delete without leaving tombstone + if (++j == _cap) j = 0; + if (! s[j].hashx) break; - const _cx_keyraw _raw = i_keyto(_i_keyref(_slot + j)); - k = (i_ssize)c_PASTE(fastrange_,_i_expandby)(i_hash((&_raw)), (uint64_t)_cap); - if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ - _slot[i] = _slot[j], _hashx[i] = _hashx[j], i = j; + const _cx_keyraw _raw = i_keyto(_i_keyref(d + j)); + k = fastrange_2(i_hash((&_raw)), _cap); + if ((j < i) ^ (k <= i) ^ (k > j)) { // is k outside (i, j]? + d[i] = d[j]; + s[i] = s[j]; + i = j; + } } - _hashx[i] = 0; + s[i].hashx = 0; --self->size; } - #endif // i_implement #undef i_max_load_factor -#undef _i_size #undef _i_isset #undef _i_ismap -#undef _i_ishash #undef _i_keyref #undef _i_MAP_ONLY #undef _i_SET_ONLY diff --git a/include/stc/cpque.h b/include/stc/cpque.h index b95b5020..ca51eeff 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -20,101 +20,99 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CPQUE_H_INCLUDED +#include "ccommon.h" #include <stdlib.h> #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); + _cx_DEFTYPES(_c_cpque_types, _cx_Self, i_key); #endif typedef i_keyraw _cx_raw; -STC_API void _cx_memb(_make_heap)(_cx_self* self); -STC_API void _cx_memb(_erase_at)(_cx_self* self, intptr_t idx); -STC_API void _cx_memb(_push)(_cx_self* self, _cx_value value); +STC_API void _cx_MEMB(_make_heap)(_cx_Self* self); +STC_API void _cx_MEMB(_erase_at)(_cx_Self* self, intptr_t idx); +STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value value); -STC_INLINE _cx_self _cx_memb(_init)(void) - { return c_LITERAL(_cx_self){NULL}; } +STC_INLINE _cx_Self _cx_MEMB(_init)(void) + { return c_LITERAL(_cx_Self){NULL}; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } -STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { +STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) { if (cap != self->_len && cap <= self->_cap) return true; _cx_value *d = (_cx_value *)i_realloc(self->data, cap*c_sizeof *d); return d ? (self->data = d, self->_cap = cap, true) : false; } -STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) - { _cx_memb(_reserve)(self, self->_len); } +STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self) + { _cx_MEMB(_reserve)(self, self->_len); } -STC_INLINE _cx_self _cx_memb(_with_capacity)(const intptr_t cap) { - _cx_self out = {NULL}; _cx_memb(_reserve)(&out, cap); +STC_INLINE _cx_Self _cx_MEMB(_with_capacity)(const intptr_t cap) { + _cx_Self out = {NULL}; _cx_MEMB(_reserve)(&out, cap); return out; } -STC_INLINE _cx_self _cx_memb(_with_size)(const intptr_t size, i_key null) { - _cx_self out = {NULL}; _cx_memb(_reserve)(&out, size); +STC_INLINE _cx_Self _cx_MEMB(_with_size)(const intptr_t size, i_key null) { + _cx_Self out = {NULL}; _cx_MEMB(_reserve)(&out, size); while (out._len < size) out.data[out._len++] = null; return out; } -STC_INLINE void _cx_memb(_clear)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) { intptr_t i = self->_len; self->_len = 0; while (i--) { i_keydrop((self->data + i)); } } -STC_INLINE void _cx_memb(_drop)(_cx_self* self) - { _cx_memb(_clear)(self); i_free(self->data); } +STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) + { _cx_MEMB(_clear)(self); i_free(self->data); } -STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* q) +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* q) { return q->_len; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* q) +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* q) { return !q->_len; } -STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* q) +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* q) { return q->_cap; } -STC_INLINE const _cx_value* _cx_memb(_top)(const _cx_self* self) +STC_INLINE const _cx_value* _cx_MEMB(_top)(const _cx_Self* self) { return &self->data[0]; } -STC_INLINE void _cx_memb(_pop)(_cx_self* self) - { assert(!_cx_memb(_empty)(self)); _cx_memb(_erase_at)(self, 0); } +STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) + { 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); +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self q); -STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) { +STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { if (self->data == other->data) return; - _cx_memb(_drop)(self); - *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); } -STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val) +STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val) { return i_keyclone(val); } #endif // !i_no_clone #if !defined i_no_emplace -STC_INLINE void _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) - { _cx_memb(_push)(self, i_keyfrom(raw)); } +STC_INLINE void _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) + { _cx_MEMB(_push)(self, i_keyfrom(raw)); } #endif // !i_no_emplace /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) STC_DEF void -_cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) { +_cx_MEMB(_sift_down_)(_cx_Self* self, const intptr_t idx, const intptr_t n) { _cx_value t, *arr = self->data - 1; for (intptr_t r = idx, c = idx*2; c <= n; c *= 2) { c += i_less((&arr[c]), (&arr[c + (c < n)])); @@ -124,15 +122,15 @@ _cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) { } STC_DEF void -_cx_memb(_make_heap)(_cx_self* self) { +_cx_MEMB(_make_heap)(_cx_Self* self) { intptr_t n = self->_len; for (intptr_t k = n/2; k != 0; --k) - _cx_memb(_sift_down_)(self, k, n); + _cx_MEMB(_sift_down_)(self, k, n); } #if !defined i_no_clone -STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) { - _cx_self out = _cx_memb(_with_capacity)(q._len); +STC_DEF _cx_Self _cx_MEMB(_clone)(_cx_Self q) { + _cx_Self out = _cx_MEMB(_with_capacity)(q._len); for (; out._len < out._cap; ++q.data) out.data[out._len++] = i_keyclone((*q.data)); return out; @@ -140,22 +138,23 @@ STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) { #endif STC_DEF void -_cx_memb(_erase_at)(_cx_self* self, const intptr_t idx) { +_cx_MEMB(_erase_at)(_cx_Self* self, const intptr_t idx) { i_keydrop((self->data + idx)); const intptr_t n = --self->_len; self->data[idx] = self->data[n]; - _cx_memb(_sift_down_)(self, idx + 1, n); + _cx_MEMB(_sift_down_)(self, idx + 1, n); } -STC_DEF void -_cx_memb(_push)(_cx_self* self, _cx_value value) { +STC_DEF _cx_value* +_cx_MEMB(_push)(_cx_Self* self, _cx_value value) { if (self->_len == self->_cap) - _cx_memb(_reserve)(self, self->_len*3/2 + 4); + _cx_MEMB(_reserve)(self, self->_len*3/2 + 4); _cx_value *arr = self->data - 1; /* base 1 */ intptr_t c = ++self->_len; for (; c > 1 && (i_less((&arr[c/2]), (&value))); c /= 2) arr[c] = arr[c/2]; arr[c] = value; + return arr + c; } #endif diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 1934305a..5d38ca89 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -20,46 +20,223 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -// STC queue -/* -#include <stc/crand.h> -#include <stdio.h> +#include "priv/linkage.h" -#define i_key int -#include <stc/cqueue.h> +#ifndef CQUEUE_H_INCLUDED +#include "ccommon.h" +#include "forward.h" +#include <stdlib.h> +#include <string.h> +#endif // CQUEUE_H_INCLUDED -int main() { - int n = 10000000; - crand_t rng = crand_init(1234); - crand_unif_t dist = crand_unif_init(0, n); +#ifndef _i_prefix +#define _i_prefix cqueue_ +#endif +#include "priv/template.h" - c_auto (cqueue_int, Q) - { - // Push ten million random numbers onto the queue. - for (int i=0; i<n; ++i) - cqueue_int_push(&Q, crand_unif(&rng, &dist)); - - // Push or pop on the queue ten million times - printf("before: size, capacity: %d, %d\n", n, cqueue_int_size(&Q), cqueue_int_capacity(&Q)); - for (int i=n; i>0; --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)); +#ifndef i_is_forward +_cx_DEFTYPES(_c_cdeq_types, _cx_Self, i_key); +#endif +typedef i_keyraw _cx_raw; + +STC_API _cx_Self _cx_MEMB(_with_capacity)(const intptr_t n); +STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n); +STC_API void _cx_MEMB(_clear)(_cx_Self* self); +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); // push_back +STC_API void _cx_MEMB(_shrink_to_fit)(_cx_Self *self); +STC_API _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n); + +#define _cdeq_toidx(self, pos) (((pos) - (self)->start) & (self)->capmask) +#define _cdeq_topos(self, idx) (((self)->start + (idx)) & (self)->capmask) + +STC_INLINE _cx_Self _cx_MEMB(_init)(void) + { _cx_Self cx = {0}; return cx; } +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } + +#if !defined i_no_emplace +STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push)(self, i_keyfrom(raw)); } +#endif + +#if defined _i_has_eq || defined _i_has_cmp +STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other); +#endif + +#if !defined i_no_clone +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); +STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val) + { return i_keyclone(val); } +#endif // !i_no_clone +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) + { return _cdeq_toidx(self, self->end); } +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) + { return self->capmask; } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) + { return self->start == self->end; } +STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval) + { return i_keyto(pval); } + +STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) + { return self->data + self->start; } + +STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) + { return self->data + ((self->end - 1) & self->capmask); } + +STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { // pop_front + c_assert(!_cx_MEMB(_empty)(self)); + i_keydrop((self->data + self->start)); + self->start = (self->start + 1) & self->capmask; +} + +STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { // move front out of queue + c_assert(!_cx_MEMB(_empty)(self)); + intptr_t s = self->start; + self->start = (s + 1) & self->capmask; + return self->data[s]; +} + +STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { + if (self->data == other->data) return; + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); +} + +STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { + return c_LITERAL(_cx_iter){ + _cx_MEMB(_empty)(self) ? NULL : self->data + self->start, + self->start, self + }; +} + +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) + { return c_LITERAL(_cx_iter){.pos=self->end, ._s=self}; } + +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { + if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; } + else { it->ref -= it->pos; it->pos = 0; } + if (it->pos == it->_s->end) it->ref = NULL; +} + +STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) + { return _cdeq_toidx(self, it.pos); } + +STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) + { self->end = (self->end + n) & self->capmask; } + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) || defined(i_static) + +STC_DEF _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n) { + intptr_t len = _cx_MEMB(_size)(it._s); + intptr_t pos = it.pos, idx = _cdeq_toidx(it._s, pos); + it.pos = (pos + n) & it._s->capmask; + it.ref += it.pos - pos; + if (!c_LTu(idx + n, len)) it.ref = NULL; + return it; +} + +STC_DEF void +_cx_MEMB(_clear)(_cx_Self* self) { + c_foreach (i, _cx_Self, *self) + { i_keydrop(i.ref); } + self->start = 0, self->end = 0; +} + +STC_DEF void +_cx_MEMB(_drop)(_cx_Self* self) { + _cx_MEMB(_clear)(self); + i_free(self->data); +} + +STC_DEF _cx_Self +_cx_MEMB(_with_capacity)(const intptr_t n) { + _cx_Self cx = {0}; + _cx_MEMB(_reserve)(&cx, n); + return cx; +} + +STC_DEF bool +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n) { + if (n <= self->capmask) + return true; + intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1); + _cx_value* d = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data); + if (!d) + return false; + intptr_t head = oldcap - self->start; + if (self->start <= self->end) + ; + else if (head < self->end) { + self->start = newcap - head; + c_memmove(d + self->start, d + oldcap - head, head*c_sizeof *d); + } else { + c_memmove(d + oldcap, d, self->end*c_sizeof *d); + self->end += oldcap; } + self->capmask = newcap - 1; + self->data = d; + return true; } -*/ -#ifndef _i_prefix -#define _i_prefix cqueue_ -#endif -#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; +} +#endif // i_no_clone -#undef _pop_front -#undef _i_queue +#if defined _i_has_eq || defined _i_has_cmp +STC_DEF bool +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; + for (_cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other); + i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) + { + const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); + if (!(i_eq((&_rx), (&_ry)))) return false; + } + return true; +} +#endif +#endif // IMPLEMENTATION +#include "priv/template2.h" +#define CQUEUE_H_INCLUDED diff --git a/include/stc/crand.h b/include/stc/crand.h index a1b7250d..0a6aa9e0 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -20,15 +20,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CRAND_H_INCLUDED #define CRAND_H_INCLUDED +#include "ccommon.h" /* // crand: Pseudo-random number generator #include "stc/crand.h" -int main() { +int main(void) { uint64_t seed = 123456789; crand_t rng = crand_init(seed); crand_unif_t dist1 = crand_unif_init(1, 6); @@ -92,7 +93,7 @@ STC_INLINE double crand_f64(crand_t* rng) { } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) /* Global random() */ static crand_t crand_global = {{ @@ -127,18 +128,6 @@ STC_DEF crand_unif_t crand_unif_init(int64_t low, int64_t high) { return dist; } -#if defined(__SIZEOF_INT128__) - #define c_umul128(a, b, lo, hi) \ - do { __uint128_t _z = (__uint128_t)(a)*(b); \ - *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0) -#elif defined(_MSC_VER) && defined(_WIN64) - #include <intrin.h> - #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi))) -#elif defined(__x86_64__) - #define c_umul128(a, b, lo, hi) \ - asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) -#endif - /* Int64 uniform distributed RNG, range [low, high]. */ STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) { uint64_t lo, hi; @@ -164,11 +153,10 @@ STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) { dist->next = u2*m; return (u1*m)*dist->stddev + dist->mean; } - #endif #endif #undef i_opt #undef i_static #undef i_header #undef i_implement -#undef i_extern +#undef i_import 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 <string.h> -#include <math.h> - -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 <intrin.h> - #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/cregex.h b/include/stc/cregex.h index a48b4c49..bce94b04 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -22,6 +22,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "priv/linkage.h" + #ifndef CREGEX_H_INCLUDED #define CREGEX_H_INCLUDED /* @@ -37,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, @@ -53,7 +59,6 @@ enum { typedef enum { CREG_OK = 0, - CREG_SUCCESS = 0, /* [deprecated] */ CREG_NOMATCH = -1, CREG_MATCHERROR = -2, CREG_OUTOFMEMORY = -3, @@ -82,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}; @@ -104,7 +109,7 @@ STC_INLINE cregex cregex_from_2(const char* pattern, int cflags) { return re; } -/* number of capture groups in a regex pattern including full the match capture, 0 if regex is invalid */ +/* number of capture groups in a regex pattern, excluding the full match capture (0) */ int cregex_captures(const cregex* re); /* return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */ @@ -116,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 */ @@ -136,7 +141,7 @@ STC_INLINE bool cregex_is_match(const cregex* re, const char* input) #define cregex_replace_sv_4(pattern, input, replace, count) \ cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, - bool (*mfun)(int i, csview match, cstr* mstr), int rflags); + bool (*transform)(int group, csview match, cstr* result), int rflags); /* replace input with replace using regular expression */ #define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__) @@ -154,18 +159,20 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char #define cregex_replace_pattern_4(pattern, input, replace, count) \ cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT) cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count, - bool (*mfun)(int i, csview match, cstr* mstr), int crflags); + bool (*transform)(int group, csview match, cstr* result), int crflags); /* destroy regex */ void cregex_drop(cregex* re); - #endif // CREGEX_H_INCLUDED -#if defined(i_extern) + +#if defined i_implement # include "../../src/cregex.c" +#endif +#if defined i_import # include "../../src/utf8code.c" -# undef i_extern #endif #undef i_opt #undef i_header #undef i_static +#undef i_import #undef i_implement 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 ebfe8d44..f4d33a4d 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 <stdio.h> +#define i_implement #include <stc/cstr.h> #define i_tag sx // Sorted map<cstr, double> @@ -48,9 +49,10 @@ int main(void) { csmap_sx_drop(&m); } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CSMAP_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include <stdlib.h> #include <string.h> @@ -58,27 +60,20 @@ 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) -#endif -#ifndef i_ssize - #define i_ssize int32_t - #define _i_size intptr_t #else - #define _i_size i_ssize + #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 - _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); + _cx_DEFTYPES(_c_aatree_types, _cx_Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); #endif _i_MAP_ONLY( struct _cx_value { @@ -86,205 +81,243 @@ _i_MAP_ONLY( struct _cx_value { _cx_mapped second; }; ) struct _cx_node { - i_ssize link[2]; + int32_t link[2]; int8_t level; _cx_value value; }; typedef i_keyraw _cx_keyraw; -typedef i_valraw _cx_memb(_rmapped); +typedef i_valraw _cx_MEMB(_rmapped); typedef _i_SET_ONLY( i_keyraw ) _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } ) _cx_raw; #if !defined i_no_emplace -STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)); +STC_API _cx_result _cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)); #endif // !i_no_emplace #if !defined i_no_clone -STC_API _cx_self _cx_memb(_clone)(_cx_self tree); +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self tree); #endif // !i_no_clone -STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)); -STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val); -STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API bool _cx_memb(_reserve)(_cx_self* self, _i_size cap); -STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out); -STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey); -STC_API _cx_value* _cx_memb(_front)(const _cx_self* self); -STC_API _cx_value* _cx_memb(_back)(const _cx_self* self); -STC_API int _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey); -STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it); -STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2); -STC_API void _cx_memb(_next)(_cx_iter* it); - -STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self tree = {0}; return tree; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* cx) { return cx->size == 0; } -STC_INLINE _i_size _cx_memb(_size)(const _cx_self* cx) { return cx->size; } -STC_INLINE _i_size _cx_memb(_capacity)(const _cx_self* cx) { return cx->cap; } -STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) - { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; } -STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) - { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; } -STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey) - { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); } -STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey) - { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); } - -STC_INLINE _cx_self -_cx_memb(_with_capacity)(const _i_size cap) { - _cx_self tree = _cx_memb(_init)(); - _cx_memb(_reserve)(&tree, cap); +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t cap); +STC_API _cx_value* _cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out); +STC_API _cx_iter _cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_keyraw rkey); +STC_API _cx_value* _cx_MEMB(_front)(const _cx_Self* self); +STC_API _cx_value* _cx_MEMB(_back)(const _cx_Self* self); +STC_API int _cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey); +STC_API _cx_iter _cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it); +STC_API _cx_iter _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2); +STC_API _cx_iter _cx_MEMB(_begin)(const _cx_Self* self); +STC_API void _cx_MEMB(_next)(_cx_iter* it); + +STC_INLINE _cx_Self _cx_MEMB(_init)(void) { _cx_Self tree = {0}; return tree; } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* cx) { return cx->size == 0; } +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* cx) { return cx->size; } +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* cx) { return cx->cap; } +STC_INLINE _cx_iter _cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; _cx_MEMB(_find_it)(self, rkey, &it); return it; } +STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it) != NULL; } +STC_INLINE const _cx_value* _cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it); } +STC_INLINE _cx_value* _cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it); } + +STC_INLINE _cx_Self +_cx_MEMB(_with_capacity)(const intptr_t cap) { + _cx_Self tree = _cx_MEMB(_init)(); + _cx_MEMB(_reserve)(&tree, cap); return tree; } STC_INLINE void -_cx_memb(_clear)(_cx_self* self) - { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); } +_cx_MEMB(_clear)(_cx_Self* self) + { _cx_MEMB(_drop)(self); *self = _cx_MEMB(_init)(); } STC_INLINE _cx_raw -_cx_memb(_value_toraw)(const _cx_value* val) { +_cx_MEMB(_value_toraw)(const _cx_value* val) { return _i_SET_ONLY( i_keyto(val) ) _i_MAP_ONLY( c_LITERAL(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} ); } STC_INLINE void -_cx_memb(_value_drop)(_cx_value* val) { +_cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(_i_keyref(val)); _i_MAP_ONLY( i_valdrop((&val->second)); ) } #if !defined i_no_clone STC_INLINE _cx_value -_cx_memb(_value_clone)(_cx_value _val) { +_cx_MEMB(_value_clone)(_cx_value _val) { *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val))); _i_MAP_ONLY( _val.second = i_valclone(_val.second); ) return _val; } STC_INLINE void -_cx_memb(_copy)(_cx_self *self, const _cx_self* other) { +_cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { if (self->nodes == other->nodes) return; - _cx_memb(_drop)(self); - *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); } STC_INLINE void -_cx_memb(_shrink_to_fit)(_cx_self *self) { - _cx_self tmp = _cx_memb(_clone)(*self); - _cx_memb(_drop)(self); *self = tmp; +_cx_MEMB(_shrink_to_fit)(_cx_Self *self) { + _cx_Self tmp = _cx_MEMB(_clone)(*self); + _cx_MEMB(_drop)(self); *self = tmp; } #endif // !i_no_clone #ifndef _i_isset - STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped); + STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped); #if !defined i_no_emplace - STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped); + STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped); #endif STC_INLINE const _cx_mapped* - _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey) - { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; } + _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; } STC_INLINE _cx_mapped* - _cx_memb(_at_mut)(_cx_self* self, _cx_keyraw rkey) - { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; } + _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey) + { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; } #endif // !_i_isset STC_INLINE _cx_iter -_cx_memb(_begin)(const _cx_self* self) { - _cx_iter it; - it.ref = NULL; - it._d = self->nodes, it._top = 0; - it._tn = self->root; - if (it._tn) - _cx_memb(_next)(&it); - return it; -} - -STC_INLINE _cx_iter -_cx_memb(_end)(const _cx_self* self) { +_cx_MEMB(_end)(const _cx_Self* self) { (void)self; _cx_iter it; it.ref = NULL, it._top = 0, it._tn = 0; return it; } STC_INLINE _cx_iter -_cx_memb(_advance)(_cx_iter it, size_t n) { +_cx_MEMB(_advance)(_cx_iter it, size_t n) { while (n-- && it.ref) - _cx_memb(_next)(&it); + _cx_MEMB(_next)(&it); return it; } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; - _cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other); - for (; i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) { +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; + _cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other); + for (; i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) { const _cx_keyraw _rx = i_keyto(_i_keyref(i.ref)), _ry = i_keyto(_i_keyref(j.ref)); if (!(i_eq((&_rx), (&_ry)))) return false; } return true; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) { +static _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey); + +STC_INLINE _cx_result +_cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); + if (_res.inserted) + { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} + else + { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )} + return _res; +} + +STC_INLINE _cx_value* +_cx_MEMB(_push)(_cx_Self* self, _cx_value _val) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); + if (_res.inserted) + *_res.ref = _val; + else + _cx_MEMB(_value_drop)(&_val); + return _res.ref; +} + +STC_INLINE void +_cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) { while (n--) #if defined _i_isset && defined i_no_emplace - _cx_memb(_insert)(self, *raw++); + _cx_MEMB(_insert)(self, *raw++); #elif defined _i_isset - _cx_memb(_emplace)(self, *raw++); + _cx_MEMB(_emplace)(self, *raw++); #elif defined i_no_emplace - _cx_memb(_insert_or_assign)(self, raw->first, raw->second), ++raw; + _cx_MEMB(_insert_or_assign)(self, raw->first, raw->second), ++raw; #else - _cx_memb(_emplace_or_assign)(self, raw->first, raw->second), ++raw; + _cx_MEMB(_emplace_or_assign)(self, raw->first, raw->second), ++raw; #endif } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, _i_size n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } +STC_INLINE _cx_Self +_cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) + +STC_DEF void +_cx_MEMB(_next)(_cx_iter *it) { + int32_t tn = it->_tn; + if (it->_top || tn) { + while (tn) { + it->_st[it->_top++] = tn; + tn = it->_d[tn].link[0]; + } + tn = it->_st[--it->_top]; + it->_tn = it->_d[tn].link[1]; + it->ref = &it->_d[tn].value; + } else + it->ref = NULL; +} + +STC_DEF _cx_iter +_cx_MEMB(_begin)(const _cx_Self* self) { + _cx_iter it; + it.ref = NULL; + it._d = self->nodes, it._top = 0; + it._tn = self->root; + if (it._tn) + _cx_MEMB(_next)(&it); + return it; +} STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const _i_size cap) { +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) { if (cap <= self->cap) return false; _cx_node* nodes = (_cx_node*)i_realloc(self->nodes, (cap + 1)*c_sizeof(_cx_node)); if (!nodes) return false; - nodes[0] = c_LITERAL(_cx_node){{0, 0}, 0}; + nodes[0] = c_LITERAL(_cx_node){0}; self->nodes = nodes; - self->cap = (i_ssize)cap; + self->cap = (int32_t)cap; return true; } STC_DEF _cx_value* -_cx_memb(_front)(const _cx_self* self) { +_cx_MEMB(_front)(const _cx_Self* self) { _cx_node *d = self->nodes; - i_ssize tn = self->root; + int32_t tn = self->root; while (d[tn].link[0]) tn = d[tn].link[0]; return &d[tn].value; } STC_DEF _cx_value* -_cx_memb(_back)(const _cx_self* self) { +_cx_MEMB(_back)(const _cx_Self* self) { _cx_node *d = self->nodes; - i_ssize tn = self->root; + int32_t tn = self->root; while (d[tn].link[1]) tn = d[tn].link[1]; return &d[tn].value; } -static i_ssize -_cx_memb(_new_node_)(_cx_self* self, int level) { - i_ssize tn; +static int32_t +_cx_MEMB(_new_node_)(_cx_Self* self, int level) { + int32_t tn; if (self->disp) { tn = self->disp; self->disp = self->nodes[tn].link[1]; } else { if (self->head == self->cap) - if (!_cx_memb(_reserve)(self, self->head*3/2 + 4)) + if (!_cx_MEMB(_reserve)(self, self->head*3/2 + 4)) return 0; tn = ++self->head; /* start with 1, 0 is nullnode. */ } @@ -293,32 +326,10 @@ _cx_memb(_new_node_)(_cx_self* self, int level) { return tn; } -static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey); - -STC_DEF _cx_result -_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); - if (_res.inserted) - { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} - else - { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )} - return _res; -} - -STC_DEF _cx_result -_cx_memb(_push)(_cx_self* self, _cx_value _val) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); - if (_res.inserted) - *_res.ref = _val; - else - _cx_memb(_value_drop)(&_val); - return _res; -} - #ifndef _i_isset STC_DEF _cx_result - _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); + _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key))); _cx_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped; if (_res.inserted) _res.ref->first = _key; @@ -330,8 +341,8 @@ _cx_memb(_push)(_cx_self* self, _cx_value _val) { #if !defined i_no_emplace STC_DEF _cx_result - _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped) { - _cx_result _res = _cx_memb(_insert_entry_)(self, rkey); + _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey); if (_res.inserted) _res.ref->first = i_keyfrom(rkey); else { @@ -345,8 +356,8 @@ _cx_memb(_push)(_cx_self* self, _cx_value _val) { #endif // !_i_isset STC_DEF _cx_value* -_cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out) { - i_ssize tn = self->root; +_cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out) { + int32_t tn = self->root; _cx_node *d = out->_d = self->nodes; out->_top = 0; while (tn) { @@ -362,36 +373,21 @@ _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out) { } STC_DEF _cx_iter -_cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_keyraw rkey) { _cx_iter it; - _cx_memb(_find_it)(self, rkey, &it); + _cx_MEMB(_find_it)(self, rkey, &it); if (!it.ref && it._top) { - i_ssize tn = it._st[--it._top]; + int32_t tn = it._st[--it._top]; it._tn = it._d[tn].link[1]; it.ref = &it._d[tn].value; } return it; } -STC_DEF void -_cx_memb(_next)(_cx_iter *it) { - i_ssize tn = it->_tn; - if (it->_top || tn) { - while (tn) { - it->_st[it->_top++] = tn; - tn = it->_d[tn].link[0]; - } - tn = it->_st[--it->_top]; - it->_tn = it->_d[tn].link[1]; - it->ref = &it->_d[tn].value; - } else - it->ref = NULL; -} - -STC_DEF i_ssize -_cx_memb(_skew_)(_cx_node *d, i_ssize tn) { +STC_DEF int32_t +_cx_MEMB(_skew_)(_cx_node *d, int32_t tn) { if (tn && d[d[tn].link[0]].level == d[tn].level) { - i_ssize tmp = d[tn].link[0]; + int32_t tmp = d[tn].link[0]; d[tn].link[0] = d[tmp].link[1]; d[tmp].link[1] = tn; tn = tmp; @@ -399,10 +395,10 @@ _cx_memb(_skew_)(_cx_node *d, i_ssize tn) { return tn; } -STC_DEF i_ssize -_cx_memb(_split_)(_cx_node *d, i_ssize tn) { +STC_DEF int32_t +_cx_MEMB(_split_)(_cx_node *d, int32_t tn) { if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) { - i_ssize tmp = d[tn].link[1]; + int32_t tmp = d[tn].link[1]; d[tn].link[1] = d[tmp].link[0]; d[tmp].link[0] = tn; tn = tmp; @@ -411,9 +407,9 @@ _cx_memb(_split_)(_cx_node *d, i_ssize tn) { return tn; } -static i_ssize -_cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _cx_result* _res) { - i_ssize up[64], tx = tn; +static int32_t +_cx_MEMB(_insert_entry_i_)(_cx_Self* self, int32_t tn, const _cx_keyraw* rkey, _cx_result* _res) { + int32_t up[64], tx = tn; _cx_node* d = self->nodes; int c, top = 0, dir = 0; while (tx) { @@ -424,7 +420,7 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _ dir = (c < 0); tx = d[tx].link[dir]; } - if ((tx = _cx_memb(_new_node_)(self, 1)) == 0) + if ((tx = _cx_MEMB(_new_node_)(self, 1)) == 0) return 0; d = self->nodes; _res->ref = &d[tx].value; @@ -435,8 +431,8 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _ while (top--) { if (top) dir = (d[up[top - 1]].link[1] == up[top]); - up[top] = _cx_memb(_skew_)(d, up[top]); - up[top] = _cx_memb(_split_)(d, up[top]); + up[top] = _cx_MEMB(_skew_)(d, up[top]); + up[top] = _cx_MEMB(_split_)(d, up[top]); if (top) d[up[top - 1]].link[dir] = up[top]; } @@ -444,33 +440,33 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _ } static _cx_result -_cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { _cx_result res = {NULL}; - i_ssize tn = _cx_memb(_insert_entry_i_)(self, self->root, &rkey, &res); + int32_t tn = _cx_MEMB(_insert_entry_i_)(self, self->root, &rkey, &res); self->root = tn; self->size += res.inserted; return res; } -static i_ssize -_cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_keyraw* rkey, int *erased) { +static int32_t +_cx_MEMB(_erase_r_)(_cx_Self *self, int32_t tn, const _cx_keyraw* rkey, int *erased) { _cx_node *d = self->nodes; if (tn == 0) return 0; _cx_keyraw raw = i_keyto(_i_keyref(&d[tn].value)); - i_ssize tx; int c = i_cmp((&raw), rkey); + int32_t tx; int c = i_cmp((&raw), rkey); if (c != 0) - d[tn].link[c < 0] = _cx_memb(_erase_r_)(self, d[tn].link[c < 0], rkey, erased); + d[tn].link[c < 0] = _cx_MEMB(_erase_r_)(self, d[tn].link[c < 0], rkey, erased); else { if (!(*erased)++) - _cx_memb(_value_drop)(&d[tn].value); + _cx_MEMB(_value_drop)(&d[tn].value); if (d[tn].link[0] && d[tn].link[1]) { tx = d[tn].link[0]; while (d[tx].link[1]) tx = d[tx].link[1]; d[tn].value = d[tx].value; /* move */ raw = i_keyto(_i_keyref(&d[tn].value)); - d[tn].link[0] = _cx_memb(_erase_r_)(self, d[tn].link[0], &raw, erased); + d[tn].link[0] = _cx_MEMB(_erase_r_)(self, d[tn].link[0], &raw, erased); } else { /* unlink node */ tx = tn; tn = d[tn].link[ d[tn].link[0] == 0 ]; @@ -483,19 +479,19 @@ _cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_keyraw* rkey, int *era if (d[d[tn].link[0]].level < d[tn].level - 1 || d[tx].level < d[tn].level - 1) { if (d[tx].level > --d[tn].level) d[tx].level = d[tn].level; - tn = _cx_memb(_skew_)(d, tn); - tx = d[tn].link[1] = _cx_memb(_skew_)(d, d[tn].link[1]); - d[tx].link[1] = _cx_memb(_skew_)(d, d[tx].link[1]); - tn = _cx_memb(_split_)(d, tn); - d[tn].link[1] = _cx_memb(_split_)(d, d[tn].link[1]); + tn = _cx_MEMB(_skew_)(d, tn); + tx = d[tn].link[1] = _cx_MEMB(_skew_)(d, d[tn].link[1]); + d[tx].link[1] = _cx_MEMB(_skew_)(d, d[tx].link[1]); + tn = _cx_MEMB(_split_)(d, tn); + d[tn].link[1] = _cx_MEMB(_split_)(d, d[tn].link[1]); } return tn; } STC_DEF int -_cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { +_cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) { int erased = 0; - i_ssize root = _cx_memb(_erase_r_)(self, self->root, &rkey, &erased); + int32_t root = _cx_MEMB(_erase_r_)(self, self->root, &rkey, &erased); if (!erased) return 0; self->root = root; @@ -504,23 +500,23 @@ _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { } STC_DEF _cx_iter -_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { +_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) { _cx_keyraw raw = i_keyto(_i_keyref(it.ref)); - _cx_memb(_next)(&it); + _cx_MEMB(_next)(&it); if (it.ref) { _cx_keyraw nxt = i_keyto(_i_keyref(it.ref)); - _cx_memb(_erase)(self, raw); - _cx_memb(_find_it)(self, nxt, &it); + _cx_MEMB(_erase)(self, raw); + _cx_MEMB(_find_it)(self, nxt, &it); } else - _cx_memb(_erase)(self, raw); + _cx_MEMB(_erase)(self, raw); return it; } STC_DEF _cx_iter -_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { +_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) { if (!it2.ref) { while (it1.ref) - it1 = _cx_memb(_erase_at)(self, it1); + it1 = _cx_MEMB(_erase_at)(self, it1); return it1; } _cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref); @@ -528,30 +524,30 @@ _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { for (;;) { if (memcmp(&k1, &k2, sizeof k1) == 0) return it1; - _cx_memb(_next)(&it1); + _cx_MEMB(_next)(&it1); k1 = *_i_keyref(it1.ref); - _cx_memb(_erase)(self, r1); + _cx_MEMB(_erase)(self, r1); r1 = i_keyto((&k1)); - _cx_memb(_find_it)(self, r1, &it1); + _cx_MEMB(_find_it)(self, r1, &it1); } } #if !defined i_no_clone -static i_ssize -_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_ssize sn) { +static int32_t +_cx_MEMB(_clone_r_)(_cx_Self* self, _cx_node* src, int32_t sn) { if (sn == 0) return 0; - i_ssize tx, tn = _cx_memb(_new_node_)(self, src[sn].level); - self->nodes[tn].value = _cx_memb(_value_clone)(src[sn].value); - tx = _cx_memb(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx; - tx = _cx_memb(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx; + int32_t tx, tn = _cx_MEMB(_new_node_)(self, src[sn].level); + self->nodes[tn].value = _cx_MEMB(_value_clone)(src[sn].value); + tx = _cx_MEMB(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx; + tx = _cx_MEMB(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx; return tn; } -STC_DEF _cx_self -_cx_memb(_clone)(_cx_self tree) { - _cx_self clone = _cx_memb(_with_capacity)(tree.size); - i_ssize root = _cx_memb(_clone_r_)(&clone, tree.nodes, tree.root); +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self tree) { + _cx_Self clone = _cx_MEMB(_with_capacity)(tree.size); + int32_t root = _cx_MEMB(_clone_r_)(&clone, tree.nodes, tree.root); clone.root = root; clone.size = tree.size; return clone; @@ -560,8 +556,8 @@ _cx_memb(_clone)(_cx_self tree) { #if !defined i_no_emplace STC_DEF _cx_result -_cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { - _cx_result res = _cx_memb(_insert_entry_)(self, rkey); +_cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { + _cx_result res = _cx_MEMB(_insert_entry_)(self, rkey); if (res.inserted) { *_i_keyref(res.ref) = i_keyfrom(rkey); _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);) @@ -571,24 +567,23 @@ _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe #endif // i_no_emplace static void -_cx_memb(_drop_r_)(_cx_node* d, i_ssize tn) { +_cx_MEMB(_drop_r_)(_cx_node* d, int32_t tn) { if (tn) { - _cx_memb(_drop_r_)(d, d[tn].link[0]); - _cx_memb(_drop_r_)(d, d[tn].link[1]); - _cx_memb(_value_drop)(&d[tn].value); + _cx_MEMB(_drop_r_)(d, d[tn].link[0]); + _cx_MEMB(_drop_r_)(d, d[tn].link[1]); + _cx_MEMB(_value_drop)(&d[tn].value); } } STC_DEF void -_cx_memb(_drop)(_cx_self* self) { +_cx_MEMB(_drop)(_cx_Self* self) { if (self->cap) { - _cx_memb(_drop_r_)(self->nodes, self->root); + _cx_MEMB(_drop_r_)(self->nodes, self->root); i_free(self->nodes); } } #endif // i_implement -#undef _i_size #undef _i_isset #undef _i_ismap #undef _i_keyref diff --git a/include/stc/cspan.h b/include/stc/cspan.h index ac3e9206..dcb02961 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -60,6 +60,7 @@ int demo2() { #ifndef STC_CSPAN_H_INCLUDED #define STC_CSPAN_H_INCLUDED +#include "priv/linkage.h" #include "ccommon.h" #define using_cspan(...) c_MACRO_OVERLOAD(using_cspan, __VA_ARGS__) @@ -71,7 +72,7 @@ int demo2() { typedef struct { \ Self##_value *data; \ int32_t shape[RANK]; \ - cspan_idx##RANK stride; \ + cspan_tuple##RANK stride; \ } Self; \ \ typedef struct { Self##_value *ref; int32_t pos[RANK]; const Self *_s; } Self##_iter; \ @@ -80,10 +81,10 @@ int demo2() { return (Self){.data=raw, .shape={(int32_t)n}}; \ } \ STC_INLINE Self Self##_slice_(Self##_value* v, const int32_t shape[], const int32_t stri[], \ - const int rank, const int32_t a[][2]) { \ - Self s = {.data=v}; int outrank; \ + const int rank, const int32_t a[][2]) { \ + Self s; s.data = v; int outrank; \ s.data += _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \ - c_ASSERT(outrank == RANK); \ + c_assert(outrank == RANK); \ return s; \ } \ STC_INLINE Self##_iter Self##_begin(const Self* self) { \ @@ -95,174 +96,197 @@ int demo2() { return it; \ } \ STC_INLINE void Self##_next(Self##_iter* it) { \ - it->ref += _cspan_next##RANK(RANK, it->pos, it->_s->shape, it->_s->stride.d); \ - if (it->pos[0] == it->_s->shape[0]) it->ref = NULL; \ + static const struct { int8_t i, j, inc; } t[2] = {{RANK - 1, 0, -1}, {0, RANK - 1, 1}}; \ + const int order = (it->_s->stride.d[0] < it->_s->stride.d[RANK - 1]); /* 0='C', 1='F' */ \ + it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, t[order].i, t[order].inc); \ + if (it->pos[t[order].j] == it->_s->shape[t[order].j]) \ + it->ref = NULL; \ } \ struct stc_nostruct #define using_cspan2(Self, T) using_cspan_3(Self, T, 1); using_cspan_3(Self##2, T, 2) #define using_cspan3(Self, T) using_cspan2(Self, T); using_cspan_3(Self##3, T, 3) #define using_cspan4(Self, T) using_cspan3(Self, T); using_cspan_3(Self##4, T, 4) -typedef struct { int32_t d[1]; } cspan_idx1; -typedef struct { int32_t d[2]; } cspan_idx2; -typedef struct { int32_t d[3]; } cspan_idx3; -typedef struct { int32_t d[4]; } cspan_idx4; -typedef struct { int32_t d[5]; } cspan_idx5; -typedef struct { int32_t d[6]; } cspan_idx6; -#define c_END -1 -#define c_ALL 0,-1 +#define using_cspan_tuple(N) typedef struct { int32_t d[N]; } cspan_tuple##N +using_cspan_tuple(1); using_cspan_tuple(2); +using_cspan_tuple(3); using_cspan_tuple(4); +using_cspan_tuple(5); using_cspan_tuple(6); +using_cspan_tuple(7); using_cspan_tuple(8); -#define cspan_md(array, ...) \ - {.data=array, .shape={__VA_ARGS__}, .stride={.d={__VA_ARGS__}}} +#define c_END -1 +#define c_ALL 0,c_END -/* For static initialization, use cspan_make(). c_make() for non-static only. */ -#define cspan_make(SpanType, ...) \ - {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}} +/* Use cspan_init() for static initialization only. c_init() for non-static init. */ +#define cspan_init(SpanType, ...) \ + {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}, .stride={.d={1}}} -#define cspan_slice(OutSpan, parent, ...) \ - OutSpan##_slice_((parent)->data, (parent)->shape, (parent)->stride.d, cspan_rank(parent) + \ - c_static_assert(cspan_rank(parent) == sizeof((int32_t[][2]){__VA_ARGS__})/sizeof(int32_t[2])), \ - (const int32_t[][2]){__VA_ARGS__}) - /* create a cspan from a cvec, cstack, cdeq, cqueue, or cpque (heap) */ #define cspan_from(container) \ - {.data=(container)->data, .shape={(int32_t)(container)->_len}} + {.data=(container)->data, .shape={(int32_t)(container)->_len}, .stride={.d={1}}} #define cspan_from_array(array) \ - {.data=(array) + c_static_assert(sizeof(array) != sizeof(void*)), .shape={c_arraylen(array)}} + {.data=(array), .shape={c_arraylen(array)}, .stride={.d={1}}} #define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) #define cspan_rank(self) c_arraylen((self)->shape) - +#define cspan_is_order_F(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) #define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) -#define cspan_idx_1 cspan_idx_4 -#define cspan_idx_2 cspan_idx_4 -#define cspan_idx_3 cspan_idx_4 -#define cspan_idx_4(self, ...) \ - c_PASTE(_cspan_idx, c_NUMARGS(__VA_ARGS__))((self)->shape, (self)->stride, __VA_ARGS__) // small/fast -#define cspan_idx_5(self, ...) \ - (_cspan_idxN(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \ - c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general -#define cspan_idx_6 cspan_idx_5 - #define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__)) #define cspan_front(self) ((self)->data) #define cspan_back(self) ((self)->data + cspan_size(self) - 1) -// cspan_subspanN. (N<4) Optimized, same as e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); +// cspan_subspanX: (X <= 3) optimized. Similar to cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); #define cspan_subspan(self, offset, count) \ - {.data=cspan_at(self, offset), .shape={count}} + {.data=cspan_at(self, offset), .shape={count}, .stride=(self)->stride} #define cspan_subspan2(self, offset, count) \ - {.data=cspan_at(self, offset, 0), .shape={count, (self)->shape[1]}, .stride={(self)->stride}} + {.data=cspan_at(self, offset, 0), .shape={count, (self)->shape[1]}, .stride=(self)->stride} #define cspan_subspan3(self, offset, count) \ - {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride={(self)->stride}} + {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride=(self)->stride} -// cspan_submdN: reduce rank (N<5) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); -#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__) -#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__) +// cspan_submd(): Reduce rank (N <= 4) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL}); #define cspan_submd2(self, x) \ - {.data=cspan_at(self, x, 0), .shape={(self)->shape[1]}} + {.data=cspan_at(self, x, 0), .shape={(self)->shape[1]}, .stride=(cspan_tuple1){.d={(self)->stride.d[1]}}} +#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__) #define cspan_submd3_2(self, x) \ {.data=cspan_at(self, x, 0, 0), .shape={(self)->shape[1], (self)->shape[2]}, \ - .stride={.d={0, (self)->stride.d[2]}}} + .stride=(cspan_tuple2){.d={(self)->stride.d[1], (self)->stride.d[2]}}} #define cspan_submd3_3(self, x, y) \ - {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}} + {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}, .stride=(cspan_tuple1){.d={(self)->stride.d[2]}}} +#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__) #define cspan_submd4_2(self, x) \ {.data=cspan_at(self, x, 0, 0, 0), .shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \ - .stride={.d={0, (self)->stride.d[2], (self)->stride.d[3]}}} + .stride=(cspan_tuple3){.d={(self)->stride.d[1], (self)->stride.d[2], (self)->stride.d[3]}}} #define cspan_submd4_3(self, x, y) \ - {.data=cspan_at(self, x, y, 0, 0), .shape={(self)->shape[2], (self)->shape[3]}, .stride={.d={0, (self)->stride.d[3]}}} + {.data=cspan_at(self, x, y, 0, 0), .shape={(self)->shape[2], (self)->shape[3]}, \ + .stride=(cspan_tuple2){.d={(self)->stride.d[2], (self)->stride.d[3]}}} #define cspan_submd4_4(self, x, y, z) \ - {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}} + {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}, .stride=(cspan_tuple1){.d={(self)->stride.d[3]}}} + +#define cspan_md(array, ...) cspan_md_order('C', array, __VA_ARGS__) +#define cspan_md_order(order, array, ...) /* order='C' or 'F' */ \ + {.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__}) + +/* ------------------- PRIVAT DEFINITIONS ------------------- */ -// private definitions: +// cspan_index() helpers: +#define cspan_idx_1 cspan_idx_3 +#define cspan_idx_2 cspan_idx_3 +#define cspan_idx_3(self, ...) \ + c_PASTE(_cspan_idx, c_NUMARGS(__VA_ARGS__))((self)->shape, (self)->stride, __VA_ARGS__) // small/fast +#define cspan_idx_4(self, ...) \ + (_cspan_idxN(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \ + c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general +#define cspan_idx_5 cspan_idx_4 +#define cspan_idx_6 cspan_idx_4 STC_INLINE intptr_t _cspan_size(const int32_t shape[], int rank) { intptr_t sz = shape[0]; - while (rank-- > 1) sz *= shape[rank]; + while (--rank > 0) sz *= shape[rank]; return sz; } -STC_INLINE intptr_t _cspan_idx1(const int32_t shape[1], const cspan_idx1 stri, int32_t x) - { c_ASSERT(c_LTu(x, shape[0])); return x; } +STC_INLINE void _cspan_transpose(int32_t shape[], int32_t stride[], int rank) { + for (int i = 0; i < --rank; ++i) { + c_swap(int32_t, shape + i, shape + rank); + c_swap(int32_t, stride + i, stride + rank); + } +} + +STC_INLINE intptr_t _cspan_idx1(const int32_t shape[1], const cspan_tuple1 stri, int32_t x) + { c_assert(c_LTu(x, shape[0])); return (intptr_t)stri.d[0]*x; } -STC_INLINE intptr_t _cspan_idx2(const int32_t shape[2], const cspan_idx2 stri, int32_t x, int32_t y) - { c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1])); return (intptr_t)stri.d[1]*x + y; } +STC_INLINE intptr_t _cspan_idx2(const int32_t shape[2], const cspan_tuple2 stri, int32_t x, int32_t y) + { c_assert(c_LTu(x, shape[0]) && c_LTu(y, shape[1])); return (intptr_t)stri.d[0]*x + stri.d[1]*y; } -STC_INLINE intptr_t _cspan_idx3(const int32_t shape[3], const cspan_idx3 stri, int32_t x, int32_t y, int32_t z) { - c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2])); - return (intptr_t)stri.d[2]*(stri.d[1]*x + y) + z; +STC_INLINE intptr_t _cspan_idx3(const int32_t shape[3], const cspan_tuple3 stri, int32_t x, int32_t y, int32_t z) { + c_assert(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2])); + return (intptr_t)stri.d[0]*x + stri.d[1]*y + stri.d[2]*z; } -STC_INLINE intptr_t _cspan_idx4(const int32_t shape[4], const cspan_idx4 stri, int32_t x, int32_t y, - int32_t z, int32_t w) { - c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2]) && c_LTu(w, shape[3])); - return (intptr_t)stri.d[3]*(stri.d[2]*(stri.d[1]*x + y) + z) + w; +STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stride[], const int32_t a[]) { + intptr_t off = 0; + while (rank--) { + c_assert(c_LTu(a[rank], shape[rank])); + off += stride[rank]*a[rank]; + } + return off; } -STC_API intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stri[], const int32_t a[]); -STC_API intptr_t _cspan_next2(int rank, int32_t pos[], const int32_t shape[], const int32_t stride[]); -#define _cspan_next1(r, pos, d, s) (++pos[0], 1) +STC_INLINE intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc) { + intptr_t off = stride[i]; + ++pos[i]; + for (; --rank && pos[i] == shape[i]; i += inc) { + pos[i] = 0; ++pos[i + inc]; + off += stride[i + inc] - stride[i]*shape[i]; + } + return off; +} +#define _cspan_next1(pos, shape, stride, rank, i, inc) (++pos[0], stride[0]) #define _cspan_next3 _cspan_next2 #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 odim[], int32_t ostri[], int* orank, - const int32_t shape[], const int32_t stri[], +STC_API intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, + const int32_t shape[], const int32_t stride[], int rank, const int32_t a[][2]); -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +STC_API int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank); +#endif // STC_CSPAN_H_INCLUDED -STC_DEF intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stri[], const int32_t a[]) { - intptr_t off = a[0]; - c_ASSERT(c_LTu(a[0], shape[0])); - for (int i = 1; i < rank; ++i) { - off *= stri[i]; - off += a[i]; - c_ASSERT(c_LTu(a[i], shape[i])); - } - return off; -} +/* --------------------- IMPLEMENTATION --------------------- */ +#if defined(i_implement) || defined(i_static) + +STC_DEF int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank) { + int32_t k = 1, i, j, inc, s1, s2; + if (order == 'F') i = 0, j = rank, inc = 1; + else /* 'C' */ i = rank - 1, j = -1, inc = -1; + s1 = shape[i]; shape[i] = 1; -STC_DEF intptr_t _cspan_next2(int rank, int32_t pos[], const int32_t shape[], const int32_t stride[]) { - intptr_t off = 1, rs = 1; - ++pos[rank - 1]; - while (--rank && pos[rank] == shape[rank]) { - pos[rank] = 0, ++pos[rank - 1]; - const intptr_t ds = rs*shape[rank]; - rs *= stride[rank]; - off += rs - ds; + for (i += inc; i != j; i += inc) { + s2 = shape[i]; + shape[i] = (k *= s1); + s1 = s2; } - return off; + return shape; } -STC_DEF intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank, - const int32_t shape[], const int32_t stri[], +STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, + const int32_t shape[], const int32_t stride[], int rank, const int32_t a[][2]) { intptr_t off = 0; - int i = 0, j = 0; - int32_t t, s = 1; + int i = 0, oi = 0; + int32_t end; for (; i < rank; ++i) { - off *= stri[i]; - off += a[i][0]; - switch (a[i][1]) { - case 0: s *= stri[i]; c_ASSERT(c_LTu(a[i][0], shape[i])); continue; - case -1: t = shape[i]; break; - default: t = a[i][1]; break; + off += stride[i]*a[i][0]; + switch (a[i][1]) { + case 0: c_assert(c_LTu(a[i][0], shape[i])); continue; + case -1: end = shape[i]; break; + default: end = a[i][1]; } - odim[j] = t - a[i][0]; - ostri[j] = s*stri[i]; - c_ASSERT(c_LTu(0, odim[j]) & !c_LTu(shape[i], t)); - s = 1; ++j; + oshape[oi] = end - a[i][0]; + ostride[oi] = stride[i]; + c_assert(c_LTu(0, oshape[oi]) & !c_LTu(shape[i], end)); + ++oi; } - *orank = j; + *orank = oi; return off; } -#endif + #endif #undef i_opt #undef i_header #undef i_implement #undef i_static -#undef i_extern +#undef i_import 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..f8640ed1 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -20,85 +20,79 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CSTACK_H_INCLUDED #define CSTACK_H_INCLUDED +#include "ccommon.h" #include <stdlib.h> #include "forward.h" #endif // CSTACK_H_INCLUDED -#ifndef _i_prefix #define _i_prefix cstack_ -#endif #include "priv/template.h" #ifndef i_is_forward #ifdef i_capacity #define i_no_clone - _cx_deftypes(_c_cstack_fixed, _cx_self, i_key, i_capacity); + _cx_DEFTYPES(_c_cstack_fixed, _cx_Self, i_key, i_capacity); #else - _cx_deftypes(_c_cstack_types, _cx_self, i_key); + _cx_DEFTYPES(_c_cstack_types, _cx_Self, i_key); #endif #endif typedef i_keyraw _cx_raw; -STC_INLINE _cx_self _cx_memb(_init)(void) { - _cx_self cx; cx._len = 0; -#ifndef i_capacity - cx._cap = 0; cx.data = NULL; -#endif - return cx; -} - #ifdef i_capacity -STC_INLINE void _cx_memb(_create)(_cx_self* self) +STC_INLINE void _cx_MEMB(_init)(_cx_Self* self) { self->_len = 0; } #else -STC_INLINE void _cx_memb(_create)(_cx_self* self) - { self->_len = 0; self->_cap = 0; self->data = NULL; } +STC_INLINE _cx_Self _cx_MEMB(_init)(void) { + _cx_Self out = {0}; + return out; +} -STC_INLINE _cx_self _cx_memb(_with_capacity)(intptr_t cap) { - _cx_self out = {(_cx_value *) i_malloc(cap*c_sizeof(i_key)), 0, cap}; +STC_INLINE _cx_Self _cx_MEMB(_with_capacity)(intptr_t cap) { + _cx_Self out = {(_cx_value *) i_malloc(cap*c_sizeof(i_key)), 0, cap}; return out; } -STC_INLINE _cx_self _cx_memb(_with_size)(intptr_t size, i_key null) { - _cx_self out = {(_cx_value *) i_malloc(size*c_sizeof null), size, size}; +STC_INLINE _cx_Self _cx_MEMB(_with_size)(intptr_t size, i_key null) { + _cx_Self out = {(_cx_value *) i_malloc(size*c_sizeof null), size, size}; while (size) out.data[--size] = null; return out; } #endif // i_capacity -STC_INLINE void _cx_memb(_clear)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) { _cx_value *p = self->data + self->_len; while (p-- != self->data) { i_keydrop(p); } self->_len = 0; } -STC_INLINE void _cx_memb(_drop)(_cx_self* self) { - _cx_memb(_clear)(self); +STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) { + _cx_MEMB(_clear)(self); #ifndef i_capacity i_free(self->data); #endif } -STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) + +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) { return self->_len; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return !self->_len; } -STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) { +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) { #ifndef i_capacity return self->_cap; #else return i_capacity; #endif } -STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } -STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) { +STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t n) { if (n < self->_len) return true; #ifndef i_capacity _cx_value *t = (_cx_value *)i_realloc(self->data, n*c_sizeof *t); @@ -107,86 +101,106 @@ STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) { return false; } -STC_INLINE _cx_value* _cx_memb(_append_uninit)(_cx_self *self, intptr_t n) { +STC_INLINE _cx_value* _cx_MEMB(_append_uninit)(_cx_Self *self, intptr_t n) { intptr_t len = self->_len; - if (!_cx_memb(_reserve)(self, len + n)) return NULL; + if (!_cx_MEMB(_reserve)(self, len + n)) return NULL; self->_len += n; return self->data + len; } -STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) - { _cx_memb(_reserve)(self, self->_len); } +STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self) + { _cx_MEMB(_reserve)(self, self->_len); } -STC_INLINE const _cx_value* _cx_memb(_top)(const _cx_self* self) +STC_INLINE const _cx_value* _cx_MEMB(_top)(const _cx_Self* self) { return &self->data[self->_len - 1]; } -STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) +STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return (_cx_value*) &self->data[self->_len - 1]; } -STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) +STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return (_cx_value*) &self->data[0]; } -STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value val) { - if (self->_len == _cx_memb(_capacity)(self)) - if (!_cx_memb(_reserve)(self, self->_len*3/2 + 4)) +STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value val) { + if (self->_len == _cx_MEMB(_capacity)(self)) + if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + 4)) return NULL; _cx_value* vp = self->data + self->_len++; *vp = val; return vp; } -STC_INLINE void _cx_memb(_pop)(_cx_self* self) - { assert(!_cx_memb(_empty)(self)); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } +STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) + { c_assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } -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_value _cx_MEMB(_pull)(_cx_Self* self) + { c_assert(self->_len); return self->data[--self->_len]; } -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(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } -STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, intptr_t idx) - { assert(idx < self->_len); return self->data + idx; } -STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, intptr_t idx) - { assert(idx < self->_len); return self->data + idx; } +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) + { c_assert(idx < self->_len); return self->data + idx; } +STC_INLINE _cx_value* _cx_MEMB(_at_mut)(_cx_Self* self, intptr_t 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) - { return _cx_memb(_push)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) + { return _cx_MEMB(_push)(self, i_keyfrom(raw)); } #endif // !i_no_emplace #if !defined i_no_clone -STC_INLINE _cx_self _cx_memb(_clone)(_cx_self v) { - _cx_self out = {(_cx_value *)i_malloc(v._len*c_sizeof(_cx_value)), v._len, v._len}; +STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self v) { + _cx_Self out = {(_cx_value *)i_malloc(v._len*c_sizeof(_cx_value)), v._len, v._len}; if (!out.data) out._cap = 0; else for (intptr_t i = 0; i < v._len; ++v.data) out.data[i++] = i_keyclone((*v.data)); return out; } -STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) { +STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { if (self->data == other->data) return; - _cx_memb(_drop)(self); - *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); } -STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val) +STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val) { return i_keyclone(val); } -STC_INLINE i_keyraw _cx_memb(_value_toraw)(const _cx_value* val) +STC_INLINE i_keyraw _cx_MEMB(_value_toraw)(const _cx_value* val) { return i_keyto(val); } #endif // !i_no_clone -STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { +STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { return c_LITERAL(_cx_iter){self->_len ? (_cx_value*)self->data : NULL, - (_cx_value*)self->data + self->_len}; + (_cx_value*)self->data + self->_len}; } -STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) { return c_LITERAL(_cx_iter){NULL, (_cx_value*)self->data + self->_len}; } -STC_INLINE void _cx_memb(_next)(_cx_iter* it) +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { if (++it->ref == it->end) it->ref = NULL; } -STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) +STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) { if ((it.ref += n) >= it.end) it.ref = NULL ; return it; } +STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) + { return (it.ref - self->data); } + +STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) + { self->_len += n; } + +#if defined _i_has_eq || defined _i_has_cmp +STC_INLINE bool +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + if (self->_len != other->_len) return false; + for (intptr_t i = 0; i < self->_len; ++i) { + const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i); + if (!(i_eq((&_rx), (&_ry)))) return false; + } + return true; +} +#endif #include "priv/template2.h" diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 694c02d0..17943ad5 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -24,15 +24,13 @@ /* A string type with short string optimization in C99 with good small-string * optimization (22 characters with 24 bytes string). */ +#define i_header // external linkage by default. override with i_static. +#define _i_inc_utf8 +#include "utf8.h" + #ifndef CSTR_H_INCLUDED #define CSTR_H_INCLUDED -#if defined i_extern || defined STC_EXTERN -# define _i_extern -#endif -#include "ccommon.h" -#include "forward.h" -#include "utf8.h" #include <stdlib.h> /* malloc */ #include <stdarg.h> #include <stdio.h> /* vsnprintf */ @@ -70,15 +68,17 @@ STC_API char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2); /**************************** PUBLIC API **********************************/ #define cstr_lit(literal) cstr_from_n(literal, c_litstrlen(literal)) -#define cstr_NULL (c_LITERAL(cstr){{{0}, 0}}) +#define cstr_null (c_LITERAL(cstr){0}) #define cstr_toraw(self) cstr_str(self) STC_API char* cstr_reserve(cstr* self, intptr_t cap); STC_API void cstr_shrink_to_fit(cstr* self); STC_API char* cstr_resize(cstr* self, intptr_t size, char value); STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search); +STC_API intptr_t cstr_find_sv(const cstr* self, csview search); STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len); STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len); +STC_API char* cstr_append_uninit(cstr *self, intptr_t len); STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp); STC_API void cstr_erase(cstr* self, intptr_t pos, intptr_t len); STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len); @@ -86,6 +86,7 @@ STC_API cstr cstr_from_fmt(const char* fmt, ...); STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...); STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...); STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count); +STC_API uint64_t cstr_hash(const cstr *self); STC_INLINE cstr_buf cstr_buffer(cstr* s) { return cstr_is_long(s) @@ -98,7 +99,7 @@ STC_INLINE csview cstr_sv(const cstr* s) { } STC_INLINE cstr cstr_init(void) - { return cstr_NULL; } + { return cstr_null; } STC_INLINE cstr cstr_from_n(const char* str, const intptr_t len) { cstr s; @@ -133,7 +134,7 @@ STC_INLINE cstr* cstr_take(cstr* self, const cstr s) { STC_INLINE cstr cstr_move(cstr* self) { cstr tmp = *self; - *self = cstr_NULL; + *self = cstr_null; return tmp; } @@ -169,31 +170,14 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self) // utf8 methods defined in/depending on src/utf8code.c: -extern cstr cstr_tocase(csview sv, int k); - -STC_INLINE cstr cstr_casefold_sv(csview sv) - { return cstr_tocase(sv, 0); } - -STC_INLINE cstr cstr_tolower_sv(csview sv) - { return cstr_tocase(sv, 1); } - -STC_INLINE cstr cstr_toupper_sv(csview sv) - { return cstr_tocase(sv, 2); } - -STC_INLINE cstr cstr_tolower(const char* str) - { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } - -STC_INLINE cstr cstr_toupper(const char* str) - { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } - -STC_INLINE void cstr_lowercase(cstr* self) - { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } - -STC_INLINE void cstr_uppercase(cstr* self) - { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } - -STC_INLINE bool cstr_valid_utf8(const cstr* self) - { return utf8_valid(cstr_str(self)); } +STC_API cstr cstr_casefold_sv(csview sv); +STC_API cstr cstr_tolower_sv(csview sv); +STC_API cstr cstr_toupper_sv(csview sv); +STC_API cstr cstr_tolower(const char* str); +STC_API cstr cstr_toupper(const char* str); +STC_API void cstr_lowercase(cstr* self); +STC_API void cstr_uppercase(cstr* self); +STC_API bool cstr_valid_utf8(const cstr* self); // other utf8 @@ -245,14 +229,6 @@ STC_INLINE cstr_iter cstr_advance(cstr_iter it, intptr_t pos) { STC_INLINE void cstr_clear(cstr* self) { _cstr_set_size(self, 0); } -STC_INLINE char* cstr_append_uninit(cstr *self, intptr_t len) { - intptr_t sz = cstr_size(self); - char* d = cstr_reserve(self, sz + len); - if (!d) return NULL; - _cstr_set_size(self, sz + len); - return d + sz; -} - STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2) { return strcmp(cstr_str(s1), cstr_str(s2)); } @@ -283,8 +259,6 @@ STC_INLINE intptr_t cstr_find(const cstr* self, const char* search) { return res ? (res - str) : c_NPOS; } -STC_API intptr_t cstr_find_sv(const cstr* self, csview search); - STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search) { return cstr_find(self, cstr_str(&search)); } @@ -364,13 +338,11 @@ STC_INLINE void cstr_pop(cstr* self) { STC_INLINE char* cstr_append(cstr* self, const char* str) { return cstr_append_n(self, str, c_strlen(str)); } -STC_INLINE void cstr_append_sv(cstr* self, csview sv) - { cstr_append_n(self, sv.str, sv.size); } +STC_INLINE char* cstr_append_sv(cstr* self, csview sv) + { return cstr_append_n(self, sv.str, sv.size); } -STC_INLINE char* cstr_append_s(cstr* self, cstr s) { - csview sv = cstr_sv(&s); - return cstr_append_n(self, sv.str, sv.size); -} +STC_INLINE char* cstr_append_s(cstr* self, cstr s) + { return cstr_append_sv(self, cstr_sv(&s)); } #define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__) #define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, INT32_MAX) @@ -405,13 +377,15 @@ STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) { cstr_replace_at_sv(self, pos, 0, sv); } - STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } -STC_API uint64_t cstr_hash(const cstr *self); +#endif // CSTR_H_INCLUDED + +/* -------------------------- UTF8 CASE CONVERSION ------------------------- */ +#if defined(i_import) && !defined(CSTR_X_INCLUDED) +#define CSTR_X_INCLUDED -#ifdef _i_extern static struct { int (*conv_asc)(int); uint32_t (*conv_utf)(uint32_t); @@ -420,7 +394,7 @@ fn_tocase[] = {{tolower, utf8_casefold}, {tolower, utf8_tolower}, {toupper, utf8_toupper}}; -cstr cstr_tocase(csview sv, int k) { +STC_DEF cstr cstr_tocase(csview sv, int k) { cstr out = cstr_init(); char *buf = cstr_reserve(&out, sv.size*3/2); const char *end = sv.str + sv.size; @@ -440,10 +414,36 @@ cstr cstr_tocase(csview sv, int k) { cstr_shrink_to_fit(&out); return out; } -#endif + +STC_DEF cstr cstr_casefold_sv(csview sv) + { return cstr_tocase(sv, 0); } + +STC_DEF cstr cstr_tolower_sv(csview sv) + { return cstr_tocase(sv, 1); } + +STC_DEF cstr cstr_toupper_sv(csview sv) + { return cstr_tocase(sv, 2); } + +STC_DEF cstr cstr_tolower(const char* str) + { return cstr_tolower_sv(c_sv(str, c_strlen(str))); } + +STC_DEF cstr cstr_toupper(const char* str) + { return cstr_toupper_sv(c_sv(str, c_strlen(str))); } + +STC_DEF void cstr_lowercase(cstr* self) + { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); } + +STC_DEF void cstr_uppercase(cstr* self) + { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); } + +STC_DEF bool cstr_valid_utf8(const cstr* self) + { return utf8_valid(cstr_str(self)); } +#endif // i_import /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined i_implement || defined i_static +#ifndef CSTR_C_INCLUDED +#define CSTR_C_INCLUDED STC_DEF uint64_t cstr_hash(const cstr *self) { csview sv = cstr_sv(self); @@ -505,7 +505,8 @@ STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) { if (cap > cstr_s_cap) { char* data = (char *)c_malloc(cap + 1); const intptr_t len = cstr_s_size(self); - c_memcpy(data, self->sml.data, cstr_s_cap + 1); + /* copy full short buffer to emulate realloc() */ + c_memcpy(data, self->sml.data, sizeof self->sml); self->lon.data = data; self->lon.size = (size_t)len; cstr_l_set_cap(self, cap); @@ -551,6 +552,14 @@ STC_DEF char* cstr_append_n(cstr* self, const char* str, const intptr_t len) { return r.data; } +STC_DEF char* cstr_append_uninit(cstr *self, intptr_t len) { + cstr_buf r = cstr_buffer(self); + if (r.size + len > r.cap && !(r.data = cstr_reserve(self, r.size*3/2 + len))) + return NULL; + _cstr_set_size(self, r.size + len); + return r.data + r.size; +} + STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { int c = fgetc(fp); if (c == EOF) @@ -571,9 +580,8 @@ 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) { - cstr out = cstr_NULL; +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; if (search.size) @@ -625,7 +633,7 @@ STC_DEF intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list #endif STC_DEF cstr cstr_from_fmt(const char* fmt, ...) { - cstr s = cstr_NULL; + cstr s = cstr_null; va_list args; va_start(args, fmt); cstr_vfmt(&s, 0, fmt, args); @@ -649,14 +657,14 @@ STC_DEF intptr_t cstr_printf(cstr* self, const char* fmt, ...) { va_end(args); return n; } - +#endif // CSTR_C_INCLUDED #endif // i_implement + #if defined __GNUC__ && !defined __clang__ # pragma GCC diagnostic pop #endif -#endif // CSTR_H_INCLUDED #undef i_opt #undef i_header #undef i_static #undef i_implement -#undef _i_extern +#undef i_import diff --git a/include/stc/csview.h b/include/stc/csview.h index bba3aea3..85965928 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -20,25 +20,30 @@ * 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 -#include "ccommon.h" -#include "forward.h" -#include "utf8.h" - -#define csview_NULL c_sv_1("") -#define csview_init() csview_NULL +#define csview_null c_sv_1("") +#define csview_init() csview_null #define csview_drop(p) c_default_drop(p) #define csview_clone(sv) c_default_clone(sv) #define csview_lit(literal) c_sv_1(literal) #define csview_from_n(str, n) c_sv_2(str, n) -STC_API intptr_t csview_find_sv(csview sv, csview search); +STC_API csview_iter csview_advance(csview_iter it, intptr_t pos); +STC_API intptr_t csview_find_sv(csview sv, csview search); +STC_API uint64_t csview_hash(const csview *self); +STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); +STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); +STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); STC_INLINE csview csview_from(const char* str) { return c_LITERAL(csview){str, c_strlen(str)}; } -STC_INLINE void csview_clear(csview* self) { *self = csview_NULL; } +STC_INLINE void csview_clear(csview* self) { *self = csview_null; } STC_INLINE intptr_t csview_size(csview sv) { return sv.size; } STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } @@ -88,15 +93,6 @@ STC_INLINE void csview_next(csview_iter* it) { it->u8.chr.size = utf8_chr_size(it->ref); if (it->ref == it->u8.end) it->ref = NULL; } -STC_INLINE csview_iter csview_advance(csview_iter it, intptr_t pos) { - int inc = -1; - if (pos > 0) pos = -pos, inc = 1; - while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80; - it.u8.chr.size = utf8_chr_size(it.ref); - if (it.ref == it.u8.end) it.ref = NULL; - return it; -} - /* utf8 */ STC_INLINE intptr_t csview_u8_size(csview sv) @@ -111,10 +107,6 @@ STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c { return utf8_valid_n(sv.str, sv.size); } -STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); -STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); -STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); - #define c_fortoken_sv(it, inputsv, sep) \ for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \ it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \ @@ -123,6 +115,22 @@ STC_API csview csview_token(csview sv, const char* sep, intptr_t* start); #define c_fortoken(it, input, sep) \ c_fortoken_sv(it, csview_from(input), sep) +/* ---- Container helper functions ---- */ + +STC_INLINE int csview_cmp(const csview* x, const csview* y) { + intptr_t n = x->size < y->size ? x->size : y->size; + int c = c_memcmp(x->str, y->str, n); + return c ? c : (int)(x->size - y->size); +} + +STC_INLINE int csview_icmp(const csview* x, const csview* y) + { return utf8_icmp_sv(*x, *y); } + +STC_INLINE bool csview_eq(const csview* x, const csview* y) + { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } + +#endif // CSVIEW_H_INCLUDED + /* csview interaction with cstr: */ #ifdef CSTR_H_INCLUDED @@ -140,26 +148,21 @@ STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len) { return csview_u8_substr(cstr_sv(self), bytepos, u8len); } - #endif -/* ---- Container helper functions ---- */ - -STC_INLINE int csview_cmp(const csview* x, const csview* y) { - intptr_t n = x->size < y->size ? x->size : y->size; - int c = c_memcmp(x->str, y->str, n); - return c ? c : (int)(x->size - y->size); -} - -STC_INLINE int csview_icmp(const csview* x, const csview* y) - { return utf8_icmp_sv(*x, *y); } - -STC_INLINE bool csview_eq(const csview* x, const csview* y) - { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); } - -STC_API uint64_t csview_hash(const csview *self); /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#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); @@ -199,11 +202,10 @@ STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) { *start += tok.size + sep_size; return tok; } - -#endif -#endif -#undef i_opt +#endif // CSVIEW_C_INCLUDED +#endif // i_implement +#undef i_static #undef i_header #undef i_implement -#undef i_static -#undef i_extern +#undef i_import +#undef i_opt diff --git a/include/stc/cvec.h b/include/stc/cvec.h index a1aa74b2..d08e382f 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -22,6 +22,7 @@ */ /* +#define i_implement #include <stc/cstr.h> #include <stc/forward.h> @@ -39,11 +40,11 @@ struct MyStruct { #include <stc/cvec.h> #define i_key int -#define i_is_forward // forward declared +#define i_is_forward #define i_tag i32 #include <stc/cvec.h> -int main() { +int main(void) { cvec_i32 vec = {0}; cvec_i32_push(&vec, 123); cvec_i32_drop(&vec); @@ -57,9 +58,10 @@ int main() { cvec_str_drop(&svec); } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CVEC_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include <stdlib.h> #include <string.h> @@ -68,173 +70,164 @@ 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 - _cx_deftypes(_c_cvec_types, _cx_self, i_key); + _cx_DEFTYPES(_c_cvec_types, _cx_Self, i_key); #endif typedef i_keyraw _cx_raw; -STC_API _cx_self _cx_memb(_init)(void); -STC_API void _cx_memb(_drop)(_cx_self* self); -STC_API void _cx_memb(_clear)(_cx_self* self); -STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t cap); -STC_API bool _cx_memb(_resize)(_cx_self* self, intptr_t size, i_key null); -STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value); -STC_API _cx_iter _cx_memb(_erase_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); -#if !defined i_no_cmp || defined _i_has_eq -STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw); +STC_API _cx_Self _cx_MEMB(_init)(void); +STC_API void _cx_MEMB(_drop)(_cx_Self* self); +STC_API void _cx_MEMB(_clear)(_cx_Self* self); +STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t cap); +STC_API bool _cx_MEMB(_resize)(_cx_Self* self, intptr_t size, i_key null); +STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); +STC_API _cx_iter _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n); +STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n); +#if defined _i_has_eq || defined _i_has_cmp +STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw); #endif -#ifndef i_no_cmp -STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y); -STC_API _cx_iter _cx_memb(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound); +#if defined _i_has_cmp +STC_API int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y); +STC_API _cx_iter _cx_MEMB(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound); #endif -STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); } +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); } #if !defined i_no_emplace -STC_API _cx_iter _cx_memb(_emplace_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_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n) - { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } -STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val) +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx); +STC_API _cx_iter _cx_MEMB(_copy_n)(_cx_Self* self, intptr_t idx, const _cx_value arr[], intptr_t n); +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) + { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } +STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val) { return i_keyclone(val); } -STC_INLINE void _cx_memb(_copy)(_cx_self* self, const _cx_self* other) { +STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) { if (self->data == other->data) return; - _cx_memb(_clear)(self); - _cx_memb(_copy_range)(self, self->data, other->data, - other->data + other->_len); + _cx_MEMB(_clear)(self); + _cx_MEMB(_copy_n)(self, 0, other->data, other->_len); } #endif // !i_no_clone -STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) { return self->_len; } -STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) { return self->_cap; } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return !self->_len; } -STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* val) { return i_keyto(val); } -STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; } -STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) +STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) { return self->_len; } +STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) { return self->_cap; } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return !self->_len; } +STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) { return i_keyto(val); } +STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return self->data; } +STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return self->data + self->_len - 1; } -STC_INLINE void _cx_memb(_pop)(_cx_self* self) - { assert(!_cx_memb(_empty)(self)); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } -STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) - { return _cx_memb(_push)(self, value); } -STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) { _cx_memb(_pop)(self); } - -STC_INLINE _cx_self -_cx_memb(_with_size)(const intptr_t size, i_key null) { - _cx_self cx = _cx_memb(_init)(); - _cx_memb(_resize)(&cx, size, null); +STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) + { c_assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); } +STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) + { 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); } + +STC_INLINE _cx_Self +_cx_MEMB(_with_size)(const intptr_t size, i_key null) { + _cx_Self cx = _cx_MEMB(_init)(); + _cx_MEMB(_resize)(&cx, size, null); return cx; } -STC_INLINE _cx_self -_cx_memb(_with_capacity)(const intptr_t cap) { - _cx_self cx = _cx_memb(_init)(); - _cx_memb(_reserve)(&cx, cap); +STC_INLINE _cx_Self +_cx_MEMB(_with_capacity)(const intptr_t cap) { + _cx_Self cx = _cx_MEMB(_init)(); + _cx_MEMB(_reserve)(&cx, cap); return cx; } STC_INLINE void -_cx_memb(_shrink_to_fit)(_cx_self* self) { - _cx_memb(_reserve)(self, _cx_memb(_size)(self)); +_cx_MEMB(_shrink_to_fit)(_cx_Self* self) { + _cx_MEMB(_reserve)(self, _cx_MEMB(_size)(self)); } - STC_INLINE _cx_iter -_cx_memb(_insert)(_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_MEMB(_insert_n)(_cx_Self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) { + _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n); + if (it.ref) + c_memcpy(it.ref, arr, n*c_sizeof *arr); + return it; } STC_INLINE _cx_iter -_cx_memb(_insert_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 value) { + return _cx_MEMB(_insert_n)(self, _it_ptr(it) - self->data, &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); -} -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_at)(_cx_Self* self, _cx_iter it) { + return _cx_MEMB(_erase_n)(self, it.ref - self->data, 1); } STC_INLINE _cx_iter -_cx_memb(_erase_range)(_cx_self* self, _cx_iter i1, _cx_iter i2) { - return _cx_memb(_erase_range_p)(self, i1.ref, _it2_ptr(i1, i2)); +_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter i1, _cx_iter i2) { + return _cx_MEMB(_erase_n)(self, i1.ref - self->data, _it2_ptr(i1, i2) - i1.ref); } STC_INLINE const _cx_value* -_cx_memb(_at)(const _cx_self* self, const intptr_t idx) { - assert(idx < self->_len); return self->data + idx; +_cx_MEMB(_at)(const _cx_Self* self, const intptr_t 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; +_cx_MEMB(_at_mut)(_cx_Self* self, const intptr_t idx) { + c_assert(idx < self->_len); return self->data + idx; } -STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { +STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { intptr_t n = self->_len; return c_LITERAL(_cx_iter){n ? self->data : NULL, self->data + n}; } -STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) { return c_LITERAL(_cx_iter){NULL, self->data + self->_len}; } -STC_INLINE void _cx_memb(_next)(_cx_iter* it) +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { if (++it->ref == it->end) it->ref = NULL; } -STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n) +STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) { if ((it.ref += n) >= it.end) it.ref = NULL; return it; } -STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it) +STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it) { return (it.ref - self->data); } -#if !defined i_no_cmp || defined _i_has_eq +STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n) + { self->_len += n; } + +#if defined _i_has_eq || defined _i_has_cmp STC_INLINE _cx_iter -_cx_memb(_find)(const _cx_self* self, _cx_raw raw) { - return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw); +_cx_MEMB(_find)(const _cx_Self* self, _cx_raw raw) { + return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw); } STC_INLINE const _cx_value* -_cx_memb(_get)(const _cx_self* self, _cx_raw raw) { - return _cx_memb(_find)(self, raw).ref; +_cx_MEMB(_get)(const _cx_Self* self, _cx_raw raw) { + return _cx_MEMB(_find)(self, raw).ref; } STC_INLINE _cx_value* -_cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw) - { return (_cx_value*) _cx_memb(_get)(self, raw); } +_cx_MEMB(_get_mut)(const _cx_Self* self, _cx_raw raw) + { return (_cx_value*) _cx_MEMB(_get)(self, raw); } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { if (self->_len != other->_len) return false; for (intptr_t i = 0; i < self->_len; ++i) { const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i); @@ -243,42 +236,42 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { return true; } #endif -#ifndef i_no_cmp +#if defined _i_has_cmp STC_INLINE _cx_iter -_cx_memb(_binary_search)(const _cx_self* self, _cx_raw raw) { +_cx_MEMB(_binary_search)(const _cx_Self* self, _cx_raw raw) { _cx_iter lower; - return _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower); + return _cx_MEMB(_binary_search_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw, &lower); } STC_INLINE _cx_iter -_cx_memb(_lower_bound)(const _cx_self* self, _cx_raw raw) { +_cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_raw raw) { _cx_iter lower; - _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower); + _cx_MEMB(_binary_search_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw, &lower); return lower; } STC_INLINE void -_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) { +_cx_MEMB(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) { qsort(i1.ref, (size_t)(_it2_ptr(i1, i2) - i1.ref), sizeof(_cx_value), (int(*)(const void*, const void*)) cmp); } STC_INLINE void -_cx_memb(_sort)(_cx_self* self) { - _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp)); +_cx_MEMB(_sort)(_cx_Self* self) { + _cx_MEMB(_sort_range)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), _cx_MEMB(_value_cmp)); } -#endif // !c_no_cmp +#endif // _i_has_cmp /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) -STC_DEF _cx_self -_cx_memb(_init)(void) { - return c_LITERAL(_cx_self){NULL}; +STC_DEF _cx_Self +_cx_MEMB(_init)(void) { + return c_LITERAL(_cx_Self){NULL}; } STC_DEF void -_cx_memb(_clear)(_cx_self* self) { +_cx_MEMB(_clear)(_cx_Self* self) { if (self->_cap) { for (_cx_value *p = self->data, *q = p + self->_len; p != q; ) { --q; i_keydrop(q); @@ -288,15 +281,15 @@ _cx_memb(_clear)(_cx_self* self) { } STC_DEF void -_cx_memb(_drop)(_cx_self* self) { +_cx_MEMB(_drop)(_cx_Self* self) { if (self->_cap == 0) return; - _cx_memb(_clear)(self); + _cx_MEMB(_clear)(self); i_free(self->data); } STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) { if (cap > self->_cap || (cap && cap == self->_len)) { _cx_value* d = (_cx_value*)i_realloc(self->data, cap*c_sizeof(i_key)); if (!d) @@ -308,8 +301,8 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) { } STC_DEF bool -_cx_memb(_resize)(_cx_self* self, const intptr_t len, i_key null) { - if (!_cx_memb(_reserve)(self, len)) +_cx_MEMB(_resize)(_cx_Self* self, const intptr_t len, i_key null) { + if (!_cx_MEMB(_reserve)(self, len)) return false; const intptr_t n = self->_len; for (intptr_t i = len; i < n; ++i) @@ -321,9 +314,9 @@ _cx_memb(_resize)(_cx_self* self, const intptr_t len, i_key null) { } STC_DEF _cx_value* -_cx_memb(_push)(_cx_self* self, i_key value) { +_cx_MEMB(_push)(_cx_Self* self, i_key value) { if (self->_len == self->_cap) - if (!_cx_memb(_reserve)(self, self->_len*3/2 + 4)) + if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + 4)) return NULL; _cx_value *v = self->data + self->_len++; *v = value; @@ -331,75 +324,60 @@ _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); +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self cx) { + _cx_Self out = _cx_MEMB(_init)(); + _cx_MEMB(_copy_n)(&out, 0, cx.data, cx._len); return out; } STC_DEF _cx_iter -_cx_memb(_copy_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_has_eq || defined _i_has_cmp -#if !defined i_no_cmp || defined _i_has_eq STC_DEF _cx_iter -_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { +_cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { const _cx_value* p2 = _it2_ptr(i1, i2); for (; i1.ref != p2; ++i1.ref) { const _cx_raw r = i_keyto(i1.ref); @@ -410,10 +388,10 @@ _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { return i2; } #endif -#ifndef i_no_cmp +#if defined _i_has_cmp STC_DEF _cx_iter -_cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw, +_cx_MEMB(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw, _cx_iter* lower_bound) { _cx_value* w[2] = {i1.ref, _it2_ptr(i1, i2)}; _cx_iter mid = i1; @@ -430,12 +408,12 @@ _cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw, i1.ref = NULL; return i1; } -STC_DEF int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { +STC_DEF int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y) { const _cx_raw rx = i_keyto(x); const _cx_raw ry = i_keyto(y); return i_cmp((&rx), (&ry)); } -#endif // !c_no_cmp +#endif // _i_has_cmp #endif // i_implement #define CVEC_H_INCLUDED #include "priv/template2.h" diff --git a/include/stc/extend.h b/include/stc/extend.h index 66b3ebd1..52d59414 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -43,10 +43,12 @@ #define _i_val i_val #endif -#ifdef _i_key - c_PASTE(forward_, i_con)(i_type, _i_key, _i_val); +#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_con)(i_type, _i_val); + c_PASTE(forward_, i_base)(i_type, _i_val); #endif typedef struct { @@ -54,13 +56,16 @@ 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() c_container_of(self, _cx_MEMB(_ext), get) +// Note: i_less: c_extend() accessible for cpque types +// i_cmp: c_extend() accessible for csmap and csset types +// i_hash/i_eq: c_extend() accessible for cmap and cset types #define i_is_forward -#define _i_inc <stc/i_con.h> +#define _i_inc <stc/i_base.h> #include _i_inc #undef _i_inc #undef _i_key #undef _i_val -#undef i_con +#undef i_base #undef i_extend diff --git a/include/stc/forward.h b/include/stc/forward.h index 31e67e7d..484a8b63 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -24,17 +24,16 @@ #define STC_FORWARD_H_INCLUDED #include <stdint.h> +#include <stddef.h> #define forward_carc(CX, VAL) _c_carc_types(CX, VAL) #define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL) #define forward_cdeq(CX, VAL) _c_cdeq_types(CX, VAL) #define forward_clist(CX, VAL) _c_clist_types(CX, VAL) -#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, int32_t, c_true, c_false) -#define forward_cmap64(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, int64_t, c_true, c_false) -#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, int32_t, c_false, c_true) -#define forward_cset64(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, int64_t, c_false, c_true) -#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, int32_t, c_true, c_false) -#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, int32_t, c_false, c_true) +#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, c_true, c_false) +#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, c_false, c_true) +#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, c_true, c_false) +#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, c_false, c_true) #define forward_cstack(CX, VAL) _c_cstack_types(CX, VAL) #define forward_cpque(CX, VAL) _c_cpque_types(CX, VAL) #define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL) @@ -83,12 +82,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; \ @@ -103,10 +107,11 @@ typedef union { SELF##_node *last; \ } SELF -#define _c_chash_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \ +typedef struct chash_slot chash_slot; + +#define _c_chash_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \ typedef KEY SELF##_key; \ typedef VAL SELF##_mapped; \ - typedef SZ SELF##_ssize; \ \ typedef SET_ONLY( SELF##_key ) \ MAP_ONLY( struct SELF##_value ) \ @@ -119,19 +124,18 @@ typedef union { \ typedef struct { \ SELF##_value *ref, *_end; \ - uint8_t* _hx; \ + chash_slot* sref; \ } SELF##_iter; \ \ typedef struct SELF { \ - SELF##_value* table; \ - uint8_t* _hashx; \ - SELF##_ssize size, bucket_count; \ + SELF##_value* data; \ + chash_slot* slot; \ + intptr_t size, bucket_count; \ } SELF -#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \ +#define _c_aatree_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \ typedef KEY SELF##_key; \ typedef VAL SELF##_mapped; \ - typedef SZ SELF##_ssize; \ typedef struct SELF##_node SELF##_node; \ \ typedef SET_ONLY( SELF##_key ) \ @@ -147,12 +151,12 @@ typedef union { SELF##_value *ref; \ SELF##_node *_d; \ int _top; \ - SELF##_ssize _tn, _st[36]; \ + int32_t _tn, _st[36]; \ } SELF##_iter; \ \ typedef struct SELF { \ SELF##_node *nodes; \ - SELF##_ssize root, disp, head, size, cap; \ + int32_t root, disp, head, size, cap; \ } SELF #define _c_cstack_fixed(SELF, VAL, CAP) \ diff --git a/include/stc/priv/altnames.h b/include/stc/priv/linkage.h index 723b6a66..7f63f5f1 100644 --- a/include/stc/priv/altnames.h +++ b/include/stc/priv/linkage.h @@ -20,15 +20,21 @@ * 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 +#undef STC_API +#undef STC_DEF + +#ifdef i_extern // [deprecated] +# define i_import +#endif +#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \ + defined(i_implement) || defined(STC_IMPLEMENT)) + #define STC_API extern + #define STC_DEF +#else + #define i_static + #define STC_API static inline + #define STC_DEF static inline +#endif +#if defined(STC_IMPLEMENT) || defined(i_import) + #define i_implement +#endif diff --git a/include/stc/priv/raii.h b/include/stc/priv/raii.h deleted file mode 100644 index bb41e0d1..00000000 --- a/include/stc/priv/raii.h +++ /dev/null @@ -1,27 +0,0 @@ -#define c_defer(...) \ - for (int _i = 1; _i; _i = 0, __VA_ARGS__) - -#define c_with(...) c_MACRO_OVERLOAD(c_with, __VA_ARGS__) -#define c_with_2(declvar, drop) \ - for (declvar, *_i, **_ip = &_i; _ip; _ip = 0, drop) -#define c_with_3(declvar, pred, drop) \ - for (declvar, *_i, **_ip = &_i; _ip && (pred); _ip = 0, drop) - -#define c_scope(...) c_MACRO_OVERLOAD(c_scope, __VA_ARGS__) -#define c_scope_2(init, drop) \ - for (int _i = (init, 1); _i; _i = 0, drop) -#define c_scope_3(init, pred, drop) \ - for (int _i = (init, 1); _i && (pred); _i = 0, drop) - -#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__) -#define c_auto_2(C, a) \ - c_with_2(C a = C##_init(), C##_drop(&a)) -#define c_auto_3(C, a, b) \ - c_with_2(c_EXPAND(C a = C##_init(), b = C##_init()), \ - (C##_drop(&b), C##_drop(&a))) -#define c_auto_4(C, a, b, c) \ - c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init()), \ - (C##_drop(&c), C##_drop(&b), C##_drop(&a))) -#define c_auto_5(C, a, b, c, d) \ - c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \ - (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a))) diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index 16ef51af..30ed5732 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -20,34 +20,28 @@ * 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 #define STC_TEMPLATE_H_INCLUDED - #define _cx_self i_type - #define _cx_memb(name) c_PASTE(_cx_self, name) - #define _cx_deftypes(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__)) - #define _cx_value _cx_memb(_value) - #define _cx_key _cx_memb(_key) - #define _cx_mapped _cx_memb(_mapped) - #define _cx_raw _cx_memb(_raw) - #define _cx_keyraw _cx_memb(_keyraw) - #define _cx_iter _cx_memb(_iter) - #define _cx_result _cx_memb(_result) - #define _cx_node _cx_memb(_node) + #define _cx_Self i_type + #define _cx_MEMB(name) c_PASTE(_cx_Self, name) + #define _cx_DEFTYPES(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__)) + #define _cx_value _cx_MEMB(_value) + #define _cx_key _cx_MEMB(_key) + #define _cx_mapped _cx_MEMB(_mapped) + #define _cx_raw _cx_MEMB(_raw) + #define _cx_keyraw _cx_MEMB(_keyraw) + #define _cx_iter _cx_MEMB(_iter) + #define _cx_result _cx_MEMB(_result) + #define _cx_node _cx_MEMB(_node) #endif #ifndef i_type #define i_type c_PASTE(_i_prefix, i_tag) #endif -#ifndef i_ssize - #define i_ssize intptr_t -#endif - #ifndef i_allocator #define i_allocator c #endif @@ -108,14 +102,16 @@ #if c_option(c_no_emplace) #define i_no_emplace #endif -#ifdef i_eq - #define _i_has_eq +#if c_option(c_native_cmp) + #define i_native_cmp +#endif +#if c_option(c_no_clone) || defined _i_carc + #define i_no_clone #endif #if defined i_key_str #define i_keyclass cstr #define i_rawclass crawstr - #define i_keyfrom cstr_from #ifndef i_tag #define i_tag str #endif @@ -159,20 +155,28 @@ #endif #ifdef i_rawclass - #if !defined i_cmp && !defined i_no_cmp + #if !(defined i_cmp || defined i_no_cmp) #define i_cmp c_PASTE(i_keyraw, _cmp) #endif - #if !defined i_hash && !defined i_no_hash + #if !(defined i_hash || defined i_no_hash || defined i_no_cmp) #define i_hash c_PASTE(i_keyraw, _hash) #endif #endif +#if !defined i_keyraw && !defined i_no_clone + #if !defined i_keyfrom && defined i_keyclone + #define i_keyfrom i_keyclone + #elif !defined i_keyclone && defined i_keyfrom + #define i_keyclone i_keyfrom + #endif +#endif + #if !defined i_key #error "No i_key or i_val defined" #elif defined i_keyraw ^ defined i_keyto - #error "Both i_keyraw/valraw and i_keyto/valto must be defined, if any" -#elif defined i_keyfrom && !defined i_keyraw - #error "i_keyfrom/valfrom defined without i_keyraw/valraw" + #error "Both i_keyraw/i_valraw and i_keyto/i_valto must be defined, if any" +#elif !defined i_no_clone && (defined i_keyclone ^ defined i_keydrop) + #error "Both i_keyclone/i_valclone and i_keydrop/i_valdrop must be defined, if any" #elif defined i_from || defined i_drop #error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead" #endif @@ -180,18 +184,13 @@ #ifndef i_tag #define i_tag i_key #endif -#if c_option(c_no_clone) - #define i_no_clone -#elif !(defined i_keyclone || defined i_no_clone) && (defined i_keydrop || defined i_keyraw) - #error i_keyclone/valclone should be defined when i_keydrop/valdrop or i_keyraw/valraw is defined -#endif #ifndef i_keyraw #define i_keyraw i_key #endif #ifndef i_keyfrom #define i_keyfrom c_default_clone #else - #define _i_has_from + #define i_has_emplace #endif #ifndef i_keyto #define i_keyto c_default_toraw @@ -203,24 +202,33 @@ #define i_keydrop c_default_drop #endif -// i_eq, i_less, i_cmp -#if !defined i_eq && (defined i_cmp || defined i_less) - #define i_eq(x, y) !(i_cmp(x, y)) -#elif !defined i_eq - #define i_eq c_default_eq -#endif -#if defined i_less && defined i_cmp - #error "Only one of i_less and i_cmp may be defined" -#elif !defined i_less && !defined i_cmp - #define i_less c_default_less -#elif !defined i_less - #define i_less(x, y) (i_cmp(x, y)) < 0 -#endif -#ifndef i_cmp - #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y)) +#ifndef i_no_cmp + #if defined i_cmp || defined i_less || defined i_native_cmp + #define _i_has_cmp + #endif + #if defined i_eq || defined i_native_cmp + #define _i_has_eq + #endif + + // i_eq, i_less, i_cmp + #if !defined i_eq && (defined i_cmp || defined i_less) + #define i_eq(x, y) !(i_cmp(x, y)) + #elif !defined i_eq + #define i_eq(x, y) *x == *y + #endif + #if defined i_cmp && defined i_less + #error "Only one of i_cmp and i_less may be defined" + #elif defined i_cmp + #define i_less(x, y) (i_cmp(x, y)) < 0 + #elif !defined i_less + #define i_less(x, y) *x < *y + #endif + #ifndef i_cmp + #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y)) + #endif #endif -#ifndef i_hash +#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_native_cmp) #define i_hash c_default_hash #endif @@ -228,8 +236,7 @@ #ifdef i_val_str #define i_valclass cstr - #define i_valraw crawstr - #define i_valfrom cstr_from + #define i_valraw const char* #elif defined i_val_ssv #define i_valclass cstr #define i_valraw csview @@ -256,20 +263,29 @@ #endif #endif +#if !defined i_valraw && !defined i_no_clone + #if !defined i_valfrom && defined i_valclone + #define i_valfrom i_valclone + #elif !defined i_valclone && defined i_valfrom + #define i_valclone i_valfrom + #endif +#endif + #ifndef i_val #error "i_val* must be defined for maps" +#elif defined i_valraw ^ defined i_valto + #error "Both i_valraw and i_valto must be defined, if any" +#elif !defined i_no_clone && (defined i_valclone ^ defined i_valdrop) + #error "Both i_valclone and i_valdrop must be defined, if any" #endif -#if !(defined i_valclone || defined i_no_clone) && (defined i_valdrop || defined i_valraw) - #error i_valclone should be defined when i_valdrop or i_valraw is defined -#endif #ifndef i_valraw #define i_valraw i_val #endif #ifndef i_valfrom #define i_valfrom c_default_clone #else - #define _i_has_from + #define i_has_emplace #endif #ifndef i_valto #define i_valto c_default_toraw @@ -289,6 +305,7 @@ #ifndef i_valraw #define i_valraw i_keyraw #endif -#ifndef _i_has_from +#ifndef i_has_emplace #define i_no_emplace #endif +#endif diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index 27c6a890..def5d01e 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 @@ -30,7 +33,6 @@ #undef i_hash #undef i_rawclass #undef i_capacity -#undef i_ssize #undef i_val #undef i_val_str @@ -57,7 +59,7 @@ #undef i_header #undef i_implement #undef i_static -#undef i_extern +#undef i_import #undef i_allocator #undef i_malloc @@ -65,14 +67,17 @@ #undef i_realloc #undef i_free +#undef i_native_cmp #undef i_no_cmp #undef i_no_hash #undef i_no_clone #undef i_no_emplace #undef i_is_forward +#undef i_has_emplace +#undef _i_has_cmp +#undef _i_has_eq #undef _i_prefix #undef _i_expandby -#undef _i_has_from -#undef _i_has_eq #undef _i_template +#endif diff --git a/include/stc/utf8.h b/include/stc/utf8.h index a4cc3846..6d12856f 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -1,11 +1,34 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "priv/linkage.h" + #ifndef UTF8_H_INCLUDED #define UTF8_H_INCLUDED +#include "ccommon.h" #include <ctype.h> #include "forward.h" -#include "ccommon.h" -// utf8 methods defined in src/utf8code.c: enum { U8G_Cc, U8G_Lt, U8G_Nd, U8G_Nl, U8G_Pc, U8G_Pd, U8G_Pf, U8G_Pi, @@ -16,6 +39,7 @@ enum { U8G_SIZE }; +// utf8 methods defined in src/utf8code.c: extern bool utf8_isgroup(int group, uint32_t c); extern bool utf8_isalpha(uint32_t c); extern uint32_t utf8_casefold(uint32_t c); @@ -51,9 +75,9 @@ STC_INLINE bool utf8_isspace(uint32_t c) { /* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */ typedef struct { uint32_t state, codep; } utf8_decode_t; +extern const uint8_t utf8_dtab[]; /* utf8code.c */ STC_INLINE uint32_t utf8_decode(utf8_decode_t* d, const uint32_t byte) { - extern const uint8_t utf8_dtab[]; /* utf8code.c */ const uint32_t type = utf8_dtab[byte]; d->codep = d->state ? (byte & 0x3fu) | (d->codep << 6) : (0xffU >> type) & byte; @@ -112,9 +136,16 @@ STC_INLINE const char* utf8_at(const char *s, intptr_t index) { STC_INLINE intptr_t utf8_pos(const char* s, intptr_t index) { return (intptr_t)(utf8_at(s, index) - s); } - #endif // UTF8_H_INCLUDED -#if defined(i_extern) + +#if defined i_import || (defined i_implement && !defined _i_inc_utf8) # include "../../src/utf8code.c" -# undef i_extern #endif +#ifndef _i_inc_utf8 +#undef i_static +#undef i_header +#undef i_implement +#undef i_import +#undef i_opt +#endif +#undef _i_inc_utf8 diff --git a/misc/benchmarks/external/ankerl/unordered_dense.h b/misc/benchmarks/external/ankerl/unordered_dense.h index faad051d..b8cacea7 100644 --- a/misc/benchmarks/external/ankerl/unordered_dense.h +++ b/misc/benchmarks/external/ankerl/unordered_dense.h @@ -1,7 +1,7 @@ ///////////////////////// ankerl::unordered_dense::{map, set} ///////////////////////// // A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion. -// Version 3.1.0 +// Version 4.0.1 // https://github.com/martinus/unordered_dense // // Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -30,12 +30,15 @@ #define ANKERL_UNORDERED_DENSE_H // see https://semver.org/spec/v2.0.0.html -#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 3 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes -#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 1 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality -#define ANKERL_UNORDERED_DENSE_VERSION_PATCH 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes +#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 4 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes +#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality +#define ANKERL_UNORDERED_DENSE_VERSION_PATCH 1 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes // API versioning with inline namespace, see https://www.foonathan.net/2018/11/inline-namespaces/ + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch) v##major##_##minor##_##patch +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define ANKERL_UNORDERED_DENSE_VERSION_CONCAT(major, minor, patch) ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch) #define ANKERL_UNORDERED_DENSE_NAMESPACE \ ANKERL_UNORDERED_DENSE_VERSION_CONCAT( \ @@ -57,9 +60,9 @@ // exceptions #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) -# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1 +# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1 // NOLINT(cppcoreguidelines-macro-usage) #else -# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0 +# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0 // NOLINT(cppcoreguidelines-macro-usage) #endif #ifdef _MSC_VER # define ANKERL_UNORDERED_DENSE_NOINLINE __declspec(noinline) @@ -89,20 +92,13 @@ # include <cstdlib> // for abort # endif -# define ANKERL_UNORDERED_DENSE_PMR 0 // NOLINT(cppcoreguidelines-macro-usage) # if defined(__has_include) # if __has_include(<memory_resource>) -# undef ANKERL_UNORDERED_DENSE_PMR -# define ANKERL_UNORDERED_DENSE_PMR 1 // NOLINT(cppcoreguidelines-macro-usage) -# define ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR \ - std::pmr::polymorphic_allocator // NOLINT(cppcoreguidelines-macro-usage) -# include <memory_resource> // for polymorphic_allocator +# define ANKERL_UNORDERED_DENSE_PMR std::pmr // NOLINT(cppcoreguidelines-macro-usage) +# include <memory_resource> // for polymorphic_allocator # elif __has_include(<experimental/memory_resource>) -# undef ANKERL_UNORDERED_DENSE_PMR -# define ANKERL_UNORDERED_DENSE_PMR 1 // NOLINT(cppcoreguidelines-macro-usage) -# define ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR \ - std::experimental::pmr::polymorphic_allocator // NOLINT(cppcoreguidelines-macro-usage) -# include <experimental/memory_resource> // for polymorphic_allocator +# define ANKERL_UNORDERED_DENSE_PMR std::experimental::pmr // NOLINT(cppcoreguidelines-macro-usage) +# include <experimental/memory_resource> // for polymorphic_allocator # endif # endif @@ -428,7 +424,7 @@ constexpr bool is_map_v = !std::is_void_v<Mapped>; // clang-format off template <typename Hash, typename KeyEqual> -constexpr bool is_transparent_v = is_detected_v<detect_is_transparent, Hash>&& is_detected_v<detect_is_transparent, KeyEqual>; +constexpr bool is_transparent_v = is_detected_v<detect_is_transparent, Hash> && is_detected_v<detect_is_transparent, KeyEqual>; // clang-format on template <typename From, typename To1, typename To2> @@ -446,19 +442,320 @@ struct base_table_type_map { // base type for set doesn't have mapped_type struct base_table_type_set {}; +} // namespace detail + +// Very much like std::deque, but faster for indexing (in most cases). As of now this doesn't implement the full std::vector +// API, but merely what's necessary to work as an underlying container for ankerl::unordered_dense::{map, set}. +// It allocates blocks of equal size and puts them into the m_blocks vector. That means it can grow simply by adding a new +// block to the back of m_blocks, and doesn't double its size like an std::vector. The disadvantage is that memory is not +// linear and thus there is one more indirection necessary for indexing. +template <typename T, typename Allocator = std::allocator<T>, size_t MaxSegmentSizeBytes = 4096> +class segmented_vector { + template <bool IsConst> + class iter_t; + +public: + using allocator_type = Allocator; + using pointer = typename std::allocator_traits<allocator_type>::pointer; + using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer; + using difference_type = typename std::allocator_traits<allocator_type>::difference_type; + using value_type = T; + using size_type = std::size_t; + using reference = T&; + using const_reference = T const&; + using iterator = iter_t<false>; + using const_iterator = iter_t<true>; + +private: + using vec_alloc = typename std::allocator_traits<Allocator>::template rebind_alloc<pointer>; + std::vector<pointer, vec_alloc> m_blocks{}; + size_t m_size{}; + + // Calculates the maximum number for x in (s << x) <= max_val + static constexpr auto num_bits_closest(size_t max_val, size_t s) -> size_t { + auto f = size_t{0}; + while (s << (f + 1) <= max_val) { + ++f; + } + return f; + } + + using self_t = segmented_vector<T, Allocator, MaxSegmentSizeBytes>; + static constexpr auto num_bits = num_bits_closest(MaxSegmentSizeBytes, sizeof(T)); + static constexpr auto num_elements_in_block = 1U << num_bits; + static constexpr auto mask = num_elements_in_block - 1U; + + /** + * Iterator class doubles as const_iterator and iterator + */ + template <bool IsConst> + class iter_t { + using ptr_t = typename std::conditional_t<IsConst, segmented_vector::const_pointer const*, segmented_vector::pointer*>; + ptr_t m_data{}; + size_t m_idx{}; + + template <bool B> + friend class iter_t; + + public: + using difference_type = segmented_vector::difference_type; + using value_type = T; + using reference = typename std::conditional_t<IsConst, value_type const&, value_type&>; + using pointer = typename std::conditional_t<IsConst, segmented_vector::const_pointer, segmented_vector::pointer>; + using iterator_category = std::forward_iterator_tag; + + iter_t() noexcept = default; + + template <bool OtherIsConst, typename = typename std::enable_if<IsConst && !OtherIsConst>::type> + // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) + constexpr iter_t(iter_t<OtherIsConst> const& other) noexcept + : m_data(other.m_data) + , m_idx(other.m_idx) {} + + constexpr iter_t(ptr_t data, size_t idx) noexcept + : m_data(data) + , m_idx(idx) {} + + template <bool OtherIsConst, typename = typename std::enable_if<IsConst && !OtherIsConst>::type> + constexpr auto operator=(iter_t<OtherIsConst> const& other) noexcept -> iter_t& { + m_data = other.m_data; + m_idx = other.m_idx; + return *this; + } + + constexpr auto operator++() noexcept -> iter_t& { + ++m_idx; + return *this; + } + + constexpr auto operator+(difference_type diff) noexcept -> iter_t { + return {m_data, static_cast<size_t>(static_cast<difference_type>(m_idx) + diff)}; + } + + template <bool OtherIsConst> + constexpr auto operator-(iter_t<OtherIsConst> const& other) noexcept -> difference_type { + return static_cast<difference_type>(m_idx) - static_cast<difference_type>(other.m_idx); + } + + constexpr auto operator*() const noexcept -> reference { + return m_data[m_idx >> num_bits][m_idx & mask]; + } + + constexpr auto operator->() const noexcept -> pointer { + return &m_data[m_idx >> num_bits][m_idx & mask]; + } + + template <bool O> + constexpr auto operator==(iter_t<O> const& o) const noexcept -> bool { + return m_idx == o.m_idx; + } + + template <bool O> + constexpr auto operator!=(iter_t<O> const& o) const noexcept -> bool { + return !(*this == o); + } + }; + + // slow path: need to allocate a new segment every once in a while + void increase_capacity() { + auto ba = Allocator(m_blocks.get_allocator()); + pointer block = std::allocator_traits<Allocator>::allocate(ba, num_elements_in_block); + m_blocks.push_back(block); + } + + // Moves everything from other + void append_everything_from(segmented_vector&& other) { + reserve(size() + other.size()); + for (auto&& o : other) { + emplace_back(std::move(o)); + } + } + + // Copies everything from other + void append_everything_from(segmented_vector const& other) { + reserve(size() + other.size()); + for (auto const& o : other) { + emplace_back(o); + } + } + + void dealloc() { + auto ba = Allocator(m_blocks.get_allocator()); + for (auto ptr : m_blocks) { + std::allocator_traits<Allocator>::deallocate(ba, ptr, num_elements_in_block); + } + } + + [[nodiscard]] static constexpr auto calc_num_blocks_for_capacity(size_t capacity) { + return (capacity + num_elements_in_block - 1U) / num_elements_in_block; + } + +public: + segmented_vector() = default; + + // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) + segmented_vector(Allocator alloc) + : m_blocks(vec_alloc(alloc)) {} + + segmented_vector(segmented_vector&& other, Allocator alloc) + : m_blocks(vec_alloc(alloc)) { + if (other.get_allocator() == alloc) { + *this = std::move(other); + } else { + // Oh my, allocator is different so we need to copy everything. + append_everything_from(std::move(other)); + } + } + + segmented_vector(segmented_vector&& other) noexcept + : m_blocks(std::move(other.m_blocks)) + , m_size(std::exchange(other.m_size, {})) {} + + segmented_vector(segmented_vector const& other, Allocator alloc) + : m_blocks(vec_alloc(alloc)) { + append_everything_from(other); + } + + segmented_vector(segmented_vector const& other) { + append_everything_from(other); + } + + auto operator=(segmented_vector const& other) -> segmented_vector& { + if (this == &other) { + return *this; + } + clear(); + append_everything_from(other); + return *this; + } + + auto operator=(segmented_vector&& other) noexcept -> segmented_vector& { + clear(); + dealloc(); + m_blocks = std::move(other.m_blocks); + m_size = std::exchange(other.m_size, {}); + return *this; + } + + ~segmented_vector() { + clear(); + dealloc(); + } + + [[nodiscard]] constexpr auto size() const -> size_t { + return m_size; + } + + [[nodiscard]] constexpr auto capacity() const -> size_t { + return m_blocks.size() * num_elements_in_block; + } + + // Indexing is highly performance critical + [[nodiscard]] constexpr auto operator[](size_t i) const noexcept -> T const& { + return m_blocks[i >> num_bits][i & mask]; + } + + [[nodiscard]] constexpr auto operator[](size_t i) noexcept -> T& { + return m_blocks[i >> num_bits][i & mask]; + } + + [[nodiscard]] constexpr auto begin() -> iterator { + return {m_blocks.data(), 0U}; + } + [[nodiscard]] constexpr auto begin() const -> const_iterator { + return {m_blocks.data(), 0U}; + } + [[nodiscard]] constexpr auto cbegin() const -> const_iterator { + return {m_blocks.data(), 0U}; + } + + [[nodiscard]] constexpr auto end() -> iterator { + return {m_blocks.data(), m_size}; + } + [[nodiscard]] constexpr auto end() const -> const_iterator { + return {m_blocks.data(), m_size}; + } + [[nodiscard]] constexpr auto cend() const -> const_iterator { + return {m_blocks.data(), m_size}; + } + + [[nodiscard]] constexpr auto back() -> reference { + return operator[](m_size - 1); + } + [[nodiscard]] constexpr auto back() const -> const_reference { + return operator[](m_size - 1); + } + + void pop_back() { + back().~T(); + --m_size; + } + + [[nodiscard]] auto empty() const { + return 0 == m_size; + } + + void reserve(size_t new_capacity) { + m_blocks.reserve(calc_num_blocks_for_capacity(new_capacity)); + while (new_capacity > capacity()) { + increase_capacity(); + } + } + + [[nodiscard]] auto get_allocator() const -> allocator_type { + return allocator_type{m_blocks.get_allocator()}; + } + + template <class... Args> + auto emplace_back(Args&&... args) -> reference { + if (m_size == capacity()) { + increase_capacity(); + } + auto* ptr = static_cast<void*>(&operator[](m_size)); + auto& ref = *new (ptr) T(std::forward<Args>(args)...); + ++m_size; + return ref; + } + + void clear() { + if constexpr (!std::is_trivially_destructible_v<T>) { + for (size_t i = 0, s = size(); i < s; ++i) { + operator[](i).~T(); + } + } + m_size = 0; + } + + void shrink_to_fit() { + auto ba = Allocator(m_blocks.get_allocator()); + auto num_blocks_required = calc_num_blocks_for_capacity(m_size); + while (m_blocks.size() > num_blocks_required) { + std::allocator_traits<Allocator>::deallocate(ba, m_blocks.back(), num_elements_in_block); + m_blocks.pop_back(); + } + m_blocks.shrink_to_fit(); + } +}; + +namespace detail { + // This is it, the table. Doubles as map and set, and uses `void` for T when its used as a set. template <class Key, class T, // when void, treat it as a set. class Hash, class KeyEqual, class AllocatorOrContainer, - class Bucket> + class Bucket, + bool IsSegmented> class table : public std::conditional_t<is_map_v<T>, base_table_type_map<T>, base_table_type_set> { + using underlying_value_type = typename std::conditional_t<is_map_v<T>, std::pair<Key, T>, Key>; + using underlying_container_type = std::conditional_t<IsSegmented, + segmented_vector<underlying_value_type, AllocatorOrContainer>, + std::vector<underlying_value_type, AllocatorOrContainer>>; + public: - using value_container_type = std::conditional_t< - is_detected_v<detect_iterator, AllocatorOrContainer>, - AllocatorOrContainer, - typename std::vector<typename std::conditional_t<is_map_v<T>, std::pair<Key, T>, Key>, AllocatorOrContainer>>; + using value_container_type = std:: + conditional_t<is_detected_v<detect_iterator, AllocatorOrContainer>, AllocatorOrContainer, underlying_container_type>; private: using bucket_alloc = @@ -492,7 +789,8 @@ private: static_assert(std::is_trivially_copyable_v<Bucket>, "assert we can just memset / memcpy"); value_container_type m_values{}; // Contains all the key-value pairs in one densely stored container. No holes. - typename std::allocator_traits<bucket_alloc>::pointer m_buckets{}; + using bucket_pointer = typename std::allocator_traits<bucket_alloc>::pointer; + bucket_pointer m_buckets{}; size_t m_num_buckets = 0; size_t m_max_bucket_capacity = 0; float m_max_load_factor = default_max_load_factor; @@ -507,8 +805,7 @@ private: } // Helper to access bucket through pointer types - [[nodiscard]] static constexpr auto at(typename std::allocator_traits<bucket_alloc>::pointer bucket_ptr, size_t offset) - -> Bucket& { + [[nodiscard]] static constexpr auto at(bucket_pointer bucket_ptr, size_t offset) -> Bucket& { return *(bucket_ptr + static_cast<typename std::allocator_traits<bucket_alloc>::difference_type>(offset)); } @@ -578,7 +875,7 @@ private: } [[nodiscard]] static constexpr auto calc_num_buckets(uint8_t shifts) -> size_t { - return std::min(max_bucket_count(), size_t{1} << (64U - shifts)); + return (std::min)(max_bucket_count(), size_t{1} << (64U - shifts)); } [[nodiscard]] constexpr auto calc_shifts_for_size(size_t s) const -> uint8_t { @@ -983,7 +1280,7 @@ public: } [[nodiscard]] static constexpr auto max_size() noexcept -> size_t { - if constexpr (std::numeric_limits<value_idx_type>::max() == std::numeric_limits<size_t>::max()) { + if constexpr ((std::numeric_limits<value_idx_type>::max)() == (std::numeric_limits<size_t>::max)()) { return size_t{1} << (sizeof(value_idx_type) * 8 - 1); } else { return size_t{1} << (sizeof(value_idx_type) * 8); @@ -1272,7 +1569,7 @@ public: auto const last_to_end = std::distance(last, cend()); // remove elements from left to right which moves elements from the end back - auto const mid = idx_first + std::min(first_to_last, last_to_end); + auto const mid = idx_first + (std::min)(first_to_last, last_to_end); auto idx = idx_first; while (idx != mid) { erase(begin() + idx); @@ -1439,8 +1736,8 @@ public: } void rehash(size_t count) { - count = std::min(count, max_size()); - auto shifts = calc_shifts_for_size(std::max(count, size())); + count = (std::min)(count, max_size()); + auto shifts = calc_shifts_for_size((std::max)(count, size())); if (shifts != m_shifts) { m_shifts = shifts; deallocate_buckets(); @@ -1451,12 +1748,12 @@ public: } void reserve(size_t capa) { - capa = std::min(capa, max_size()); + capa = (std::min)(capa, max_size()); if constexpr (has_reserve<value_container_type>) { // std::deque doesn't have reserve(). Make sure we only call when available m_values.reserve(capa); } - auto shifts = calc_shifts_for_size(std::max(capa, size())); + auto shifts = calc_shifts_for_size((std::max)(capa, size())); if (0 == m_num_buckets || shifts < m_shifts) { m_shifts = shifts; deallocate_buckets(); @@ -1519,16 +1816,31 @@ template <class Key, class KeyEqual = std::equal_to<Key>, class AllocatorOrContainer = std::allocator<std::pair<Key, T>>, class Bucket = bucket_type::standard> -using map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>; +using map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, false>; + +template <class Key, + class T, + class Hash = hash<Key>, + class KeyEqual = std::equal_to<Key>, + class AllocatorOrContainer = std::allocator<std::pair<Key, T>>, + class Bucket = bucket_type::standard> +using segmented_map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, true>; + +template <class Key, + class Hash = hash<Key>, + class KeyEqual = std::equal_to<Key>, + class AllocatorOrContainer = std::allocator<Key>, + class Bucket = bucket_type::standard> +using set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket, false>; template <class Key, class Hash = hash<Key>, class KeyEqual = std::equal_to<Key>, class AllocatorOrContainer = std::allocator<Key>, class Bucket = bucket_type::standard> -using set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket>; +using segmented_set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket, true>; -# if ANKERL_UNORDERED_DENSE_PMR +# if defined(ANKERL_UNORDERED_DENSE_PMR) namespace pmr { @@ -1537,10 +1849,23 @@ template <class Key, class Hash = hash<Key>, class KeyEqual = std::equal_to<Key>, class Bucket = bucket_type::standard> -using map = detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR<std::pair<Key, T>>, Bucket>; +using map = + detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<std::pair<Key, T>>, Bucket, false>; + +template <class Key, + class T, + class Hash = hash<Key>, + class KeyEqual = std::equal_to<Key>, + class Bucket = bucket_type::standard> +using segmented_map = + detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<std::pair<Key, T>>, Bucket, true>; + +template <class Key, class Hash = hash<Key>, class KeyEqual = std::equal_to<Key>, class Bucket = bucket_type::standard> +using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<Key>, Bucket, false>; template <class Key, class Hash = hash<Key>, class KeyEqual = std::equal_to<Key>, class Bucket = bucket_type::standard> -using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR<Key>, Bucket>; +using segmented_set = + detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<Key>, Bucket, true>; } // namespace pmr @@ -1558,11 +1883,18 @@ using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_ namespace std { // NOLINT(cert-dcl58-cpp) -template <class Key, class T, class Hash, class KeyEqual, class AllocatorOrContainer, class Bucket, class Pred> +template <class Key, + class T, + class Hash, + class KeyEqual, + class AllocatorOrContainer, + class Bucket, + class Pred, + bool IsSegmented> // NOLINTNEXTLINE(cert-dcl58-cpp) -auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>& map, Pred pred) - -> size_t { - using map_t = ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>; +auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, IsSegmented>& map, + Pred pred) -> size_t { + using map_t = ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, IsSegmented>; // going back to front because erase() invalidates the end iterator auto const old_size = map.size(); @@ -1575,7 +1907,7 @@ auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, All } } - return map.size() - old_size; + return old_size - map.size(); } } // namespace std diff --git a/misc/benchmarks/external/emhash/hash_table7.hpp b/misc/benchmarks/external/emhash/hash_table7.hpp index 8f8982f9..41970d8c 100644 --- a/misc/benchmarks/external/emhash/hash_table7.hpp +++ b/misc/benchmarks/external/emhash/hash_table7.hpp @@ -92,7 +92,7 @@ of resizing granularity. Ignoring variance, the expected occurrences of list siz #include "wyhash.h" #endif -#ifdef EMH_KEY +#ifdef EMH_NEW #undef EMH_KEY #undef EMH_VAL #undef EMH_PKV @@ -547,10 +547,10 @@ public: static PairT* alloc_bucket(size_type num_buckets) { -#if _WIN32 - auto* new_pairs = (PairT*)malloc(AllocSize(num_buckets)); -#else +#ifdef EMH_ALLOC auto* new_pairs = (PairT*)aligned_alloc(EMH_MALIGN, AllocSize(num_buckets)); +#else + auto* new_pairs = (PairT*)malloc(AllocSize(num_buckets)); #endif return new_pairs; } @@ -1668,16 +1668,10 @@ private: // key is not in this map. Find a place to put it. size_type find_empty_bucket(const size_type bucket_from, const size_type main_bucket) { -#ifdef EMH_ALIGN64 // only works 64bit - const auto boset = bucket_from % MASK_BIT; - auto* const align = _bitmask + bucket_from / MASK_BIT; - const auto bmask = ((size_t)align[1] << (MASK_BIT - boset)) | (align[0] >> boset); - if (EMH_LIKELY(bmask != 0)) - return bucket_from + CTZ(bmask); -#elif EMH_ITER_SAFE +#if EMH_ITER_SAFE const auto boset = bucket_from % 8; - auto* const start = (uint8_t*)_bitmask + bucket_from / 8; - size_t bmask; memcpy(&bmask, start + 0, sizeof(bmask)); bmask >>= boset;// bmask |= ((size_t)start[8] << (SIZE_BIT - boset)); + auto* const align = (uint8_t*)_bitmask + bucket_from / 8;(void)main_bucket; + size_t bmask; memcpy(&bmask, align + 0, sizeof(bmask)); bmask >>= boset;// bmask |= ((size_t)align[8] << (SIZE_BIT - boset)); if (EMH_LIKELY(bmask != 0)) return bucket_from + CTZ(bmask); #else @@ -1715,21 +1709,15 @@ private: } // key is not in this map. Find a place to put it. - size_type find_unique_empty(const size_type bucket_from, const size_t main_bucket) - { -#ifdef EMH_ALIGN64 - const auto boset = bucket_from % MASK_BIT; - auto* const align = _bitmask + bucket_from / MASK_BIT; - const auto bmask = ((size_t)align[1] << (MASK_BIT - boset)) | (align[0] >> boset); - static_assert(sizeof(size_t) > 4); -#elif EMH_ITER_SAFE + size_type find_unique_empty(const size_type bucket_from) + { const auto boset = bucket_from % 8; - auto* const start = (uint8_t*)_bitmask + bucket_from / 8; - size_t bmask; memcpy(&bmask, start + 0, sizeof(bmask)); bmask >>= boset; -#else - const auto boset = bucket_from % 8; (void)main_bucket; auto* const align = (uint8_t*)_bitmask + bucket_from / 8; - const auto bmask = (*(size_t*)(align) >> boset); //maybe not aligned and warning + +#if EMH_ITER_SAFE + size_t bmask; memcpy(&bmask, align + 0, sizeof(bmask)); bmask >>= boset; +#else + const auto bmask = (*(size_t*)(align) >> boset); //maybe not aligned and warning #endif if (EMH_LIKELY(bmask != 0)) return bucket_from + CTZ(bmask); @@ -1789,12 +1777,12 @@ private: next_bucket = find_last_bucket(next_bucket); //find a new empty and link it to tail - return EMH_BUCKET(_pairs, next_bucket) = find_unique_empty(next_bucket, bucket); + return EMH_BUCKET(_pairs, next_bucket) = find_empty_bucket(next_bucket, bucket); } #if EMH_INT_HASH static constexpr uint64_t KC = UINT64_C(11400714819323198485); - inline uint64_t hash64(uint64_t key) + inline static uint64_t hash64(uint64_t key) { #if __SIZEOF_INT128__ && EMH_INT_HASH == 1 __uint128_t r = key; r *= KC; diff --git a/misc/benchmarks/plotbench/cdeq_benchmark.cpp b/misc/benchmarks/plotbench/cdeq_benchmark.cpp index bb0e28c8..54d7305b 100644 --- a/misc/benchmarks/plotbench/cdeq_benchmark.cpp +++ b/misc/benchmarks/plotbench/cdeq_benchmark.cpp @@ -12,7 +12,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 50000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 60000000, S = 0x3ffc, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } diff --git a/misc/benchmarks/plotbench/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/plotbench/cvec_benchmark.cpp b/misc/benchmarks/plotbench/cvec_benchmark.cpp index c488a01c..3b4c3d7d 100644 --- a/misc/benchmarks/plotbench/cvec_benchmark.cpp +++ b/misc/benchmarks/plotbench/cvec_benchmark.cpp @@ -12,7 +12,7 @@ enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; typedef struct { const char* name; Range test[N_TESTS]; } Sample; -enum {SAMPLES = 2, N = 80000000, S = 0x3ffc, R = 4}; +enum {SAMPLES = 2, N = 40000000, S = 0x3ffc, R = 4}; uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } diff --git a/misc/benchmarks/plotbench/plot.py b/misc/benchmarks/plotbench/plot.py index 0ba92264..e65631b7 100644 --- a/misc/benchmarks/plotbench/plot.py +++ b/misc/benchmarks/plotbench/plot.py @@ -12,8 +12,8 @@ df = df[df.Method != 'total'] if n > 0: df = df[df.Compiler == comp[n]] -g = sns.catplot(data=df, x='Method', y='Seconds', hue='Library', col='C', kind='bar', - ci=68, legend=False, col_wrap=2, sharex=False, aspect=1.4, height=3.1) +g = sns.catplot(data=df, x='Method', y='Seconds', hue='Library', col='C', kind='bar', orient='v', + errorbar=('ci', 68), legend=False, col_wrap=2, sharex=False, aspect=1.4, height=3.1) g.set_xlabels('') g.add_legend(bbox_to_anchor=(0.75, 0.2), borderaxespad=0.) diff --git a/misc/benchmarks/plotbench/run_clang.sh b/misc/benchmarks/plotbench/run_clang.sh index 096e71be..59d577d9 100644 --- a/misc/benchmarks/plotbench/run_clang.sh +++ b/misc/benchmarks/plotbench/run_clang.sh @@ -1,10 +1,10 @@ exe='' if [ "$OS" = "Windows_NT" ] ; then exe=".exe" ; fi -clang++ -I../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp -clang++ -I../include -O3 -o clist_benchmark$exe clist_benchmark.cpp -clang++ -I../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp -clang++ -I../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp -clang++ -I../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp +clang++ -DNDEBUG -I../../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp +clang++ -DNDEBUG -I../../include -O3 -o clist_benchmark$exe clist_benchmark.cpp +clang++ -DNDEBUG -I../../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp +clang++ -DNDEBUG -I../../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp +clang++ -DNDEBUG -I../../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp c='Win-Clang-14.0.1' ./cdeq_benchmark$exe $c diff --git a/misc/benchmarks/plotbench/run_gcc.sh b/misc/benchmarks/plotbench/run_gcc.sh index 5249ed1e..73b979d3 100644 --- a/misc/benchmarks/plotbench/run_gcc.sh +++ b/misc/benchmarks/plotbench/run_gcc.sh @@ -1,8 +1,8 @@ -g++ -I../include -O3 -o cdeq_benchmark cdeq_benchmark.cpp -g++ -I../include -O3 -o clist_benchmark clist_benchmark.cpp -g++ -I../include -O3 -o cmap_benchmark cmap_benchmark.cpp -g++ -I../include -O3 -o csmap_benchmark csmap_benchmark.cpp -g++ -I../include -O3 -o cvec_benchmark cvec_benchmark.cpp +g++ -DNDEBUG -I../../include -O3 -o cdeq_benchmark cdeq_benchmark.cpp +g++ -DNDEBUG -I../../include -O3 -o clist_benchmark clist_benchmark.cpp +g++ -DNDEBUG -I../../include -O3 -o cmap_benchmark cmap_benchmark.cpp +g++ -DNDEBUG -I../../include -O3 -o csmap_benchmark csmap_benchmark.cpp +g++ -DNDEBUG -I../../include -O3 -o cvec_benchmark cvec_benchmark.cpp c='Mingw-g++-11.3.0' ./cdeq_benchmark $c diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp index bae9a42b..c6a81777 100644 --- a/misc/benchmarks/shootout_hashmaps.cpp +++ b/misc/benchmarks/shootout_hashmaps.cpp @@ -2,7 +2,7 @@ #include <time.h> #include <stc/crand.h> -#define MAX_LOAD_FACTOR 85 +#define MAX_LOAD_FACTOR 80 #ifdef __cplusplus #include <limits> @@ -35,8 +35,8 @@ KHASH_MAP_INIT_INT64(ii, IValue) // cmap template expansion #define i_key IKey #define i_val IValue -#define i_ssize int32_t // enable 2^K buckets like the rest. #define i_tag ii +//#define i_expandby 1 #define i_max_load_factor MAX_LOAD_FACTOR / 100.0f #include <stc/cmap.h> diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c index d5d7fa7c..f6b7f1db 100644 --- a/misc/benchmarks/various/csort_bench.c +++ b/misc/benchmarks/various/csort_bench.c @@ -5,8 +5,12 @@ #ifdef __cplusplus #include <algorithm> #endif -#define i_val int -#include <stc/algo/csort.h> +#define NDEBUG +#define i_type Ints +#define i_key int +#define i_more +#include <stc/cvec.h> +#include <stc/algo/sort.h> #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 sort_n: "); 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..f4b067f8 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 <stc/cspan.h> #include <stdio.h> #include <time.h> @@ -12,8 +12,7 @@ enum { nz = 64 }; int lx = 15, ly = 10, lz = 5; -int hx = 20, hy = 15, hz = 15; -intptr_t n = 1000000; +int hx = 30, hy = 15, hz = 15; // define the contents of two nx x ny x nz arrays in and out double Vout[nx * ny * nz]; @@ -21,12 +20,12 @@ double Vin[nx * ny * nz]; //, 1.23; // define some slice indices for each dimension -static void MDRanges_setup(intptr_t state) +static void MDRanges_setup(intptr_t n) { double sum = 0; clock_t t = clock(); - for (intptr_t s = 0; s < state; ++s) + for (intptr_t s = 0; s < n; ++s) { MD3 r_in = cspan_md(Vin, nx, ny, nz); MD3 r_out = cspan_md(Vout, nx, ny, nz); @@ -41,18 +40,18 @@ static void MDRanges_setup(intptr_t state) printf("setup: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); } -static void TraditionalForLoop(intptr_t state) +static void TraditionalForLoop(intptr_t n) { clock_t t = clock(); double sum = 0; - for (int s = 0; s < state; ++s) { + for (int s = 0; s < n; ++s) { for (int x = lx; x < hx; ++x) { for (int y = ly; y < hy; ++y) { - for (int z = lz; z < hz; ++z) - { - double d = Vin[nz*(ny*x + y) + z]; - Vout[nz*(ny*x + y) + z] += d; + for (int z = lz; z < hz; ++z) { + int i = nz*(ny*x + y) + z; + double d = Vin[i]; + Vout[i] += d; sum += d; } } @@ -62,18 +61,18 @@ static void TraditionalForLoop(intptr_t state) printf("forloop: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); } -static void MDRanges_nested_loop(intptr_t state) +static void MDRanges_nested_loop(intptr_t n) { + clock_t t = clock(); MD3 r_in = cspan_md(Vin, nx, ny, nz); MD3 r_out = cspan_md(Vout, nx, ny, nz); r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz}); r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz}); // C++23: for (auto [o, i] : std::views::zip(flat(r_out), flat(r_in))) { o = i; } - clock_t t = clock(); double sum = 0; - for (intptr_t s = 0; s < state; ++s) { + for (intptr_t s = 0; s < n; ++s) { for (int x = 0; x < r_in.shape[0]; ++x) { for (int y = 0; y < r_in.shape[1]; ++y) { for (int z = 0; z < r_in.shape[2]; ++z) @@ -89,7 +88,7 @@ static void MDRanges_nested_loop(intptr_t state) printf("nested: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum); } -static void MDRanges_loop_over_joined(intptr_t state) +static void MDRanges_loop_over_joined(intptr_t n) { MD3 r_in = cspan_md(Vin, nx, ny, nz); MD3 r_out = cspan_md(Vout, nx, ny, nz); @@ -100,7 +99,7 @@ static void MDRanges_loop_over_joined(intptr_t state) double sum = 0; clock_t t = clock(); - for (intptr_t s = 0; s < state; ++s) { + for (intptr_t s = 0; s < n; ++s) { MD3_iter i = MD3_begin(&r_in); MD3_iter o = MD3_begin(&r_out); @@ -114,8 +113,9 @@ 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) { + intptr_t n = 100000; 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 993ff1bb..244c1291 100644 --- a/misc/benchmarks/various/sso_bench.cpp +++ b/misc/benchmarks/various/sso_bench.cpp @@ -3,65 +3,82 @@ #include <chrono> #include <stc/crand.h> +#define i_static #include <stc/cstr.h> #define i_type StcVec #define i_val_str #include <stc/cstack.h> -#define i_type StcSet -#define i_val_str -#include <stc/csset.h> - #include <vector> using StdVec = std::vector<std::string>; -#include <set> -using StdSet = std::set<std::string>; -static const int BENCHMARK_SIZE = 2000000; -static const int MAX_STRING_SIZE = 50; +#include <unordered_set> +#include "../external/ankerl/robin_hood.h" + +struct string_hash { + using is_transparent = void; + [[nodiscard]] size_t operator()(const char *txt) const { + return std::hash<std::string_view>{}(txt); + } + [[nodiscard]] size_t operator()(std::string_view txt) const { + return std::hash<std::string_view>{}(txt); + } + [[nodiscard]] size_t operator()(const std::string &txt) const { + return std::hash<std::string>{}(txt); + } +}; +using StdSet = robin_hood::unordered_flat_set<std::string, string_hash, std::equal_to<>>; +//using StdSet = std::unordered_set<std::string>; + +#define i_type StcSet +#define i_val_str +//#define i_hash(txtp) std::hash<std::string_view>{}(*txtp) +#include <stc/cset.h> + + +static const int BENCHMARK_SIZE = 250000; +static const int MAX_STRING_SIZE = 100; static const char CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=+-"; using time_point = std::chrono::high_resolution_clock::time_point; -static inline std::string randomString_STD(int strsize) { - std::string s(strsize, 0); - char* p = &s[0]; +static inline const char* randomString(int strsize) { + static char str[256]; union { uint64_t u8; uint8_t b[8]; } r; for (int i = 0; i < strsize; ++i) { if ((i & 7) == 0) r.u8 = crand() & 0x3f3f3f3f3f3f3f3f; - p[i] = CHARS[r.b[i & 7]]; + str[i] = CHARS[r.b[i & 7]]; } - return s; + str[strsize] = 0; + return str; } -static inline cstr randomString_STC(int strsize) { - cstr s = cstr_with_size(strsize, 0); - char* p = cstr_data(&s); - union { uint64_t u8; uint8_t b[8]; } r; - for (int i = 0; i < strsize; ++i) { - if ((i & 7) == 0) r.u8 = crand() & 0x3f3f3f3f3f3f3f3f; - p[i] = CHARS[r.b[i & 7]]; - } - return s; + + +static inline void addRandomString(StdVec& vec, const char* str) { + vec.push_back(str); } +static inline void addRandomString(StcVec& vec, const char* str) { + StcVec_emplace(&vec, str); +} -void addRandomString(StdVec& vec, int strsize) { - vec.push_back(std::move(randomString_STD(strsize))); +static inline void addRandomString(StdSet& set, const char* str) { + set.insert(str); } -void addRandomString(StcVec& vec, int strsize) { - StcVec_push(&vec, randomString_STC(strsize)); +static inline void addRandomString(StcSet& set, const char* str) { + StcSet_emplace(&set, str); } -void addRandomString(StdSet& set, int strsize) { - set.insert(std::move(randomString_STD(strsize))); +static inline bool getRandomString(const StdSet& set, const char* str) { + return set.find(str) != set.end(); } -void addRandomString(StcSet& set, int strsize) { - StcSet_insert(&set, randomString_STC(strsize)); +static inline bool getRandomString(const StcSet& set, const char* str) { + return StcSet_contains(&set, str); } @@ -70,7 +87,7 @@ int benchmark(C& container, const int n, const int strsize) { time_point t1 = std::chrono::high_resolution_clock::now(); for (int i = 0; i < n; i++) - addRandomString(container, strsize); + addRandomString(container, randomString(strsize)); time_point t2 = std::chrono::high_resolution_clock::now(); const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count(); @@ -78,9 +95,25 @@ int benchmark(C& container, const int n, const int strsize) { return (int)duration; } +template <class C> +int benchmark_lookup(C& container, const int n, const int strsize) { + for (int i = 0; i < n; i++) + addRandomString(container, randomString(strsize)); + + time_point t1 = std::chrono::high_resolution_clock::now(); + int found = 0; + for (int i = 0; i < n; i++) + found += (int)getRandomString(container, randomString(strsize)); + + time_point t2 = std::chrono::high_resolution_clock::now(); + const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count(); + std::cerr << (strsize ? strsize : 32) << "\t" << duration << '\t' << found; + return (int)duration; +} -int main() { - uint64_t seed = 4321; +#include <time.h> +int main(void) { + uint64_t seed = time(NULL); // 4321; int sum, n; // VECTOR WITH STRINGS @@ -88,48 +121,75 @@ int main() { csrand(seed); sum = 0, n = 0; std::cerr << "\nstrsize\tmsecs\tstd::vector<std::string>, size=" << BENCHMARK_SIZE << "\n"; - for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { StdVec vec; vec.reserve(BENCHMARK_SIZE); sum += benchmark(vec, BENCHMARK_SIZE, strsize), ++n; std::cout << '\t' << vec.front() << '\n'; } - std::cout << "Avg:\t" << sum/n << '\n'; + std::cout << "Avg:\t" << sum/n << "ms\n"; csrand(seed); sum = 0, n = 0; std::cerr << "\nstrsize\tmsecs\tcvec<cstr>, size=" << BENCHMARK_SIZE << "\n"; - for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { StcVec vec = StcVec_with_capacity(BENCHMARK_SIZE); sum += benchmark(vec, BENCHMARK_SIZE, strsize), ++n; std::cout << '\t' << cstr_str(&vec.data[0]) << '\n'; StcVec_drop(&vec); } - std::cout << "Avg:\t" << sum/n << '\n'; + std::cout << "Avg:\t" << sum/n << "ms\n"; + + // INSERT: SORTED SET WITH STRINGS + + csrand(seed); + sum = 0, n = 0; + std::cerr << "\nstrsize\tmsecs\tinsert: robin_hood::unordered_flat_set<std::string>, size=" << BENCHMARK_SIZE/2 << "\n"; + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { + StdSet set; set.reserve(BENCHMARK_SIZE/2); + sum += benchmark(set, BENCHMARK_SIZE/2, strsize), ++n; + std::cout << '\t' << *set.begin() << '\n'; + } + std::cout << "Avg:\t" << sum/n << "ms\n"; - // SORTED SET WITH STRINGS csrand(seed); sum = 0, n = 0; - std::cerr << "\nstrsize\tmsecs\tstd::set<std::string>, size=" << BENCHMARK_SIZE/16 << "\n"; + std::cerr << "\nstrsize\tmsecs\tinsert: cset<cstr>, size=" << BENCHMARK_SIZE/2 << "\n"; + for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) { + StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/2); + sum += benchmark(set, BENCHMARK_SIZE/2, strsize), ++n; + std::cout << '\t' << cstr_str(StcSet_begin(&set).ref) << '\n'; + StcSet_drop(&set); + } + std::cout << "Avg:\t" << sum/n << "ms\n"; + + // LOOKUP: SORTED SET WITH STRINGS + + csrand(seed); + sum = 0, n = 0; + std::cerr << "\nstrsize\tmsecs\tfind: robin_hood::unordered_flat_set<std::string>, size=" << BENCHMARK_SIZE/2 << "\n"; for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { - StdSet set; - sum += benchmark(set, BENCHMARK_SIZE/16, strsize), ++n; + StdSet set; set.reserve(BENCHMARK_SIZE/2); + sum += benchmark_lookup(set, BENCHMARK_SIZE/2, strsize), ++n; std::cout << '\t' << *set.begin() << '\n'; } - std::cout << "Avg:\t" << sum/n << '\n'; + std::cout << "Avg:\t" << sum/n << "ms\n"; csrand(seed); sum = 0, n = 0; - std::cerr << "\nstrsize\tmsecs\tcsset<cstr>, size=" << BENCHMARK_SIZE/16 << "\n"; + std::cerr << "\nstrsize\tmsecs\tfind: cset<cstr>, size=" << BENCHMARK_SIZE/2 << "\n"; for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) { - StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/16); - sum += benchmark(set, BENCHMARK_SIZE/16, strsize), ++n; - std::cout << '\t' << cstr_str(StcSet_front(&set)) << '\n'; + StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/2); + sum += benchmark_lookup(set, BENCHMARK_SIZE/2, strsize), ++n; + std::cout << '\t' << cstr_str(StcSet_begin(&set).ref) << '\n'; StcSet_drop(&set); } - std::cout << "Avg:\t" << sum/n << '\n'; + std::cout << "Avg:\t" << sum/n << "ms\n"; + std::cerr << "sizeof(std::string) : " << sizeof(std::string) << std::endl - << "sizeof(cstr) : " << sizeof(cstr) << std::endl; + << "sizeof(cstr) : " << sizeof(cstr) << std::endl + << "sizeof(StdSet) : " << sizeof(StdSet) << std::endl + << "sizeof(StcSet) : " << sizeof(StcSet) << std::endl; return 0; } diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp index ae8e4c38..a5dfd901 100644 --- a/misc/benchmarks/various/string_bench_STC.cpp +++ b/misc/benchmarks/various/string_bench_STC.cpp @@ -4,10 +4,11 @@ #include <iostream> #include <iomanip> #include <chrono> -#define i_static +#define i_implement #include <stc/cstr.h> // string -#define i_static +#define i_implement #include <stc/csview.h> // string_view +#include <stc/algo/raii.h> #define i_key_str #include <stc/cvec.h> // vec of cstr with const char* lookup @@ -183,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 8bb87937..153ac02f 100644 --- a/misc/benchmarks/various/string_bench_STD.cpp +++ b/misc/benchmarks/various/string_bench_STD.cpp @@ -12,6 +12,7 @@ #include <unordered_map> #define i_static #include <stc/cstr.h> +#include <stc/algo/raii.h> std::vector<std::string> read_file(const char* name) { @@ -193,7 +194,7 @@ void benchmark( //const size_t MAX_LOOP = 1000000; const size_t MAX_LOOP = 2000; -int main() +int main(void) { std::vector<std::string> vec_shortstr; std::vector<std::string_view> vec_shortstrview; diff --git a/misc/examples/arc_containers.c b/misc/examples/arc_containers.c index 84ba8dda..2fb04c56 100644 --- a/misc/examples/arc_containers.c +++ b/misc/examples/arc_containers.c @@ -1,7 +1,8 @@ // Create a stack and a list of shared pointers to maps, // and demonstrate sharing and cloning of maps. -#define i_static +#define i_implement #include <stc/cstr.h> +#include <stc/algo/raii.h> #define i_type Map #define i_key_str // strings #define i_val int @@ -9,23 +10,21 @@ #include <stc/csmap.h> #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|c_no_cmp|c_no_clone +#define i_opt c_no_atomic #include <stc/carc.h> #define i_type Stack -#define i_valboxed Arc // define i_valboxed for carc/cbox value (not i_val) -#define i_opt c_no_cmp +#define i_keyboxed Arc // define i_keyboxed for carc/cbox value (not i_key) #include <stc/cvec.h> #define i_type List -#define i_valboxed Arc // as above -#define i_opt c_no_cmp +#define i_keyboxed Arc // as above #include <stc/clist.h> -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 2339adbb..87d64e67 100644 --- a/misc/examples/arc_demo.c +++ b/misc/examples/arc_demo.c @@ -6,27 +6,31 @@ 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_no_clone // required because of valdrop +#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 <stc/carc.h> // Arc -#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements +#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements #include <stc/csset.h> // csset_Arc (like: std::set<std::shared_ptr<int>>) -#define i_valboxed Arc // note: as above. +#define i_keyboxed Arc // note: as above. #include <stc/cvec.h> // cvec_Arc (like: std::vector<std::shared_ptr<int>>) -int main() +int main(void) { const int years[] = {2021, 2012, 2022, 2015}; cvec_Arc vec = {0}; - c_forrange (i, c_arraylen(years)) - cvec_Arc_push(&vec, Arc_from(years[i])); + c_forrange (i, c_arraylen(years)) { + cvec_Arc_emplace(&vec, years[i]); + // cvec_Arc_push(&vec, Arc_from(years[i])); // alt. + } + + cvec_Arc_sort(&vec); printf("vec:"); c_foreach (i, cvec_Arc, vec) diff --git a/misc/examples/arcvec_erase.c b/misc/examples/arcvec_erase.c index 3bf41559..addef8b7 100644 --- a/misc/examples/arcvec_erase.c +++ b/misc/examples/arcvec_erase.c @@ -3,19 +3,19 @@ void show_drop(int* x) { printf("drop: %d\n", *x); } #define i_type Arc -#define i_val int -#define i_valdrop show_drop -#define i_no_clone // required because of valdrop +#define i_key int +#define i_keydrop show_drop +#define i_native_cmp // enable sort/search for int type #include <stc/carc.h> // Shared pointer to int #define i_type Vec -#define i_valboxed Arc +#define i_keyboxed Arc #include <stc/cvec.h> // Vec: cvec<Arc> -int main() +int main(void) { - 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/astar.c b/misc/examples/astar.c index 7dd12d50..590b7952 100644 --- a/misc/examples/astar.c +++ b/misc/examples/astar.c @@ -4,6 +4,7 @@ // This is a reimplementation of the CTL example to STC: // https://github.com/glouw/ctl/blob/master/examples/astar.c // https://www.redblobgames.com/pathfinding/a-star/introduction.html +#define i_implement #include <stc/cstr.h> #include <stdio.h> @@ -19,7 +20,7 @@ point; point point_init(int x, int y, int width) { - return (point) { x, y, 0, width }; + return c_LITERAL(point){ x, y, 0, width }; } int @@ -55,11 +56,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 <stc/cpque.h> -#define i_val point +#define i_key point #define i_opt c_no_cmp #include <stc/cdeq.h> diff --git a/misc/examples/birthday.c b/misc/examples/birthday.c index c301128a..4742cb45 100644 --- a/misc/examples/birthday.c +++ b/misc/examples/birthday.c @@ -13,8 +13,8 @@ static uint64_t seed = 12345; static void test_repeats(void) { enum {BITS = 46, BITS_TEST = BITS/2 + 2}; - const static uint64_t N = 1ull << BITS_TEST; - const static uint64_t mask = (1ull << BITS) - 1; + static const uint64_t N = 1ull << BITS_TEST; + static const uint64_t mask = (1ull << BITS) - 1; printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST); crand_t rng = crand_init(seed); @@ -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 <stc/cbits.h> -int main() +int main(void) { Bits s1 = Bits_from("1110100110111"); diff --git a/misc/examples/books.c b/misc/examples/books.c index a62769b0..1fd57f27 100644 --- a/misc/examples/books.c +++ b/misc/examples/books.c @@ -1,4 +1,5 @@ // https://doc.rust-lang.org/std/collections/struct.HashMap.html +#define i_implement #include <stc/cstr.h> #define i_key_str #define i_val_str @@ -6,7 +7,7 @@ // Type inference lets us omit an explicit type signature (which // would be `HashMap<String, String>` 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 9954883c..94d126c0 100644 --- a/misc/examples/box.c +++ b/misc/examples/box.c @@ -1,10 +1,11 @@ /* cbox: heap allocated boxed type */ +#define i_implement #include <stc/cstr.h> typedef struct { cstr name, last; } Person; Person Person_make(const char* name, const char* last) { - return (Person){.name = cstr_from(name), .last = cstr_from(last)}; + return c_LITERAL(Person){.name = cstr_from(name), .last = cstr_from(last)}; } uint64_t Person_hash(const Person* a) { @@ -28,14 +29,14 @@ 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 <stc/cbox.h> #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 <stc/csset.h> -int main() +int main(void) { Persons vec = {0}; PBox p = PBox_from(Person_make("Laura", "Palmer")); diff --git a/misc/examples/box2.c b/misc/examples/box2.c index cba255d2..eaab1c47 100644 --- a/misc/examples/box2.c +++ b/misc/examples/box2.c @@ -13,27 +13,25 @@ typedef struct { Point bottom_right; } Rectangle; -#define i_val Point -#define i_no_cmp +#define i_key Point #include <stc/cbox.h> // cbox_Point -#define i_val Rectangle -#define i_no_cmp +#define i_key Rectangle #include <stc/cbox.h> // cbox_Rectangle // Box in box: -#define i_valboxed cbox_Point // NB: use i_valboxed when value is a cbox or carc! #define i_type BoxBoxPoint +#define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc! #define i_no_cmp #include <stc/cbox.h> // BoxBoxPoint Point origin(void) { - return (Point){ .x=1.0, .y=2.0 }; + return c_LITERAL(Point){ .x=1.0, .y=2.0 }; } cbox_Point boxed_origin(void) { // Allocate this point on the heap, and return a pointer to it - return cbox_Point_make((Point){ .x=1.0, .y=2.0 }); + return cbox_Point_make(c_LITERAL(Point){ .x=1.0, .y=2.0 }); } @@ -46,7 +44,7 @@ int main(void) { }; // Heap allocated rectangle - cbox_Rectangle boxed_rectangle = cbox_Rectangle_make((Rectangle){ + cbox_Rectangle boxed_rectangle = cbox_Rectangle_make(c_LITERAL(Rectangle){ .top_left = origin(), .bottom_right = { .x=3.0, .y=-4.0 } }); diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c new file mode 100644 index 00000000..599ceaab --- /dev/null +++ b/misc/examples/cointerleave.c @@ -0,0 +1,62 @@ +// https://www.youtube.com/watch?v=8sEe-4tig_A +#include <stdio.h> +#include <stc/calgo.h> +#define i_type IVec +#define i_key int +#include <stc/cvec.h> + +struct GenValue { + IVec *v; + IVec_iter it; + int cco_state; +}; + +static int get_value(struct GenValue* g) +{ + cco_routine(g) { + for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) + cco_yield_v(*g->it.ref); + } + return -1; +} + +struct Generator { + struct GenValue x, y; + int cco_state; + int value; +}; + +cco_result interleaved(struct Generator* g) +{ + cco_routine(g) { + while (!(cco_done(&g->x) & cco_done(&g->y))) { + g->value = get_value(&g->x); + if (!cco_done(&g->x)) + cco_yield(); + + g->value = get_value(&g->y); + if (!cco_done(&g->y)) + cco_yield(); + } + } + return CCO_DONE; +} + +void Use(void) +{ + IVec a = c_init(IVec, {2, 4, 6, 8, 10, 11}); + IVec b = c_init(IVec, {3, 5, 7, 9}); + + struct Generator g = {{&a}, {&b}}; + + cco_block_on(interleaved(&g)) { + printf("%d ", g.value); + } + puts(""); + c_drop(IVec, &a, &b); +} + +int main(void) +{ + Use(); +} diff --git a/misc/examples/complex.c b/misc/examples/complex.c index 7dde981d..4eb1574b 100644 --- a/misc/examples/complex.c +++ b/misc/examples/complex.c @@ -5,17 +5,16 @@ // using StackList = std::stack<FloatStack>; // using ListMap = std::unordered_map<int, std::forward_list<StackList>>; // using MapMap = std::unordered_map<std::string, ListMap>; - +#define i_implement #include <stc/cstr.h> - #define i_type FloatStack -#define i_val float +#define i_key float #include <stc/cstack.h> #define i_type StackList -#define i_valclass FloatStack // "class" picks up _clone, _drop -#define i_opt c_no_cmp // no FloatStack_cmp() +#define i_keyclass FloatStack // "class" picks up _clone, _drop, _cmp +#define i_opt c_no_cmp // exclude FloatStack_cmp(): not defined #include <stc/clist.h> #define i_type ListMap @@ -29,7 +28,7 @@ #include <stc/cmap.h> -int main() +int main(void) { MapMap mmap = {0}; @@ -44,7 +43,7 @@ int main() const ListMap* lmap_p = MapMap_at(&mmap, "first"); const StackList* list_p = ListMap_at(lmap_p, 42); const FloatStack* stack_p = StackList_back(list_p); - printf("value is: %f\n", *FloatStack_at(stack_p, 3)); // pi + printf("value is: %f\n", (double)*FloatStack_at(stack_p, 3)); // pi MapMap_drop(&mmap); } diff --git a/misc/examples/convert.c b/misc/examples/convert.c index 0f09e830..fa64560e 100644 --- a/misc/examples/convert.c +++ b/misc/examples/convert.c @@ -1,17 +1,17 @@ +#define i_implement #include <stc/cstr.h> #define i_key_str #define i_val_str #include <stc/cmap.h> -#define i_val_str +#define i_key_str #include <stc/cvec.h> -#define i_val_str -#define i_extern // define _clist_mergesort() once +#define i_key_str #include <stc/clist.h> -int main() +int main(void) { cmap_str map, mclone; cvec_str keys = {0}, values = {0}; @@ -24,7 +24,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/coread.c b/misc/examples/coread.c index 0a7f4816..a13f6be5 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -1,39 +1,41 @@ +#define i_implement #include <stc/cstr.h> #include <stc/algo/coroutine.h> #include <errno.h> // Read file line by line using coroutines: -struct file_nextline { +struct file_read { const char* filename; int cco_state; FILE* fp; cstr line; }; -bool file_nextline(struct file_nextline* U) +int file_read(struct file_read* g) { - cco_begin(U) - U->fp = fopen(U->filename, "r"); - U->line = cstr_init(); + cco_routine(g) { + g->fp = fopen(g->filename, "r"); + if (!g->fp) cco_return; + g->line = cstr_init(); - while (cstr_getline(&U->line, U->fp)) - cco_yield(true); + cco_await(!cstr_getline(&g->line, g->fp)); - cco_final: // this label is required. - printf("finish\n"); - cstr_drop(&U->line); - fclose(U->fp); - cco_end(false); + cco_cleanup: + printf("finish\n"); + cstr_drop(&g->line); + if (g->fp) fclose(g->fp); + } + return 0; } int main(void) { - struct file_nextline it = {__FILE__}; + struct file_read g = {__FILE__}; int n = 0; - while (file_nextline(&it)) + cco_block_on(file_read(&g)) { - printf("%3d %s\n", ++n, cstr_str(&it.line)); - //if (n == 10) cco_stop(&it); + printf("%3d %s\n", ++n, cstr_str(&g.line)); + //if (n == 10) cco_stop(&g); } } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index b11b8532..b8dfaa13 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -5,38 +5,39 @@ // Demonstrate to call another coroutine from a coroutine: // First create prime generator, then call fibonacci sequence: -bool is_prime(int64_t i) { - for (int64_t j=2; j*j <= i; ++j) +bool is_prime(long long i) { + for (long long j=2; j*j <= i; ++j) if (i % j == 0) return false; return true; } struct prime { int count, idx; - int64_t result, pos; + long long result, pos; int cco_state; }; -bool prime(struct prime* U) { - cco_begin(U); - if (U->result < 2) U->result = 2; - if (U->result == 2) { - if (U->count-- == 0) cco_return; - ++U->idx; - cco_yield(true); +int prime(struct prime* g) { + cco_routine(g) { + if (g->result < 2) g->result = 2; + if (g->result == 2) { + if (g->count-- == 0) cco_return; + ++g->idx; + cco_yield(); } - U->result += !(U->result & 1); - for (U->pos = U->result; U->count > 0; U->pos += 2) { - if (is_prime(U->pos)) { - --U->count; - ++U->idx; - U->result = U->pos; - cco_yield(true); + g->result += !(g->result & 1); + for (g->pos = g->result; g->count > 0; g->pos += 2) { + if (is_prime(g->pos)) { + --g->count; + ++g->idx; + g->result = g->pos; + cco_yield(); } } - cco_final: - printf("final prm\n"); - cco_end(false); + cco_cleanup: + printf("final prm\n"); + } + return 0; } @@ -44,30 +45,33 @@ bool prime(struct prime* U) { struct fibonacci { int count, idx; - int64_t result, b; + long long result, b; int cco_state; }; -bool fibonacci(struct fibonacci* F) { - assert(F->count < 94); +int fibonacci(struct fibonacci* g) { + assert(g->count < 94); - cco_begin(F); - F->idx = 0; - F->result = 0; - F->b = 1; + long long sum; + cco_routine(g) { + g->idx = 0; + g->result = 0; + g->b = 1; for (;;) { - if (F->count-- == 0) + if (g->count-- == 0) cco_return; - if (++F->idx > 1) { - int64_t sum = F->result + F->b; // NB! locals only lasts until next cco_yield! - F->result = F->b; - F->b = sum; + if (++g->idx > 1) { + // NB! locals lasts only until next yield/await! + sum = g->result + g->b; + g->result = g->b; + g->b = sum; } - cco_yield(true); + cco_yield(); } - cco_final: - printf("final fib\n"); - cco_end(false); + cco_cleanup: + printf("final fib\n"); + } + return 0; } // Combine @@ -78,29 +82,31 @@ struct combined { int cco_state; }; -bool combined(struct combined* C) { - cco_begin(C); - cco_yield(prime(&C->prm), &C->prm, true); - cco_yield(fibonacci(&C->fib), &C->fib, true); +int combined(struct combined* g) { + cco_routine(g) { + cco_await_on(prime(&g->prm)); + cco_await_on(fibonacci(&g->fib)); - // Reuse the C->prm context and extend the count: - C->prm.count = 8; C->prm.result += 2; - cco_reset(&C->prm); - cco_yield(prime(&C->prm), &C->prm, true); + // Reuse the g->prm context and extend the count: + g->prm.count = 8, g->prm.result += 2; + cco_reset(&g->prm); + cco_await_on(prime(&g->prm)); - cco_final: puts("final comb"); - cco_end(false); + cco_cleanup: + puts("final combined"); + } + return 0; } -int main(void) { - struct combined comb = {.prm={.count=8}, .fib={14}}; - if (true) - while (combined(&comb)) +int main(void) +{ + struct combined c = {.prm={.count=8}, .fib={14}}; + int res; + + cco_block_on(combined(&c), &res) { + if (res == CCO_YIELD) printf("Prime(%d)=%lld, Fib(%d)=%lld\n", - comb.prm.idx, (long long)comb.prm.result, - comb.fib.idx, (long long)comb.fib.result); - else - while (prime(&comb.prm)) - printf("Prime(%d)=%lld\n", - comb.prm.idx, (long long)comb.prm.result); + c.prm.idx, c.prm.result, + c.fib.idx, c.fib.result); + } } diff --git a/misc/examples/csmap_erase.c b/misc/examples/csmap_erase.c index 697e6c09..8d4eeae3 100644 --- a/misc/examples/csmap_erase.c +++ b/misc/examples/csmap_erase.c @@ -1,5 +1,6 @@ // map_erase.c // From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16 +#define i_implement #include <stc/cstr.h> #include <stdio.h> @@ -15,7 +16,7 @@ void printmap(mymap m) printf("\nsize() == %" c_ZI "\n\n", mymap_size(&m)); } -int main() +int main(void) { mymap m1 = {0}; @@ -34,7 +35,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..c392338d 100644 --- a/misc/examples/csmap_find.c +++ b/misc/examples/csmap_find.c @@ -1,5 +1,6 @@ // This implements the c++ std::map::find example at: // https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17 +#define i_implement #include <stc/cstr.h> #define i_key int @@ -7,8 +8,7 @@ #define i_tag istr #include <stc/csmap.h> -#define i_val csmap_istr_raw -#define i_opt c_no_cmp +#define i_key csmap_istr_raw #define i_tag istr #include <stc/cvec.h> @@ -40,21 +40,21 @@ void findit(csmap_istr c, csmap_istr_key val) } } -int main() +int main(void) { - 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):"); print_collection_csmap_istr(&m1); typedef cvec_istr_value pair; - cvec_istr_push(&v, (pair){43, "Tc"}); - cvec_istr_push(&v, (pair){41, "Nb"}); - cvec_istr_push(&v, (pair){46, "Pd"}); - cvec_istr_push(&v, (pair){42, "Mo"}); - cvec_istr_push(&v, (pair){44, "Ru"}); - cvec_istr_push(&v, (pair){44, "Ru"}); // attempt a duplicate + cvec_istr_push(&v, c_LITERAL(pair){43, "Tc"}); + cvec_istr_push(&v, c_LITERAL(pair){41, "Nb"}); + cvec_istr_push(&v, c_LITERAL(pair){46, "Pd"}); + cvec_istr_push(&v, c_LITERAL(pair){42, "Mo"}); + cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); + cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); // attempt a duplicate puts("Inserting the following vector data into m1:"); print_collection_cvec_istr(&v); diff --git a/misc/examples/csmap_insert.c b/misc/examples/csmap_insert.c index 3da245c7..c9f02891 100644 --- a/misc/examples/csmap_insert.c +++ b/misc/examples/csmap_insert.c @@ -5,13 +5,14 @@ #define i_tag ii // Map of int => int #include <stc/csmap.h> +#define i_implement #include <stc/cstr.h> #define i_key int #define i_val_str #define i_tag istr // Map of int => cstr #include <stc/csmap.h> -#define i_val csmap_ii_raw +#define i_key csmap_ii_raw #define i_opt c_no_cmp #define i_tag ii #include <stc/cvec.h> @@ -28,12 +29,12 @@ void print_istr(csmap_istr map) { puts(""); } -int main() +int main(void) { // insert single values csmap_ii m1 = {0}; csmap_ii_insert(&m1, 1, 10); - csmap_ii_push(&m1, (csmap_ii_value){2, 20}); + csmap_ii_push(&m1, c_LITERAL(csmap_ii_value){2, 20}); puts("The original key and mapped values of m1 are:"); print_ii(m1); @@ -60,11 +61,11 @@ int main() csmap_ii m2 = {0}; cvec_ii v = {0}; typedef cvec_ii_value ipair; - cvec_ii_push(&v, (ipair){43, 294}); - cvec_ii_push(&v, (ipair){41, 262}); - cvec_ii_push(&v, (ipair){45, 330}); - cvec_ii_push(&v, (ipair){42, 277}); - cvec_ii_push(&v, (ipair){44, 311}); + cvec_ii_push(&v, c_LITERAL(ipair){43, 294}); + cvec_ii_push(&v, c_LITERAL(ipair){41, 262}); + cvec_ii_push(&v, c_LITERAL(ipair){45, 330}); + cvec_ii_push(&v, c_LITERAL(ipair){42, 277}); + cvec_ii_push(&v, c_LITERAL(ipair){44, 311}); puts("Inserting the following vector data into m2:"); c_foreach (e, cvec_ii, v) @@ -96,7 +97,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..9c7f5e1a 100644 --- a/misc/examples/csset_erase.c +++ b/misc/examples/csset_erase.c @@ -3,9 +3,9 @@ #define i_key int #include <stc/csset.h> -int main() +int main(void) { - 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); @@ -38,4 +38,4 @@ int main() puts(""); csset_int_drop(&set); -}
\ No newline at end of file +} diff --git a/misc/examples/cstr_match.c b/misc/examples/cstr_match.c index 58cf8884..be03e981 100644 --- a/misc/examples/cstr_match.c +++ b/misc/examples/cstr_match.c @@ -1,8 +1,9 @@ +#define i_implement #include <stc/cstr.h> #include <stc/csview.h> #include <stdio.h> -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 de92e378..ecc89f2e 100644 --- a/misc/examples/demos.c +++ b/misc/examples/demos.c @@ -1,6 +1,7 @@ +#define i_implement #include <stc/cstr.h> -void stringdemo1() +void stringdemo1(void) { cstr cs = cstr_lit("one-nine-three-seven-five"); printf("%s.\n", cstr_str(&cs)); @@ -27,11 +28,11 @@ void stringdemo1() cstr_drop(&cs); } -#define i_val int64_t +#define i_key int64_t #define i_tag ix #include <stc/cvec.h> -void vectordemo1() +void vectordemo1(void) { cvec_ix bignums = cvec_ix_with_capacity(100); cvec_ix_reserve(&bignums, 100); @@ -51,10 +52,10 @@ void vectordemo1() cvec_ix_drop(&bignums); } -#define i_val_str +#define i_key_str #include <stc/cvec.h> -void vectordemo2() +void vectordemo2(void) { cvec_str names = {0}; cvec_str_emplace_back(&names, "Mary"); @@ -71,11 +72,12 @@ void vectordemo2() cvec_str_drop(&names); } -#define i_val int +#define i_key int #define i_tag ix +#define i_native_cmp #include <stc/clist.h> -void listdemo1() +void listdemo1(void) { clist_ix nums = {0}, nums2 = {0}; for (int i = 0; i < 10; ++i) @@ -107,7 +109,7 @@ void listdemo1() #define i_tag i #include <stc/cset.h> -void setdemo1() +void setdemo1(void) { cset_i nums = {0}; cset_i_insert(&nums, 8); @@ -123,7 +125,7 @@ void setdemo1() #define i_tag ii #include <stc/cmap.h> -void mapdemo1() +void mapdemo1(void) { cmap_ii nums = {0}; cmap_ii_insert(&nums, 8, 64); @@ -137,7 +139,7 @@ void mapdemo1() #define i_tag si #include <stc/cmap.h> -void mapdemo2() +void mapdemo2(void) { cmap_si nums = {0}; cmap_si_emplace_or_assign(&nums, "Hello", 64); @@ -159,7 +161,7 @@ void mapdemo2() #define i_val_str #include <stc/cmap.h> -void mapdemo3() +void mapdemo3(void) { cmap_str table = {0}; cmap_str_emplace(&table, "Map", "test"); @@ -179,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 new file mode 100644 index 00000000..a5063a42 --- /dev/null +++ b/misc/examples/dining_philosophers.c @@ -0,0 +1,105 @@ +// https://en.wikipedia.org/wiki/Dining_philosophers_problem +#include <stdio.h> +#include <time.h> +#include <stc/crand.h> +#include <stc/algo/coroutine.h> + +// Define the number of philosophers and forks +enum { + num_philosophers = 5, + num_forks = num_philosophers, +}; + +struct Philosopher { + int id; + cco_timer tm; + cco_sem* left_fork; + cco_sem* right_fork; + int cco_state; // required +}; + +struct Dining { + // Define semaphores for the forks + cco_sem forks[num_forks]; + struct Philosopher ph[num_philosophers]; + int cco_state; // required +}; + + +// Philosopher coroutine +int philosopher(struct Philosopher* p) +{ + double duration; + cco_routine(p) { + while (1) { + duration = 1.0 + crandf()*2.0; + printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10); + cco_timer_await(&p->tm, duration); + + printf("Philosopher %d is hungry...\n", p->id); + cco_sem_await(p->left_fork); + cco_sem_await(p->right_fork); + + duration = 0.5 + crandf(); + printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10); + cco_timer_await(&p->tm, duration); + + cco_sem_release(p->left_fork); + cco_sem_release(p->right_fork); + } + + cco_cleanup: + printf("Philosopher %d finished\n", p->id); + } + return 0; +} + + +// Dining coroutine +int dining(struct Dining* d) +{ + cco_routine(d) { + for (int i = 0; i < num_forks; ++i) + cco_sem_set(&d->forks[i], 1); // all forks available + for (int i = 0; i < num_philosophers; ++i) { + cco_reset(&d->ph[i]); + d->ph[i].id = i + 1; + d->ph[i].left_fork = &d->forks[i]; + d->ph[i].right_fork = &d->forks[(i + 1) % num_forks]; + } + + while (1) { + // per-"frame" logic resume each philosopher + for (int i = 0; i < num_philosophers; ++i) { + philosopher(&d->ph[i]); + } + cco_yield(); // suspend, return control back to main + } + + cco_cleanup: + for (int i = 0; i < num_philosophers; ++i) { + cco_stop(&d->ph[i]); + philosopher(&d->ph[i]); + } + puts("Dining finished"); + } + return 0; +} + +int main(void) +{ + struct Dining dine; + cco_reset(&dine); + int n=0; + cco_timer tm = cco_timer_from(15.0); // seconds + csrand((uint64_t)time(NULL)); + + while (!cco_done(&dine)) { + if (cco_timer_expired(&tm)) + cco_stop(&dine); + dining(&dine); // resume + cco_sleep(0.001); + ++n; + } + printf("n=%d\n", n); +} diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index fbb7280f..f3c008b3 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -1,12 +1,13 @@ #include <stdio.h> -#define i_extern +#define i_import #include <stc/cstr.h> +#define i_implement #include <stc/csview.h> #include <stc/algo/filter.h> #include <stc/algo/crange.h> #define i_type IVec -#define i_val int +#define i_key int #include <stc/cstack.h> // filters and transforms: @@ -17,7 +18,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)) @@ -54,7 +55,8 @@ fn main() { void demo2(void) { IVec vector = {0}; - c_forfilter (x, crange, crange_obj(INT64_MAX), + crange r = crange_make(INT64_MAX); + c_forfilter (x, crange, r, c_flt_skipwhile(x, *x.ref != 11) && (*x.ref % 2) != 0 && c_flt_take(x, 5) @@ -81,7 +83,7 @@ fn main() { } */ #define i_type SVec -#define i_valclass csview +#define i_keyclass csview #include <stc/cstack.h> void demo3(void) diff --git a/misc/examples/forloops.c b/misc/examples/forloops.c index 1fc00614..47cced8f 100644 --- a/misc/examples/forloops.c +++ b/misc/examples/forloops.c @@ -2,7 +2,7 @@ #include <stc/algo/filter.h>
#define i_type IVec
-#define i_val int
+#define i_key int
#include <stc/cstack.h>
#define i_type IMap
@@ -11,7 +11,7 @@ #include <stc/cmap.h>
-int main()
+int main(void)
{
puts("c_forrange:");
c_forrange (30) printf(" xx");
@@ -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/functor.c b/misc/examples/functor.c index c0a4f8e8..e3bde1dd 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -1,22 +1,22 @@ // Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue // Example of per-instance less-function on a single priority queue type // -// Note: i_less: has self for cpque types only -// i_cmp: has self for csmap and csset types only -// i_hash/i_eq: has self for cmap and cset types only #include <stdio.h> #define i_type IPQue -#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_base cpque +#define i_key int +#define i_extend bool(*less)(const int*, const int*); +#define i_less(x, y) c_extend()->less(x, y) +// Note: i_less: c_extend() accessible for cpque types +// i_cmp: c_extend() accessible for csmap and csset types +// i_hash/i_eq: c_extend() accessible for cmap and cset types #include <stc/extend.h> void print_queue(const char* name, IPQue_ext q) { // NB: make a clone because there is no way to traverse - // priority_queue's content without erasing the queue. + // priority queue's content without erasing the queue. IPQue_ext copy = {q.less, IPQue_clone(q.get)}; for (printf("%s: \t", name); !IPQue_empty(©.get); IPQue_pop(©.get)) @@ -30,28 +30,27 @@ 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"); - c_forrange (i, n) - printf("%d ", data[i]); + c_forrange (i, n) printf("%d ", data[i]); puts(""); - IPQue_ext q1 = {int_less}; // Max priority queue - IPQue_ext minq1 = {int_greater}; // Min priority queue - IPQue_ext q5 = {int_lambda}; // Using lambda to compare elements. - c_forrange (i, n) - IPQue_push(&q1.get, data[i]); + // Max priority queue + IPQue_ext q1 = {.less=int_less}; + IPQue_put_n(&q1.get, data, n); print_queue("q1", q1); - c_forrange (i, n) - IPQue_push(&minq1.get, data[i]); + // Min priority queue + IPQue_ext minq1 = {.less=int_greater}; + IPQue_put_n(&minq1.get, data, n); print_queue("minq1", minq1); - c_forrange (i, n) - IPQue_push(&q5.get, data[i]); + // Using lambda to compare elements. + IPQue_ext q5 = {.less=int_lambda}; + IPQue_put_n(&q5.get, data, n); print_queue("q5", q5); c_drop(IPQue, &q1.get, &minq1.get, &q5.get); diff --git a/misc/examples/gauss2.c b/misc/examples/gauss2.c index df709d03..1ab8ade5 100644 --- a/misc/examples/gauss2.c +++ b/misc/examples/gauss2.c @@ -1,20 +1,21 @@ #include <stdio.h> #include <time.h> -#include <stc/crand.h> +#define i_implement #include <stc/cstr.h> +#include <stc/crand.h> // Declare int -> int sorted map. #define i_key int #define i_val int #include <stc/csmap.h> -int main() +int main(void) { enum {N = 5000000}; uint64_t seed = (uint64_t)time(NULL); crand_t rng = crand_init(seed); - const double Mean = round(crand_f64(&rng)*98.f - 49.f), StdDev = crand_f64(&rng)*10.f + 1.f, Scale = 74.f; + const double Mean = round(crand_f64(&rng)*98.0 - 49.0), StdDev = crand_f64(&rng)*10.0 + 1.0, Scale = 74.0; printf("Demo of gaussian / normal distribution of %d random samples\n", N); printf("Mean %f, StdDev %f\n", Mean, StdDev); diff --git a/misc/examples/generator.c b/misc/examples/generator.c index 2bccc489..a15f9ba5 100644 --- a/misc/examples/generator.c +++ b/misc/examples/generator.c @@ -4,49 +4,51 @@ #include <stdio.h> typedef struct { - int n; + int size; int a, b, c; -} Triple_value, Triple; +} Triple, Triple_value; typedef struct { Triple_value* ref; + int count; int cco_state; } Triple_iter; -bool Triple_next(Triple_iter* it) { - Triple_value* t = it->ref; - cco_begin(it); - for (t->c = 1;; ++t->c) { - for (t->a = 1; t->a < t->c; ++t->a) { - for (t->b = t->a; t->b < t->c; ++t->b) { - if (t->a*t->a + t->b*t->b == t->c*t->c) { - if (t->n-- == 0) cco_return; - cco_yield(true); +int Triple_next(Triple_iter* it) { + Triple_value* g = it->ref; + cco_routine(it) + { + for (g->c = 5; g->size; ++g->c) { + for (g->a = 1; g->a < g->c; ++g->a) { + for (g->b = g->a; g->b < g->c; ++g->b) { + if (g->a*g->a + g->b*g->b == g->c*g->c) { + if (it->count++ == g->size) + cco_return; + cco_yield(); } } } } - cco_final: - it->ref = NULL; - cco_end(false); + cco_cleanup: + it->ref = NULL; + } + return 0; } -Triple_iter Triple_begin(Triple* t) { - Triple_iter it = {t}; - if (t->n > 0) Triple_next(&it); - else it.ref = NULL; +Triple_iter Triple_begin(Triple* g) { + Triple_iter it = {.ref=g}; + Triple_next(&it); return it; } -int main() +int main(void) { puts("Pythagorean triples with c < 100:"); - Triple t = {INT32_MAX}; - c_foreach (i, Triple, t) - { + Triple triple = {.size=30}; // max number of triples + c_foreach (i, Triple, triple) { if (i.ref->c < 100) - printf("%u: (%d, %d, %d)\n", INT32_MAX - i.ref->n + 1, i.ref->a, i.ref->b, i.ref->c); + printf("%u: (%d, %d, %d)\n", i.count, i.ref->a, i.ref->b, i.ref->c); else cco_stop(&i); } diff --git a/misc/examples/hashmap.c b/misc/examples/hashmap.c index 47a3bcff..cf11b7f7 100644 --- a/misc/examples/hashmap.c +++ b/misc/examples/hashmap.c @@ -1,4 +1,5 @@ // https://doc.rust-lang.org/rust-by-example/std/hash.html +#define i_implement #include <stc/cstr.h> #define i_key_str #define i_val_str diff --git a/misc/examples/inits.c b/misc/examples/inits.c index 81bcdd3e..53a49f1f 100644 --- a/misc/examples/inits.c +++ b/misc/examples/inits.c @@ -1,3 +1,4 @@ +#define i_implement #include <stc/cstr.h> #define i_key int @@ -17,18 +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 <stc/cvec.h> -#define i_val ipair_t +#define i_key ipair_t #define i_cmp ipair_cmp #define i_tag ip -#define i_extern // define _clist_mergesort() once #include <stc/clist.h> -#define i_val float +#define i_key float #define i_tag f #include <stc/cpque.h> @@ -45,7 +45,7 @@ int main(void) puts("\npop and show high priorites first:"); while (! cpque_f_empty(&floats)) { - printf("%.1f ", *cpque_f_top(&floats)); + printf("%.1f ", (double)*cpque_f_top(&floats)); cpque_f_pop(&floats); } puts("\n"); @@ -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/intrusive.c b/misc/examples/intrusive.c index 0f153589..80c1f63b 100644 --- a/misc/examples/intrusive.c +++ b/misc/examples/intrusive.c @@ -3,8 +3,9 @@ #include <stdio.h> #define i_type List -#define i_val int -#include <stc/clist.h> +#define i_key int +#define i_native_cmp +#include <stc/clist.h> void printList(List list) { printf("list:"); @@ -13,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, {.value=*i.ref})); diff --git a/misc/examples/list.c b/misc/examples/list.c index 363d7fec..fa33305a 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -4,10 +4,11 @@ #include <stc/crand.h> #define i_type DList -#define i_val double +#define i_key double +#define i_native_cmp #include <stc/clist.h> -int main() { +int main(void) { const int n = 3000000; DList list = {0}; @@ -34,7 +35,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..211c5a5d 100644 --- a/misc/examples/list_erase.c +++ b/misc/examples/list_erase.c @@ -2,12 +2,12 @@ #include <stdio.h> #define i_type IList -#define i_val int +#define i_key int #include <stc/clist.h> -int main () +int main(void) { - 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..f1fd6e1f 100644 --- a/misc/examples/list_splice.c +++ b/misc/examples/list_splice.c @@ -1,8 +1,7 @@ #include <stdio.h> -#define i_val int +#define i_key int #define i_tag i -#define i_extern // define _clist_mergesort() once #include <stc/clist.h> void print_ilist(const char* s, clist_i list) @@ -14,10 +13,10 @@ void print_ilist(const char* s, clist_i list) puts(""); } -int main () +int main(void) { - 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..e5d816e9 100644 --- a/misc/examples/lower_bound.c +++ b/misc/examples/lower_bound.c @@ -1,17 +1,18 @@ #include <stdio.h> -#define i_val int +#define i_key int +#define i_native_cmp #include <stc/cvec.h> -#define i_val int +#define i_key int #include <stc/csset.h> -int main() +int main(void) { // 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 +41,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/make.sh b/misc/examples/make.sh index b0c0bd52..cf224950 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -1,20 +1,19 @@ #!/bin/sh if [ "$(uname)" = 'Linux' ]; then - sanitize='-fsanitize=address' + sanitize='-fsanitize=address -fsanitize=undefined -fsanitize-trap' clibs='-lm' # -pthread oflag='-o ' fi -cc=gcc; cflags="-s -O3 -std=c99 -Wconversion -Wpedantic -Wall -Wsign-compare -Wwrite-strings -Wno-maybe-uninitialized" -#cc=gcc; cflags="-g -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" -#cc=tcc; cflags="-Wall -std=c99" -#cc=clang; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall -Wno-unused-function -Wsign-compare -Wwrite-strings" -#cc=gcc; cflags="-x c++ -s -O2 -Wall -std=c++20" -#cc=g++; cflags="-x c++ -s -O2 -Wall" -#cc=cl; cflags="-O2 -nologo -W3 -MD" -#cc=cl; cflags="-nologo -TP" -#cc=cl; cflags="-nologo -std:c11" +cc=gcc; cflags="-std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-implicit-fallthrough -Wno-missing-field-initializers" +#cc=gcc; cflags="-std=c99 -g -Werror -Wfatal-errors -Wpedantic -Wall $sanitize" +#cc=tcc; cflags="-std=c99 -Wall" +#cc=clang; cflags="-std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -Wno-missing-field-initializers" +#cc=gcc; cflags="-x c++ -std=c++20 -O2 -s -Wall" +#cc=cl; cflags="-nologo -O2 -MD -W3 -wd4003" +#cc=cl; cflags="-nologo -TP -std:c++20 -wd4003" +#cc=cl; cflags="-nologo -std:c11 -wd4003" if [ "$cc" = "cl" ]; then oflag='/Fe:' diff --git a/misc/examples/mapmap.c b/misc/examples/mapmap.c index 668da5de..d3065659 100644 --- a/misc/examples/mapmap.c +++ b/misc/examples/mapmap.c @@ -1,5 +1,5 @@ // create a structure like: std::map<std::string, std::map<std::string, std::string>>: - +#define i_implement #include <stc/cstr.h> // People: std::map<std::string, std::string> diff --git a/misc/examples/mmap.c b/misc/examples/mmap.c index 0394a2df..04a605a7 100644 --- a/misc/examples/mmap.c +++ b/misc/examples/mmap.c @@ -2,8 +2,9 @@ // https://en.cppreference.com/w/cpp/container/multimap/insert // Multimap entries +#define i_implement #include <stc/cstr.h> -#define i_val_str +#define i_key_str #include <stc/clist.h> // Map of int => clist_str. @@ -29,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 3980e6d8..798a1126 100644 --- a/misc/examples/multidim.c +++ b/misc/examples/multidim.c @@ -6,9 +6,9 @@ using_cspan3(ispan, int); -int main() +int main(void) { - 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); @@ -28,7 +28,6 @@ int main() } puts("ss3 = ms3[:, 1:3, 1:3]"); ispan3 ss3 = ms3; - //cspan_slice(&ss3, {c_ALL}, {1,3}, {1,3}); ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3}); for (int i=0; i != ss3.shape[0]; i++) { diff --git a/misc/examples/multimap.c b/misc/examples/multimap.c index d8981a81..1068a5dc 100644 --- a/misc/examples/multimap.c +++ b/misc/examples/multimap.c @@ -1,3 +1,4 @@ +#define i_implement #include <stc/cstr.h> // Olympics multimap example @@ -39,7 +40,7 @@ OlympicLoc OlympicLoc_clone(OlympicLoc loc); void OlympicLoc_drop(OlympicLoc* self); // Create a clist<OlympicLoc>, 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 <stc/clist.h> @@ -65,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 3714e1d5..16111b0b 100644 --- a/misc/examples/music_arc.c +++ b/misc/examples/music_arc.c @@ -1,5 +1,6 @@ // shared_ptr-examples.cpp // based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 +#define i_implement #include <stc/cstr.h> typedef struct @@ -12,7 +13,7 @@ int Song_cmp(const Song* x, const Song* y) { return cstr_cmp(&x->title, &y->title); } Song Song_make(const char* artist, const char* title) - { return (Song){cstr_from(artist), cstr_from(title)}; } + { return c_LITERAL(Song){cstr_from(artist), cstr_from(title)}; } void Song_drop(Song* s) { printf("drop: %s\n", cstr_str(&s->title)); @@ -21,18 +22,18 @@ void Song_drop(Song* s) { // Define the shared pointer: #define i_type SongArc -#define i_valclass Song -#define i_opt c_no_hash // arc require hash fn, disable as we don't need it. +#define i_keyclass Song +#define i_no_hash // no hash fn for Song, fallback hash pointer to Song. #include <stc/carc.h> // ... and a vector of them #define i_type SongVec -#define i_valboxed SongArc // use i_valboxed on carc / cbox instead of i_val -#include <stc/cstack.h> +#define i_keyboxed SongArc // use i_keyboxed on carc / cbox (instead of i_key) +#include <stc/cvec.h> -void example3() +void example3(void) { - 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") @@ -60,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 8b291d34..9676e7b4 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -5,11 +5,11 @@ forward_clist(clist_i32, int); forward_clist(clist_pnt, struct Point); typedef struct { - clist_i32 intlst; - clist_pnt pntlst; + clist_i32 intlist; + clist_pnt pntlist; } MyStruct; -#define i_val int +#define i_key int #define i_tag i32 #define i_is_forward #include <stc/clist.h> @@ -20,49 +20,51 @@ 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 <stc/clist.h> -#define i_val float +#define i_key float +#define i_native_cmp // use < and == operators for comparison #include <stc/clist.h> void MyStruct_drop(MyStruct* s); #define i_type MyList -#define i_valclass MyStruct // i_valclass uses MyStruct_drop -#define i_opt c_no_clone|c_no_cmp +#define i_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 <stc/clist.h> void MyStruct_drop(MyStruct* s) { - clist_i32_drop(&s->intlst); - clist_pnt_drop(&s->pntlst); + clist_i32_drop(&s->intlist); + clist_pnt_drop(&s->pntlist); } -int main() +int main(void) { MyStruct my = {0}; - clist_i32_push_back(&my.intlst, 123); - clist_pnt_push_back(&my.pntlst, (Point){123, 456}); + clist_i32_push_back(&my.intlist, 123); + clist_pnt_push_back(&my.pntlist, c_LITERAL(Point){123, 456}); MyStruct_drop(&my); - clist_pnt plst = c_make(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); - clist_pnt_sort(&plst); + clist_pnt plist = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); + clist_pnt_sort(&plist); - c_foreach (i, clist_pnt, plst) + c_foreach (i, clist_pnt, plist) printf(" (%d %d)", i.ref->x, i.ref->y); puts(""); - clist_pnt_drop(&plst); + clist_pnt_drop(&plist); - clist_float flst = c_make(clist_float, {123.3f, 321.2f, -32.2f, 78.2f}); - clist_float_sort(&flst); + clist_float flist = c_init(clist_float, {123.3f, 321.2f, -32.2f, 78.2f}); + clist_float_sort(&flist); - c_foreach (i, clist_float, flst) - printf(" %g", *i.ref); + c_foreach (i, clist_float, flist) + printf(" %g", (double)*i.ref); puts(""); - clist_float_drop(&flst); + clist_float_drop(&flist); } diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c index 3a4f934d..de990040 100644 --- a/misc/examples/new_map.c +++ b/misc/examples/new_map.c @@ -1,12 +1,13 @@ +#define i_implement #include <stc/cstr.h> #include <stc/forward.h> forward_cmap(cmap_pnt, struct Point, int); -struct MyStruct { +typedef struct MyStruct { cmap_pnt pntmap; cstr name; -} typedef MyStruct; +} MyStruct; // int => int map #define i_key int @@ -14,7 +15,7 @@ struct MyStruct { #include <stc/cmap.h> // Point => int map -struct Point { int x, y; } typedef Point; +typedef struct Point { int x, y; } Point; int point_cmp(const Point* a, const Point* b) { int c = a->x - b->x; @@ -40,20 +41,20 @@ int point_cmp(const Point* a, const Point* b) { #include <stc/cset.h> -int main() +int main(void) { - 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 9147e3f2..16823bb6 100644 --- a/misc/examples/new_pque.c +++ b/misc/examples/new_pque.c @@ -1,16 +1,16 @@ #include <stdio.h> -struct Point { int x, y; } typedef Point; +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 <stc/cpque.h> -int main() +int main(void) { - 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_queue.c b/misc/examples/new_queue.c index 916f4dbc..f3592df6 100644 --- a/misc/examples/new_queue.c +++ b/misc/examples/new_queue.c @@ -5,22 +5,22 @@ forward_cqueue(cqueue_pnt, struct Point); -struct Point { int x, y; } typedef Point; +typedef struct Point { int x, y; } Point; int point_cmp(const Point* a, const Point* b) { int c = c_default_cmp(&a->x, &b->x); return c ? c : c_default_cmp(&a->y, &b->y); } -#define i_val Point +#define i_key Point #define i_cmp point_cmp #define i_is_forward #define i_tag pnt #include <stc/cqueue.h> #define i_type IQ -#define i_val int +#define i_key int #include <stc/cqueue.h> -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 d8245b8b..ee946c9a 100644 --- a/misc/examples/new_smap.c +++ b/misc/examples/new_smap.c @@ -1,3 +1,4 @@ +#define i_implement #include <stc/cstr.h> #include <stc/forward.h> @@ -10,7 +11,7 @@ typedef struct { } MyStruct; // Point => int map -struct Point { int x, y; } typedef Point; +typedef struct Point { int x, y; } Point; int point_cmp(const Point* a, const Point* b) { int c = a->x - b->x; return c ? c : a->y - b->y; @@ -35,14 +36,14 @@ int point_cmp(const Point* a, const Point* b) { #include <stc/csset.h> -int main() +int main(void) { - 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/new_sptr.c b/misc/examples/new_sptr.c index 1b72e4f5..7fef5d1f 100644 --- a/misc/examples/new_sptr.c +++ b/misc/examples/new_sptr.c @@ -1,3 +1,4 @@ +#define i_implement #include <stc/cstr.h> typedef struct { cstr name, last; } Person; @@ -8,28 +9,27 @@ int Person_cmp(const Person* a, const Person* b); uint64_t Person_hash(const Person* p); #define i_type PersonArc -#define i_valclass Person // "class" ensure Person_drop will be called -#define i_cmp Person_cmp // enable carc object comparisons (not ptr to obj) -#define i_hash Person_hash // enable carc object hash (not ptr to obj) +#define i_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined. #include <stc/carc.h> #define i_type IPtr -#define i_val int -#define i_valdrop(x) printf("drop: %d\n", *x) -#define i_no_clone +#define i_key int +#define i_keydrop(x) printf("drop: %d\n", *x) +#define i_native_cmp #include <stc/carc.h> #define i_type IPStack -#define i_valboxed IPtr +#define i_keyboxed IPtr #include <stc/cstack.h> #define i_type PASet -#define i_valboxed PersonArc +#define i_keyboxed PersonArc #include <stc/cset.h> Person Person_make(const char* name, const char* last) { - return (Person){.name = cstr_from(name), .last = cstr_from(last)}; + Person p = {.name = cstr_from(name), .last = cstr_from(last)}; + return p; } int Person_cmp(const Person* a, const Person* b) { diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c index df443b7f..88efd55a 100644 --- a/misc/examples/new_vec.c +++ b/misc/examples/new_vec.c @@ -4,32 +4,33 @@ forward_cvec(cvec_i32, int); forward_cvec(cvec_pnt, struct Point); -struct MyStruct { +typedef struct MyStruct { cvec_i32 intvec; cvec_pnt pntvec; -} typedef MyStruct; +} MyStruct; -#define i_val int -#define i_is_forward +#define i_key int #define i_tag i32 +#define i_is_forward #include <stc/cvec.h> 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 #define i_is_forward -#define i_tag pnt #include <stc/cvec.h> -int main() +int main(void) { MyStruct my = {0}; - cvec_pnt_push(&my.pntvec, (Point){42, 14}); - cvec_pnt_push(&my.pntvec, (Point){32, 94}); - cvec_pnt_push(&my.pntvec, (Point){62, 81}); - cvec_pnt_push(&my.pntvec, (Point){32, 91}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){42, 14}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 94}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){62, 81}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 91}); cvec_pnt_sort(&my.pntvec); diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c index 620d311f..38c883a7 100644 --- a/misc/examples/person_arc.c +++ b/misc/examples/person_arc.c @@ -1,10 +1,12 @@ /* cbox: heap allocated boxed type */ +#define i_implement #include <stc/cstr.h> typedef struct { cstr name, last; } Person; Person Person_make(const char* name, const char* last) { - return (Person){.name = cstr_from(name), .last = cstr_from(last)}; + Person p = {.name = cstr_from(name), .last = cstr_from(last)}; + return p; } int Person_cmp(const Person* a, const Person* b) { @@ -28,16 +30,16 @@ 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 <stc/carc.h> #define i_type Persons -#define i_valboxed PSPtr // binds PSPtr_cmp, PSPtr_drop... +#define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop... #include <stc/cvec.h> -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/phonebook.c b/misc/examples/phonebook.c index c0007cb7..faf7566e 100644 --- a/misc/examples/phonebook.c +++ b/misc/examples/phonebook.c @@ -20,7 +20,7 @@ // IN THE SOFTWARE. // Program to emulates the phone book. - +#define i_implement #include <stc/cstr.h> #define i_key_str @@ -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/prime.c b/misc/examples/prime.c index c3a0663c..c3db707d 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -28,15 +28,18 @@ cbits sieveOfEratosthenes(llong n) int main(void) { + llong n = 100000000; printf("Computing prime numbers up to %lld\n", n); - clock_t t1 = clock(); + clock_t t = clock(); cbits primes = sieveOfEratosthenes(n + 1); + llong np = cbits_count(&primes); clock_t t2 = clock(); printf("Number of primes: %lld, time: %f\n\n", np, (float)(t2 - t1) / (float)CLOCKS_PER_SEC); + puts("Show all the primes in the range [2, 1000):"); printf("2"); c_forrange (i, 3, 1000, 2) @@ -44,7 +47,9 @@ int main(void) puts("\n"); puts("Show the last 50 primes using a temporary crange generator:"); - c_forfilter (i, crange, crange_obj(n - 1, 0, -2), + crange range = crange_make(n - 1, 0, -2); + + c_forfilter (i, crange, range, cbits_test(&primes, *i.ref/2) && c_flt_take(i, 50) ){ diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c index 7459ac77..cd3c5f4f 100644 --- a/misc/examples/printspan.c +++ b/misc/examples/printspan.c @@ -1,17 +1,16 @@ // printspan.c #include <stdio.h> +#define i_implement #include <stc/cstr.h> -#define i_val int +#define i_key int #include <stc/cvec.h> -#define i_val int +#define i_key int #include <stc/cstack.h> -#define i_val int -#include <stc/cdeq.h> -#define i_val_str +#define i_key_str #include <stc/csset.h> -#include <stc/cspan.h> +#include <stc/cspan.h> using_cspan(intspan, int, 1); void printMe(intspan container) { @@ -21,29 +20,26 @@ void printMe(intspan container) { puts(""); } -int main() +int main(void) { - intspan sp1 = cspan_make(intspan, {1, 2}); + intspan sp1 = cspan_init(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) ); + printMe( c_LITERAL(intspan)cspan_subspan(&sp2, 1, 4) ); - cvec_int vec = c_make(cvec_int, {1, 2, 3, 4, 5}); - printMe( (intspan)cspan_from(&vec) ); + cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5}); + printMe( c_LITERAL(intspan)cspan_from(&vec) ); printMe( sp2 ); - cstack_int stk = c_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) ); + cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7}); + printMe( c_LITERAL(intspan)cspan_from(&stk) ); - csset_str set = c_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)); @@ -52,6 +48,5 @@ int main() // cleanup cvec_int_drop(&vec); cstack_int_drop(&stk); - cdeq_int_drop(&deq); csset_str_drop(&set); } diff --git a/misc/examples/priority.c b/misc/examples/priority.c index 95dd3183..bf2e188a 100644 --- a/misc/examples/priority.c +++ b/misc/examples/priority.c @@ -3,12 +3,12 @@ #include <time.h> #include <stc/crand.h> -#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 <stc/cpque.h> -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 90c800aa..867a6c7b 100644 --- a/misc/examples/queue.c +++ b/misc/examples/queue.c @@ -1,7 +1,7 @@ #include <stc/crand.h> #include <stdio.h> -#define i_val int +#define i_key int #define i_tag i #include <stc/cqueue.h> diff --git a/misc/examples/random.c b/misc/examples/random.c index b4b437cf..63c5a306 100644 --- a/misc/examples/random.c +++ b/misc/examples/random.c @@ -2,7 +2,7 @@ #include <time.h> #include <stc/crand.h> -int main() +int main(void) { const size_t N = 10000000; const uint64_t seed = (uint64_t)time(NULL), range = 1000000; @@ -18,8 +18,8 @@ int main() sum += (uint32_t)crand_u64(&rng); } diff = clock() - before; - printf("full range\t\t: %f secs, %" c_ZI ", avg: %f\n", - (float)diff / CLOCKS_PER_SEC, N, (float)sum / (float)N); + printf("full range\t\t: %f secs, %d, avg: %f\n", + (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); crand_unif_t dist1 = crand_unif_init(0, range); rng = crand_init(seed); @@ -29,8 +29,8 @@ int main() sum += crand_unif(&rng, &dist1); // unbiased } diff = clock() - before; - printf("unbiased 0-%" PRIu64 "\t: %f secs, %" c_ZI ", avg: %f\n", - range, (float)diff/CLOCKS_PER_SEC, N, (float)sum / (float)N); + printf("unbiased 0-%" PRIu64 "\t: %f secs, %d, avg: %f\n", + range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); sum = 0; rng = crand_init(seed); @@ -39,7 +39,7 @@ int main() sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased } diff = clock() - before; - printf("biased 0-%" PRIu64 " \t: %f secs, %" c_ZI ", avg: %f\n", - range, (float)diff / CLOCKS_PER_SEC, N, (float)sum / (float)N); + printf("biased 0-%" PRIu64 " \t: %f secs, %d, avg: %f\n", + range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); } diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c index 01bcdc44..694ce12e 100644 --- a/misc/examples/rawptr_elements.c +++ b/misc/examples/rawptr_elements.c @@ -1,6 +1,6 @@ #include <stc/ccommon.h> #include <stdio.h> - +#define i_implement #include <stc/cstr.h> // Create cmap of cstr => long* @@ -16,7 +16,7 @@ // Alternatively, using cbox: #define i_type IBox -#define i_val long +#define i_key long #include <stc/cbox.h> // unique_ptr<long> alike. // cmap of cstr => IBox @@ -25,7 +25,7 @@ #define i_valboxed IBox // i_valboxed: use properties from IBox automatically #include <stc/cmap.h> -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 4efdcfeb..b12f7409 100644 --- a/misc/examples/read.c +++ b/misc/examples/read.c @@ -1,5 +1,7 @@ +#define i_implement #include <stc/cstr.h> -#define i_val_str +#include <stc/algo/raii.h> +#define i_key_str #include <stc/cvec.h> #include <errno.h> @@ -7,13 +9,13 @@ cvec_str read_file(const char* name) { cvec_str vec = cvec_str_init(); c_with (FILE* f = fopen(name, "r"), fclose(f)) - c_with (cstr line = cstr_NULL, cstr_drop(&line)) + c_with (cstr line = cstr_null, cstr_drop(&line)) while (cstr_getline(&line, f)) cvec_str_push(&vec, cstr_clone(line)); return vec; } -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/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 <stc/cregex.h> int main(int argc, char* argv[]) diff --git a/misc/examples/regex2.c b/misc/examples/regex2.c index 3133f7c2..a798b1a1 100644 --- a/misc/examples/regex2.c +++ b/misc/examples/regex2.c @@ -1,7 +1,7 @@ -#define i_extern +#define i_import #include <stc/cregex.h> -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])", @@ -26,7 +26,7 @@ int main() printf("\ninput: %s\n", s[i].input); c_formatch (j, &re, s[i].input) { - c_forrange (k, cregex_captures(&re)) + c_forrange (k, cregex_captures(&re) + 1) printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); } } diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c index def0ae7a..11426d2d 100644 --- a/misc/examples/regex_match.c +++ b/misc/examples/regex_match.c @@ -1,11 +1,12 @@ -#define i_extern +#define i_import #include <stc/cregex.h> +#define i_implement #include <stc/csview.h> -#define i_val float +#define i_key float #include <stc/cstack.h> -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." @@ -24,10 +25,10 @@ int main() cstack_float_push(&vec, (float)atof(i.match[0].str)); c_foreach (i, cstack_float, vec) - printf(" %g\n", *i.ref); + printf(" %g\n", (double)*i.ref); // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_R_STRIP); + 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 d3952f50..f1ea2711 100644 --- a/misc/examples/regex_replace.c +++ b/misc/examples/regex_replace.c @@ -1,4 +1,4 @@ -#define i_extern +#define i_import #include <stc/cregex.h> #include <stc/csview.h> @@ -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"; @@ -47,7 +47,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/examples/replace.c b/misc/examples/replace.c index cf5b45cb..59a56bf7 100644 --- a/misc/examples/replace.c +++ b/misc/examples/replace.c @@ -1,6 +1,7 @@ +#define i_implement #include <stc/cstr.h> -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 new file mode 100644 index 00000000..38defd0f --- /dev/null +++ b/misc/examples/scheduler.c @@ -0,0 +1,74 @@ +// https://www.youtube.com/watch?v=8sEe-4tig_A +#include <stdio.h> +#include <stc/calgo.h> + +struct Task { + int (*fn)(struct Task*); + int cco_state; + struct Scheduler* sched; +}; + +#define i_type Scheduler +#define i_key struct Task +#include <stc/cqueue.h> + +static bool schedule(Scheduler* sched) +{ + struct Task task = *Scheduler_front(sched); + Scheduler_pop(sched); + + if (!cco_done(&task)) + task.fn(&task); + + return !Scheduler_empty(sched); +} + +static int push_task(const struct Task* task) +{ + Scheduler_push(task->sched, *task); + return CCO_YIELD; +} + + +static int taskA(struct Task* task) +{ + cco_routine(task) { + puts("Hello, from task A"); + cco_yield_v(push_task(task)); + puts("A is back doing work"); + cco_yield_v(push_task(task)); + puts("A is back doing more work"); + cco_yield_v(push_task(task)); + puts("A is back doing even more work"); + } + return 0; +} + +static int taskB(struct Task* task) +{ + cco_routine(task) { + puts("Hello, from task B"); + cco_yield_v(push_task(task)); + puts("B is back doing work"); + cco_yield_v(push_task(task)); + puts("B is back doing more work"); + } + return 0; +} + +void Use(void) +{ + Scheduler scheduler = c_init(Scheduler, { + {.fn=taskA, .sched=&scheduler}, + {.fn=taskB, .sched=&scheduler}, + }); + + while (schedule(&scheduler)) {} + + Scheduler_drop(&scheduler); +} + +int main(void) +{ + Use(); +} diff --git a/misc/examples/shape.c b/misc/examples/shape.c index d7116039..bd4bdd5a 100644 --- a/misc/examples/shape.c +++ b/misc/examples/shape.c @@ -62,9 +62,9 @@ static void Triangle_draw(const Shape* shape) { const Triangle* self = DYN_CAST(Triangle, shape); printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n", - self->p[0].x, self->p[0].y, - self->p[1].x, self->p[1].y, - self->p[2].x, self->p[2].y); + (double)self->p[0].x, (double)self->p[0].y, + (double)self->p[1].x, (double)self->p[1].y, + (double)self->p[2].x, (double)self->p[2].y); } struct ShapeAPI Triangle_api = { @@ -76,7 +76,7 @@ struct ShapeAPI Triangle_api = { // ============================================================ #define i_type PointVec -#define i_val Point +#define i_key Point #include <stc/cstack.h> typedef struct { @@ -109,7 +109,7 @@ static void Polygon_draw(const Shape* shape) const Polygon* self = DYN_CAST(Polygon, shape); printf("Polygon :"); c_foreach (i, PointVec, self->points) - printf(" (%g,%g)", i.ref->x, i.ref->y); + printf(" (%g,%g)", (double)i.ref->x, (double)i.ref->y); puts(""); } @@ -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 <stc/cstack.h> @@ -137,7 +137,7 @@ int main(void) { Shapes shapes = {0}; - Triangle* tri1 = c_new(Triangle, Triangle_from((Point){5, 7}, (Point){12, 7}, (Point){12, 20})); + Triangle* tri1 = c_new(Triangle, Triangle_from(c_LITERAL(Point){5, 7}, c_LITERAL(Point){12, 7}, c_LITERAL(Point){12, 20})); Polygon* pol1 = c_new(Polygon, Polygon_init()); Polygon* pol2 = c_new(Polygon, Polygon_init()); diff --git a/misc/examples/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 <stc/cmap.h> -int main() { +int main(void) { { std::map<int, int> hist; hist.emplace(12, 100).first->second += 1; diff --git a/misc/examples/sorted_map.c b/misc/examples/sorted_map.c index ae9b45a4..89381554 100644 --- a/misc/examples/sorted_map.c +++ b/misc/examples/sorted_map.c @@ -1,11 +1,11 @@ // https://iq.opengenus.org/containers-cpp-stl/ +#include <stdio.h> #define i_key int #define i_val int #include <stc/csmap.h> -#include <stdio.h> -int main() +int main(void) { // empty map containers diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c index 2bc6fc07..ef7ed174 100644 --- a/misc/examples/splitstr.c +++ b/misc/examples/splitstr.c @@ -1,9 +1,10 @@ #include <stdio.h> -#define i_extern // cstr + utf8 functions +#define i_import // cstr + utf8 functions #include <stc/cregex.h> +#define i_implement #include <stc/csview.h> -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 70450e21..4f84b651 100644 --- a/misc/examples/sso_map.c +++ b/misc/examples/sso_map.c @@ -1,9 +1,10 @@ +#define i_implement #include <stc/cstr.h> #define i_key_str #define i_val_str #include <stc/cmap.h> -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 4b2dbcc8..687658df 100644 --- a/misc/examples/sso_substr.c +++ b/misc/examples/sso_substr.c @@ -1,7 +1,9 @@ +#define i_implement #include <stc/cstr.h> +#define i_implement #include <stc/csview.h> -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 c817e1ae..6297fb6f 100644 --- a/misc/examples/stack.c +++ b/misc/examples/stack.c @@ -3,14 +3,14 @@ #define i_tag i #define i_capacity 100 -#define i_val int +#define i_key int #include <stc/cstack.h> #define i_tag c -#define i_val char +#define i_key char #include <stc/cstack.h> -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 31a28e51..ac275da0 100644 --- a/misc/examples/sview_split.c +++ b/misc/examples/sview_split.c @@ -1,7 +1,9 @@ +#define i_implement #include <stc/cstr.h> +#define i_implement #include <stc/csview.h> -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 520bf012..9f2fcc1e 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -3,12 +3,21 @@ #include <stc/algo/coroutine.h> #include <stdio.h> +int gcd(int a, int b) { + while (b) { + int t = a % b; + a = b; + b = t; + } + return a; +} + void triples_vanilla(int n) { - for (int c = 5; n; ++c) { + for (int c = 5, i = 0; n; ++c) { for (int a = 1; a < c; ++a) { for (int b = a + 1; b < c; ++b) { - if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) { - printf("{%d, %d, %d}\n", a, b, c); + if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c && gcd(a, b) == 1) { + printf("%d: {%d, %d, %d}\n", ++i, a, b, c); if (--n == 0) goto done; } } @@ -18,47 +27,41 @@ void triples_vanilla(int n) { } struct triples { - int n; + int size, count; int a, b, c; int cco_state; }; -bool triples_next(struct triples* I) { - cco_begin(I); - for (I->c = 5; I->n; ++I->c) { - for (I->a = 1; I->a < I->c; ++I->a) { - for (I->b = I->a + 1; I->b < I->c; ++I->b) { - if ((int64_t)I->a*I->a + (int64_t)I->b*I->b == (int64_t)I->c*I->c) { - cco_yield(true); - if (--I->n == 0) cco_return; +int triples_coro(struct triples* t) { + cco_routine(t) { + t->count = 0; + for (t->c = 5; t->size; ++t->c) { + for (t->a = 1; t->a < t->c; ++t->a) { + for (t->b = t->a + 1; t->b < t->c; ++t->b) { + if ((int64_t)t->a*t->a + (int64_t)t->b*t->b == (int64_t)t->c*t->c) { + if (t->count++ == t->size) + cco_return; + cco_yield(); } } } } - cco_final: + cco_cleanup: puts("done"); - cco_end(false); -} - -int gcd(int a, int b) { - while (b) { - int t = a % b; - a = b; - b = t; } - return a; + return 0; } -int main() +int main(void) { puts("Vanilla triples:"); - triples_vanilla(6); + triples_vanilla(5); puts("\nCoroutine triples:"); - struct triples t = {INT32_MAX}; + struct triples t = {.size=INT32_MAX}; int n = 0; - while (triples_next(&t)) { + while (triples_coro(&t)) { if (gcd(t.a, t.b) > 1) continue; if (t.c < 100) diff --git a/misc/examples/unordered_set.c b/misc/examples/unordered_set.c index 61f9cc1f..dd899d78 100644 --- a/misc/examples/unordered_set.c +++ b/misc/examples/unordered_set.c @@ -1,10 +1,11 @@ // https://iq.opengenus.org/containers-cpp-stl/ // C program to demonstrate various function of stc cset +#define i_implement #include <stc/cstr.h> #define i_key_str #include <stc/cset.h> -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 3cde8701..1d54486f 100644 --- a/misc/examples/utf8replace_c.c +++ b/misc/examples/utf8replace_c.c @@ -1,6 +1,7 @@ +#define i_implement #include <stc/cstr.h> -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 abb909c3..d6125854 100644 --- a/misc/examples/vikings.c +++ b/misc/examples/vikings.c @@ -1,3 +1,4 @@ +#define i_implement #include <stc/cstr.h> typedef struct Viking { @@ -40,15 +41,15 @@ static inline RViking Viking_toraw(const Viking* vp) { #define i_val int // mapped type #include <stc/cmap.h> -int main() +int main(void) { Vikings vikings = {0}; - Vikings_emplace(&vikings, (RViking){"Einar", "Norway"}, 20); - Vikings_emplace(&vikings, (RViking){"Olaf", "Denmark"}, 24); - Vikings_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12); - Vikings_emplace(&vikings, (RViking){"Björn", "Sweden"}, 10); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Einar", "Norway"}, 20); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Olaf", "Denmark"}, 24); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Harald", "Iceland"}, 12); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Björn", "Sweden"}, 10); - Vikings_value* v = Vikings_get_mut(&vikings, (RViking){"Einar", "Norway"}); + Vikings_value* v = Vikings_get_mut(&vikings, c_LITERAL(RViking){"Einar", "Norway"}); v->second += 3; // add 3 hp points to Einar c_forpair (vk, hp, Vikings, vikings) { diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c index aa4b2a65..4e192de6 100644 --- a/misc/tests/cregex_test.c +++ b/misc/tests/cregex_test.c @@ -1,6 +1,7 @@ -#define i_extern +#define i_import #include <stc/cregex.h> #include <stc/csview.h> +#include <stc/algo/raii.h> #include "ctest.h" #define M_START(m) ((m).str - inp) @@ -14,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 @@ -192,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); } } @@ -208,7 +209,7 @@ CTEST(cregex, captures_len) { c_auto (cregex, re) { re = cregex_from("(ab(cd))(ef)"); - ASSERT_EQ(cregex_captures(&re), 4); + ASSERT_EQ(cregex_captures(&re), 3); } } @@ -217,7 +218,7 @@ CTEST(cregex, captures_cap) const char* inp; c_auto (cregex, re) { re = cregex_from("(ab)((cd)+)"); - ASSERT_EQ(cregex_captures(&re), 4); + ASSERT_EQ(cregex_captures(&re), 3); csview cap[5]; ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap), CREG_OK); @@ -272,14 +273,14 @@ CTEST(cregex, replace) // Compile RE separately re = cregex_from(pattern); - ASSERT_EQ(cregex_captures(&re), 4); + ASSERT_EQ(cregex_captures(&re), 3); // European date format. cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); 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/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index 83ac762b..d7ca9b64 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -1,5 +1,6 @@ #include <stdio.h> #include <stc/cspan.h> +#include <stc/algo/raii.h> #include "ctest.h" using_cspan3(intspan, int); @@ -9,11 +10,11 @@ CTEST(cspan, subdim) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; intspan3 m = cspan_md(array, 2, 2, 3); - for (size_t i = 0; i < m.shape[0]; ++i) { + for (int i = 0; i < m.shape[0]; ++i) { intspan2 sub_i = cspan_submd3(&m, i); - for (size_t j = 0; j < m.shape[1]; ++j) { + for (int j = 0; j < m.shape[1]; ++j) { intspan sub_i_j = cspan_submd2(&sub_i, j); - for (size_t k = 0; k < m.shape[2]; ++k) { + for (int k = 0; k < m.shape[2]; ++k) { ASSERT_EQ(*cspan_at(&sub_i_j, k), *cspan_at(&m, i, j, k)); } } @@ -24,18 +25,18 @@ CTEST(cspan, slice) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; intspan2 m1 = cspan_md(array, 3, 4); - size_t sum1 = 0; - for (size_t i = 0; i < m1.shape[0]; ++i) { - for (size_t j = 0; j < m1.shape[1]; ++j) { + int sum1 = 0; + for (int i = 0; i < m1.shape[0]; ++i) { + for (int j = 0; j < m1.shape[1]; ++j) { sum1 += *cspan_at(&m1, i, j); } } intspan2 m2 = cspan_slice(intspan2, &m1, {c_ALL}, {2,4}); - size_t sum2 = 0; - for (size_t i = 0; i < m2.shape[0]; ++i) { - for (size_t j = 0; j < m2.shape[1]; ++j) { + int sum2 = 0; + for (int i = 0; i < m2.shape[0]; ++i) { + for (int j = 0; j < m2.shape[1]; ++j) { sum2 += *cspan_at(&m2, i, j); } } @@ -43,7 +44,7 @@ CTEST(cspan, slice) { ASSERT_EQ(45, sum2); } -#define i_val int +#define i_key int #include <stc/cstack.h> CTEST(cspan, slice2) { @@ -55,10 +56,10 @@ CTEST(cspan, slice2) { intspan3 ms3 = cspan_md(stack.data, 10, 20, 30); ms3 = cspan_slice(intspan3, &ms3, {1,4}, {3,7}, {20,24}); - size_t sum = 0; - for (size_t i = 0; i < ms3.shape[0]; ++i) { - for (size_t j = 0; j < ms3.shape[1]; ++j) { - for (size_t k = 0; k < ms3.shape[2]; ++k) { + int sum = 0; + for (int i = 0; i < ms3.shape[0]; ++i) { + for (int j = 0; j < ms3.shape[1]; ++j) { + for (int k = 0; k < ms3.shape[2]; ++k) { sum += *cspan_at(&ms3, i, j, k); } } @@ -74,7 +75,7 @@ CTEST(cspan, slice2) { #define i_type Tiles -#define i_val intspan3 +#define i_key intspan3 #include <stc/cstack.h> CTEST_FIXTURE(cspan_cube) { diff --git a/src/cregex.c b/src/cregex.c index 0688d9e1..ac94a5dd 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -25,9 +25,24 @@ THE SOFTWARE. */ #ifndef CREGEX_C_INCLUDED #define CREGEX_C_INCLUDED -#include <stc/cstr.h> -#include <stc/cregex.h> // header only + #include <setjmp.h> +#ifdef i_import +# define _i_import +#endif +#ifndef CREGEX_H_INCLUDED +# include "../include/stc/cregex.h" +#endif +#ifdef _i_import +# include "utf8code.c" +#endif +#ifdef _i_import +# define i_implement +#else +# undef i_implement +#endif +#undef _i_import +#include "../include/stc/cstr.h" typedef uint32_t _Rune; /* Utf8 code point */ typedef int32_t _Token; @@ -842,20 +857,21 @@ _bldcclass(_Parser *par) static _Reprog* -_regcomp1(_Reprog *progp, _Parser *par, const char *s, int cflags) +_regcomp1(_Reprog *pp, _Parser *par, const char *s, int cflags) { _Token token; /* get memory for the program. estimated max usage */ par->instcap = 5U + 6*strlen(s); - _Reprog* pp = (_Reprog *)c_realloc(progp, sizeof(_Reprog) + par->instcap*sizeof(_Reinst)); - if (pp == NULL) { + _Reprog* old_pp = pp; + pp = (_Reprog *)c_realloc(pp, sizeof(_Reprog) + par->instcap*sizeof(_Reinst)); + if (! pp) { + c_free(old_pp); par->error = CREG_OUTOFMEMORY; - c_free(progp); return NULL; } - pp->flags.icase = (cflags & CREG_C_ICASE) != 0; - 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; @@ -928,14 +944,14 @@ _runematch(_Rune s, _Rune r) case ASC_LO: inv = 1; case ASC_lo: return inv ^ (islower((int)r) != 0); case ASC_UP: inv = 1; case ASC_up: return inv ^ (isupper((int)r) != 0); case ASC_XD: inv = 1; case ASC_xd: return inv ^ (isxdigit((int)r) != 0); - case UTF_AN: inv = 1; case UTF_an: return inv ^ utf8_isalnum(r); - case UTF_BL: inv = 1; case UTF_bl: return inv ^ utf8_isblank(r); - case UTF_SP: inv = 1; case UTF_sp: return inv ^ utf8_isspace(r); - case UTF_LL: inv = 1; case UTF_ll: return inv ^ utf8_islower(r); - case UTF_LU: inv = 1; case UTF_lu: return inv ^ utf8_isupper(r); - case UTF_LC: inv = 1; case UTF_lc: return inv ^ utf8_iscased(r); - case UTF_AL: inv = 1; case UTF_al: return inv ^ utf8_isalpha(r); - case UTF_WR: inv = 1; case UTF_wr: return inv ^ utf8_isword(r); + case UTF_AN: inv = 1; case UTF_an: return inv ^ (int)utf8_isalnum(r); + case UTF_BL: inv = 1; case UTF_bl: return inv ^ (int)utf8_isblank(r); + case UTF_SP: inv = 1; case UTF_sp: return inv ^ (int)utf8_isspace(r); + case UTF_LL: inv = 1; case UTF_ll: return inv ^ (int)utf8_islower(r); + case UTF_LU: inv = 1; case UTF_lu: return inv ^ (int)utf8_isupper(r); + case UTF_LC: inv = 1; case UTF_lc: return inv ^ (int)utf8_iscased(r); + case UTF_AL: inv = 1; case UTF_al: return inv ^ (int)utf8_isalpha(r); + case UTF_WR: inv = 1; case UTF_wr: return inv ^ (int)utf8_isword(r); case UTF_cc: case UTF_CC: case UTF_lt: case UTF_LT: case UTF_nd: case UTF_ND: @@ -956,7 +972,7 @@ _runematch(_Rune s, _Rune r) case UTF_latin: case UTF_LATIN: n = (int)s - UTF_GRP; inv = n & 1; - return inv ^ utf8_isgroup(n / 2, r); + return inv ^ (int)utf8_isgroup(n / 2, r); } return s == r; } @@ -1100,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); @@ -1168,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; } @@ -1204,7 +1220,7 @@ _build_subst(const char* replace, int nmatch, const csview match[], cstr_buf buf = cstr_buffer(subst); intptr_t len = 0, cap = buf.cap; char* dst = buf.data; - cstr mstr = cstr_NULL; + cstr mstr = cstr_null; while (*replace != '\0') { if (*replace == '$') { @@ -1216,11 +1232,11 @@ _build_subst(const char* replace, int nmatch, const csview match[], g = arg - '0'; if (replace[1] >= '0' && replace[1] <= '9' && replace[2] == ';') { g = g*10 + (replace[1] - '0'); replace += 2; } - if (g < (int)nmatch) { + if (g < nmatch) { csview m = mfun && mfun(g, match[g], &mstr) ? cstr_sv(&mstr) : match[g]; if (len + m.size > cap) - dst = cstr_reserve(subst, cap = cap*3/2 + m.size); - for (int i = 0; i < (int)m.size; ++i) + dst = cstr_reserve(subst, cap += cap/2 + m.size); + for (int i = 0; i < m.size; ++i) dst[len++] = m.str[i]; } ++replace; @@ -1229,7 +1245,7 @@ _build_subst(const char* replace, int nmatch, const csview match[], } } if (len == cap) - dst = cstr_reserve(subst, cap = cap*3/2 + 4); + dst = cstr_reserve(subst, cap += cap/2 + 4); dst[len++] = *replace++; } cstr_drop(&mstr); @@ -1250,12 +1266,12 @@ cregex_compile_3(cregex *self, const char* pattern, int cflags) { int cregex_captures(const cregex* self) { - return self->prog ? 1 + self->prog->nsubids : 0; + return self->prog ? self->prog->nsubids : 0; } int cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) { - int res = _regexec(re->prog, input, cregex_captures(re), match, mflags); + int res = _regexec(re->prog, input, cregex_captures(re) + 1, match, mflags); switch (res) { case 1: return CREG_OK; case 0: return CREG_NOMATCH; @@ -1277,12 +1293,12 @@ cregex_find_pattern_4(const char* pattern, const char* input, cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count, bool (*mfun)(int, csview, cstr*), int rflags) { - cstr out = cstr_NULL; - cstr subst = cstr_NULL; + cstr out = cstr_null; + cstr subst = cstr_null; csview match[CREG_MAX_CAPTURES]; - int nmatch = cregex_captures(re); + 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); diff --git a/src/libstc.c b/src/libstc.c new file mode 100644 index 00000000..7b49540a --- /dev/null +++ b/src/libstc.c @@ -0,0 +1,8 @@ +#define i_import
+#include "../include/stc/cregex.h" /* cstr. utf8, and cregex */
+#define i_implement
+#include "../include/stc/csview.h"
+#if __STDC_VERSION__ >= 201112L
+# define i_implement
+# include "../include/c11/fmt.h"
+#endif
diff --git a/src/singleupdate.sh b/src/singleupdate.sh index d9a16568..8a621e57 100644 --- a/src/singleupdate.sh +++ b/src/singleupdate.sh @@ -1,27 +1,27 @@ -d=$(git rev-parse --show-toplevel)
-mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc
-python singleheader.py $d/include/c11/print.h > $d/../stcsingle/c11/print.h
-python singleheader.py $d/include/stc/calgo.h > $d/../stcsingle/stc/calgo.h
-python singleheader.py $d/include/stc/carc.h > $d/../stcsingle/stc/carc.h
-python singleheader.py $d/include/stc/cbits.h > $d/../stcsingle/stc/cbits.h
-python singleheader.py $d/include/stc/cbox.h > $d/../stcsingle/stc/cbox.h
-python singleheader.py $d/include/stc/ccommon.h > $d/../stcsingle/stc/ccommon.h
-python singleheader.py $d/include/stc/cdeq.h > $d/../stcsingle/stc/cdeq.h
-python singleheader.py $d/include/stc/clist.h > $d/../stcsingle/stc/clist.h
-python singleheader.py $d/include/stc/cmap.h > $d/../stcsingle/stc/cmap.h
-python singleheader.py $d/include/stc/coption.h > $d/../stcsingle/stc/coption.h
-python singleheader.py $d/include/stc/cpque.h > $d/../stcsingle/stc/cpque.h
-python singleheader.py $d/include/stc/cqueue.h > $d/../stcsingle/stc/cqueue.h
-python singleheader.py $d/include/stc/crand.h > $d/../stcsingle/stc/crand.h
-python singleheader.py $d/include/stc/cregex.h > $d/../stcsingle/stc/cregex.h
-python singleheader.py $d/include/stc/cset.h > $d/../stcsingle/stc/cset.h
-python singleheader.py $d/include/stc/csmap.h > $d/../stcsingle/stc/csmap.h
-python singleheader.py $d/include/stc/cspan.h > $d/../stcsingle/stc/cspan.h
-python singleheader.py $d/include/stc/csset.h > $d/../stcsingle/stc/csset.h
-python singleheader.py $d/include/stc/cstack.h > $d/../stcsingle/stc/cstack.h
-python singleheader.py $d/include/stc/cstr.h > $d/../stcsingle/stc/cstr.h
-python singleheader.py $d/include/stc/csview.h > $d/../stcsingle/stc/csview.h
-python singleheader.py $d/include/stc/cvec.h > $d/../stcsingle/stc/cvec.h
-python singleheader.py $d/include/stc/extend.h > $d/../stcsingle/stc/extend.h
-python singleheader.py $d/include/stc/forward.h > $d/../stcsingle/stc/forward.h
-echo "stcsingle headers updated"
\ No newline at end of file +d=$(git rev-parse --show-toplevel) +mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc +python singleheader.py $d/include/c11/fmt.h > $d/../stcsingle/c11/fmt.h +python singleheader.py $d/include/stc/calgo.h > $d/../stcsingle/stc/calgo.h +python singleheader.py $d/include/stc/carc.h > $d/../stcsingle/stc/carc.h +python singleheader.py $d/include/stc/cbits.h > $d/../stcsingle/stc/cbits.h +python singleheader.py $d/include/stc/cbox.h > $d/../stcsingle/stc/cbox.h +python singleheader.py $d/include/stc/ccommon.h > $d/../stcsingle/stc/ccommon.h +python singleheader.py $d/include/stc/cdeq.h > $d/../stcsingle/stc/cdeq.h +python singleheader.py $d/include/stc/clist.h > $d/../stcsingle/stc/clist.h +python singleheader.py $d/include/stc/cmap.h > $d/../stcsingle/stc/cmap.h +python singleheader.py $d/include/stc/coption.h > $d/../stcsingle/stc/coption.h +python singleheader.py $d/include/stc/cpque.h > $d/../stcsingle/stc/cpque.h +python singleheader.py $d/include/stc/cqueue.h > $d/../stcsingle/stc/cqueue.h +python singleheader.py $d/include/stc/crand.h > $d/../stcsingle/stc/crand.h +python singleheader.py $d/include/stc/cregex.h > $d/../stcsingle/stc/cregex.h +python singleheader.py $d/include/stc/cset.h > $d/../stcsingle/stc/cset.h +python singleheader.py $d/include/stc/csmap.h > $d/../stcsingle/stc/csmap.h +python singleheader.py $d/include/stc/cspan.h > $d/../stcsingle/stc/cspan.h +python singleheader.py $d/include/stc/csset.h > $d/../stcsingle/stc/csset.h +python singleheader.py $d/include/stc/cstack.h > $d/../stcsingle/stc/cstack.h +python singleheader.py $d/include/stc/cstr.h > $d/../stcsingle/stc/cstr.h +python singleheader.py $d/include/stc/csview.h > $d/../stcsingle/stc/csview.h +python singleheader.py $d/include/stc/cvec.h > $d/../stcsingle/stc/cvec.h +python singleheader.py $d/include/stc/extend.h > $d/../stcsingle/stc/extend.h +python singleheader.py $d/include/stc/forward.h > $d/../stcsingle/stc/forward.h +echo "$d/../stcsingle headers updated" diff --git a/src/utf8code.c b/src/utf8code.c index 496f5eef..4abf10ea 100644 --- a/src/utf8code.c +++ b/src/utf8code.c @@ -1,6 +1,9 @@ #ifndef UTF8_C_INCLUDED #define UTF8_C_INCLUDED -#include <stc/utf8.h> // header only + +#ifndef UTF8_H_INCLUDED +#include "../include/stc/utf8.h" /* header only */ +#endif #include "utf8tabs.inc" const uint8_t utf8_dtab[] = { @@ -458,28 +461,31 @@ static const URange16 Latin_range16[] = { #define UNI_ENTRY(Code) \ { Code##_range16, sizeof(Code##_range16)/sizeof(URange16) } -#ifndef __cplusplus +#ifdef __cplusplus +#define _e_arg(k, v) v +#else +#define _e_arg(k, v) [k] = v static #endif const UGroup _utf8_unicode_groups[U8G_SIZE] = { - [U8G_Cc] = UNI_ENTRY(Cc), - [U8G_Lt] = UNI_ENTRY(Lt), - [U8G_Nd] = UNI_ENTRY(Nd), - [U8G_Nl] = UNI_ENTRY(Nl), - [U8G_Pc] = UNI_ENTRY(Pc), - [U8G_Pd] = UNI_ENTRY(Pd), - [U8G_Pf] = UNI_ENTRY(Pf), - [U8G_Pi] = UNI_ENTRY(Pi), - [U8G_Sc] = UNI_ENTRY(Sc), - [U8G_Zl] = UNI_ENTRY(Zl), - [U8G_Zp] = UNI_ENTRY(Zp), - [U8G_Zs] = UNI_ENTRY(Zs), - [U8G_Arabic] = UNI_ENTRY(Arabic), - [U8G_Cyrillic] = UNI_ENTRY(Cyrillic), - [U8G_Devanagari] = UNI_ENTRY(Devanagari), - [U8G_Greek] = UNI_ENTRY(Greek), - [U8G_Han] = UNI_ENTRY(Han), - [U8G_Latin] = UNI_ENTRY(Latin), + _e_arg(U8G_Cc, UNI_ENTRY(Cc)), + _e_arg(U8G_Lt, UNI_ENTRY(Lt)), + _e_arg(U8G_Nd, UNI_ENTRY(Nd)), + _e_arg(U8G_Nl, UNI_ENTRY(Nl)), + _e_arg(U8G_Pc, UNI_ENTRY(Pc)), + _e_arg(U8G_Pd, UNI_ENTRY(Pd)), + _e_arg(U8G_Pf, UNI_ENTRY(Pf)), + _e_arg(U8G_Pi, UNI_ENTRY(Pi)), + _e_arg(U8G_Sc, UNI_ENTRY(Sc)), + _e_arg(U8G_Zl, UNI_ENTRY(Zl)), + _e_arg(U8G_Zp, UNI_ENTRY(Zp)), + _e_arg(U8G_Zs, UNI_ENTRY(Zs)), + _e_arg(U8G_Arabic, UNI_ENTRY(Arabic)), + _e_arg(U8G_Cyrillic, UNI_ENTRY(Cyrillic)), + _e_arg(U8G_Devanagari, UNI_ENTRY(Devanagari)), + _e_arg(U8G_Greek, UNI_ENTRY(Greek)), + _e_arg(U8G_Han, UNI_ENTRY(Han)), + _e_arg(U8G_Latin, UNI_ENTRY(Latin)), }; #endif |
