summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md65
-rw-r--r--docs/algorithm_api.md (renamed from docs/ccommon_api.md)158
-rw-r--r--docs/carc_api.md24
-rw-r--r--docs/cbox_api.md29
-rw-r--r--docs/cdeq_api.md23
-rw-r--r--docs/clist_api.md21
-rw-r--r--docs/cmap_api.md39
-rw-r--r--docs/coroutine_api.md292
-rw-r--r--docs/cpque_api.md22
-rw-r--r--docs/cqueue_api.md16
-rw-r--r--docs/crandom_api.md47
-rw-r--r--docs/cset_api.md26
-rw-r--r--docs/csmap_api.md38
-rw-r--r--docs/cspan_api.md25
-rw-r--r--docs/csset_api.md18
-rw-r--r--docs/cstack_api.md16
-rw-r--r--docs/cvec_api.md23
-rw-r--r--docs/pics/Figure_1.pngbin0 -> 58425 bytes
-rw-r--r--docs/pics/coroutine.jpgbin0 -> 81539 bytes
-rw-r--r--include/stc/algo/crange.h13
-rw-r--r--include/stc/algo/filter.h16
-rw-r--r--include/stc/algo/sort.h2
-rw-r--r--include/stc/algorithm.h (renamed from include/stc/calgo.h)1
-rw-r--r--include/stc/ccommon.h6
-rw-r--r--include/stc/cdeq.h19
-rw-r--r--include/stc/coroutine.h (renamed from include/stc/algo/coroutine.h)100
-rw-r--r--include/stc/cqueue.h206
-rw-r--r--include/stc/crand.h43
-rw-r--r--include/stc/cspan.h12
-rw-r--r--include/stc/cstr.h34
-rw-r--r--include/stc/priv/cqueue_hdr.h117
-rw-r--r--include/stc/priv/cqueue_imp.h129
-rw-r--r--include/stc/priv/template.h8
-rw-r--r--include/stc/priv/template2.h2
-rw-r--r--misc/benchmarks/plotbench/cvec_benchmark.cpp6
-rw-r--r--misc/benchmarks/plotbench/plot.py2
-rw-r--r--misc/benchmarks/plotbench/run_all.bat2
-rw-r--r--misc/benchmarks/plotbench/run_clang.sh2
-rw-r--r--misc/benchmarks/plotbench/run_gcc.sh2
-rw-r--r--misc/benchmarks/plotbench/run_vc.bat4
-rw-r--r--misc/benchmarks/various/csort_bench.c2
-rw-r--r--misc/examples/algorithms/forfilter.c (renamed from misc/examples/forfilter.c)7
-rw-r--r--misc/examples/algorithms/forloops.c (renamed from misc/examples/forloops.c)134
-rw-r--r--misc/examples/algorithms/random.c (renamed from misc/examples/random.c)20
-rw-r--r--misc/examples/algorithms/shape.c (renamed from misc/examples/shape.c)0
-rw-r--r--misc/examples/algorithms/shape.cpp (renamed from misc/examples/shape.cpp)0
-rw-r--r--misc/examples/bitsets/bits.c (renamed from misc/examples/bits.c)0
-rw-r--r--misc/examples/bitsets/bits2.c (renamed from misc/examples/bits2.c)0
-rw-r--r--misc/examples/bitsets/prime.c (renamed from misc/examples/prime.c)13
-rw-r--r--misc/examples/coroutines/cointerleave.c (renamed from misc/examples/cointerleave.c)4
-rw-r--r--misc/examples/coroutines/coread.c (renamed from misc/examples/coread.c)4
-rw-r--r--misc/examples/coroutines/coroutines.c (renamed from misc/examples/coroutines.c)10
-rw-r--r--misc/examples/coroutines/cotasks1.c100
-rw-r--r--misc/examples/coroutines/cotasks2.c98
-rw-r--r--misc/examples/coroutines/dining_philosophers.c (renamed from misc/examples/dining_philosophers.c)2
-rw-r--r--misc/examples/coroutines/filetask.c80
-rw-r--r--misc/examples/coroutines/generator.c (renamed from misc/examples/generator.c)2
-rw-r--r--misc/examples/coroutines/scheduler.c (renamed from misc/examples/scheduler.c)2
-rw-r--r--misc/examples/coroutines/triples.c (renamed from misc/examples/triples.c)53
-rw-r--r--misc/examples/hashmaps/birthday.c (renamed from misc/examples/birthday.c)0
-rw-r--r--misc/examples/hashmaps/books.c (renamed from misc/examples/books.c)0
-rw-r--r--misc/examples/hashmaps/hashmap.c (renamed from misc/examples/hashmap.c)0
-rw-r--r--misc/examples/hashmaps/new_map.c (renamed from misc/examples/new_map.c)0
-rw-r--r--misc/examples/hashmaps/phonebook.c (renamed from misc/examples/phonebook.c)0
-rw-r--r--misc/examples/hashmaps/unordered_set.c (renamed from misc/examples/unordered_set.c)0
-rw-r--r--misc/examples/hashmaps/vikings.c (renamed from misc/examples/vikings.c)0
-rw-r--r--misc/examples/linkedlists/intrusive.c (renamed from misc/examples/intrusive.c)2
-rw-r--r--misc/examples/linkedlists/list.c (renamed from misc/examples/list.c)8
-rw-r--r--misc/examples/linkedlists/list_erase.c (renamed from misc/examples/list_erase.c)0
-rw-r--r--misc/examples/linkedlists/list_splice.c (renamed from misc/examples/list_splice.c)0
-rw-r--r--misc/examples/linkedlists/new_list.c (renamed from misc/examples/new_list.c)2
-rwxr-xr-xmisc/examples/make.sh18
-rw-r--r--misc/examples/mixed/astar.c (renamed from misc/examples/astar.c)0
-rw-r--r--misc/examples/mixed/complex.c (renamed from misc/examples/complex.c)0
-rw-r--r--misc/examples/mixed/convert.c (renamed from misc/examples/convert.c)0
-rw-r--r--misc/examples/mixed/demos.c (renamed from misc/examples/demos.c)2
-rw-r--r--misc/examples/mixed/inits.c (renamed from misc/examples/inits.c)0
-rw-r--r--misc/examples/mixed/read.c (renamed from misc/examples/read.c)4
-rw-r--r--misc/examples/priorityqueues/functor.c (renamed from misc/examples/functor.c)0
-rw-r--r--misc/examples/priorityqueues/new_pque.c (renamed from misc/examples/new_pque.c)0
-rw-r--r--misc/examples/priorityqueues/priority.c (renamed from misc/examples/priority.c)6
-rw-r--r--misc/examples/queues/new_queue.c (renamed from misc/examples/new_queue.c)6
-rw-r--r--misc/examples/queues/queue.c (renamed from misc/examples/queue.c)10
-rw-r--r--misc/examples/rawptr_elements.c59
-rw-r--r--misc/examples/regularexpressions/regex1.c (renamed from misc/examples/regex1.c)0
-rw-r--r--misc/examples/regularexpressions/regex2.c (renamed from misc/examples/regex2.c)0
-rw-r--r--misc/examples/regularexpressions/regex_match.c (renamed from misc/examples/regex_match.c)0
-rw-r--r--misc/examples/regularexpressions/regex_replace.c (renamed from misc/examples/regex_replace.c)0
-rw-r--r--misc/examples/sidebyside.cpp57
-rw-r--r--misc/examples/smartpointers/arc_containers.c (renamed from misc/examples/arc_containers.c)0
-rw-r--r--misc/examples/smartpointers/arc_demo.c (renamed from misc/examples/arc_demo.c)2
-rw-r--r--misc/examples/smartpointers/arcvec_erase.c (renamed from misc/examples/arcvec_erase.c)2
-rw-r--r--misc/examples/smartpointers/box.c (renamed from misc/examples/box.c)0
-rw-r--r--misc/examples/smartpointers/box2.c (renamed from misc/examples/box2.c)0
-rw-r--r--misc/examples/smartpointers/map_box.c34
-rw-r--r--misc/examples/smartpointers/map_ptr.c34
-rw-r--r--misc/examples/smartpointers/music_arc.c (renamed from misc/examples/music_arc.c)12
-rw-r--r--misc/examples/smartpointers/new_sptr.c (renamed from misc/examples/new_sptr.c)2
-rw-r--r--misc/examples/smartpointers/person_arc.c (renamed from misc/examples/person_arc.c)0
-rw-r--r--misc/examples/sortedmaps/csmap_erase.c (renamed from misc/examples/csmap_erase.c)0
-rw-r--r--misc/examples/sortedmaps/csmap_find.c (renamed from misc/examples/csmap_find.c)0
-rw-r--r--misc/examples/sortedmaps/csmap_insert.c (renamed from misc/examples/csmap_insert.c)0
-rw-r--r--misc/examples/sortedmaps/csset_erase.c (renamed from misc/examples/csset_erase.c)0
-rw-r--r--misc/examples/sortedmaps/gauss2.c (renamed from misc/examples/gauss2.c)4
-rw-r--r--misc/examples/sortedmaps/listmap.c (renamed from misc/examples/mmap.c)0
-rw-r--r--misc/examples/sortedmaps/mapmap.c (renamed from misc/examples/mapmap.c)0
-rw-r--r--misc/examples/sortedmaps/multimap.c (renamed from misc/examples/multimap.c)0
-rw-r--r--misc/examples/sortedmaps/new_smap.c (renamed from misc/examples/new_smap.c)0
-rw-r--r--misc/examples/sortedmaps/sorted_map.c (renamed from misc/examples/sorted_map.c)0
-rw-r--r--misc/examples/spans/mdspan.c51
-rw-r--r--misc/examples/spans/multidim.c (renamed from misc/examples/multidim.c)0
-rw-r--r--misc/examples/spans/printspan.c (renamed from misc/examples/printspan.c)0
-rw-r--r--misc/examples/strings/cstr_match.c (renamed from misc/examples/cstr_match.c)0
-rw-r--r--misc/examples/strings/replace.c (renamed from misc/examples/replace.c)0
-rw-r--r--misc/examples/strings/splitstr.c (renamed from misc/examples/splitstr.c)0
-rw-r--r--misc/examples/strings/sso_map.c (renamed from misc/examples/sso_map.c)0
-rw-r--r--misc/examples/strings/sso_substr.c (renamed from misc/examples/sso_substr.c)0
-rw-r--r--misc/examples/strings/sview_split.c (renamed from misc/examples/sview_split.c)0
-rw-r--r--misc/examples/strings/utf8replace_c.c (renamed from misc/examples/utf8replace_c.c)0
-rw-r--r--misc/examples/strings/utf8replace_rs.rs (renamed from misc/examples/utf8replace_rs.rs)0
-rw-r--r--misc/examples/vectors/lower_bound.c (renamed from misc/examples/lower_bound.c)2
-rw-r--r--misc/examples/vectors/new_vec.c (renamed from misc/examples/new_vec.c)0
-rw-r--r--misc/examples/vectors/stack.c (renamed from misc/examples/stack.c)0
-rw-r--r--src/singleheader.py18
-rw-r--r--src/singleupdate.sh53
125 files changed, 1536 insertions, 991 deletions
diff --git a/README.md b/README.md
index b7e06790..55c77ca4 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@
STC - Smart Template Containers
===============================
-### [Version 4.3 RC3](#version-history)
-
+### [Version 4.3 Released](#version-history)
+- See details for breaking changes.
---
Description
-----------
@@ -33,10 +33,10 @@ Containers
Algorithms
----------
-- [***Ranged for-loops*** - c_foreach, c_forpair, c_forlist](docs/ccommon_api.md#ranged-for-loops)
-- [***Range algorithms*** - c_forrange, crange, c_forfilter](docs/ccommon_api.md#range-algorithms)
-- [***Generic algorithms*** - c_init, c_find_if, c_erase_if, csort, etc.](docs/ccommon_api.md#generic-algorithms)
-- [***Coroutines*** - Simon Tatham's coroutines done right.](docs/ccommon_api.md#coroutines)
+- [***Ranged for-loops*** - c_foreach, c_forpair, c_forlist](docs/algorithm_api.md#ranged-for-loops)
+- [***Range algorithms*** - c_forrange, crange, c_forfilter](docs/algorithm_api.md#range-algorithms)
+- [***Generic algorithms*** - c_init, c_find_if, c_erase_if, csort, etc.](docs/algorithm_api.md#generic-algorithms)
+- [***Coroutines*** - ergonomic portable coroutines](docs/coroutine_api.md)
- [***Regular expressions*** - Rob Pike's Plan 9 regexp modernized!](docs/cregex_api.md)
- [***Random numbers*** - a very fast *PRNG* based on *SFC64*](docs/crandom_api.md)
- [***Command line argument parser*** - similar to *getopt()*](docs/coption_api.md)
@@ -61,12 +61,11 @@ List of contents
---
## Highlights
-- **No boilerplate code** - Specify only the required template parameters, e.g. ***cmp***- and/or ***clone***-, ***drop***- functions, and leave the rest as defaults.
+- **Minimal boilerplate code** - Specify only the required template parameters, and leave the rest as defaults.
- **Fully type safe** - Because of templating, it avoids error-prone casting of container types and elements back and forth from the containers.
-- **User friendly** - Just include the headers and you are good. The API and functionality is very close to c++ STL and is fully listed in the docs.
-- **Unparalleled performance** - Maps and sets are much faster than the C++ STL containers, the remaining are similar in speed.
+- **High performance** - Unordered maps and sets, queues and deques are significantly faster than the C++ STL containers, the remaining are similar or close to STL in speed (See graph below).
- **Fully memory managed** - Containers destructs keys/values via default or user supplied drop function. They may be cloned if element types are clonable. Also, smart pointers are supported and can be stored in containers. See [***carc***](docs/carc_api.md) and [***cbox***](docs/cbox_api.md).
-- **Uniform, easy-to-learn API** - Intuitive method/type names and uniform usage across the various containers.
+- **Uniform, easy-to-learn API** - Just include the headers and you are good. The API and functionality resembles c++ STL and is fully listed in the docs. Intuitive method/type names and uniform usage across the various containers.
- **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed for comparison and calculation is asking for trouble. STC only uses signed numbers in the API for this reason.
- **Small footprint** - Small source code and generated executables. The executable from the example below using *four different* container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux.
- **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section.
@@ -95,17 +94,17 @@ So instead of calling e.g. `cvec_str_push(&vec, cstr_from("Hello"))`, you may ca
same element access syntax. E.g.:
- `c_foreach (it, MyInts, myints) *it.ref += 42;` works for any container defined as
`MyInts` with `int` elements.
- - `c_foreach (it, MyInts, it1, it2) *it.ref += 42;` iterates from `it1` up to `it2`.
+ - `c_foreach (it, MyInts, it1, it2) *it.ref += 42;` iterates from `it1` up to not including `it2`.
---
## Performance
STC is a fast and memory efficient library, and code compiles fast:
-![Benchmark](misc/benchmarks/pics/benchmark.gif)
+![Benchmark](docs/pics/Figure_1.png)
Benchmark notes:
-- The barchart shows average test times over three platforms: Mingw64 10.30, Win-Clang 12, VC19. CPU: Ryzen 7 2700X CPU @4Ghz.
+- The barchart shows average test times over three compilers: **Mingw64 13.1.0, Win-Clang 16.0.5, VC-19-36**. CPU: **Ryzen 7 5700X**.
- Containers uses value types `uint64_t` and pairs of `uint64_t` for the maps.
- Black bars indicates performance variation between various platforms/compilers.
- Iterations are repeated 4 times over n elements.
@@ -237,7 +236,7 @@ int main(void)
```
This example uses four different container types:
-[ [Run this code](https://godbolt.org/z/x5YKeMrEh) ]
+[ [Run this code](https://godbolt.org/z/qor16Gf6j) ]
```c
#include <stdio.h>
@@ -252,7 +251,7 @@ struct Point { float x, y; };
#include <stc/cvec.h> // cvec_pnt: vector of struct Point
#define i_key int
-#define i_native_cmp // enable sort/search. Use native `<` and `==` operators
+#define i_cmp_native // enable sort/search. Use native `<` and `==` operators
#include <stc/clist.h> // clist_int: singly linked list
#define i_key int
@@ -615,19 +614,20 @@ STC is generally very memory efficient. Memory usage for the different container
## Version 4.3
- Some breaking changes.
-- coroutines: much improved with some new API and added features.
-- cspan: Support for column-major (fortran order) multidim spans and transposed views.
-- Removed default comparison for clist, cvec and cdeq (as with cstack and cqueue).
- - Using i_key_str, i_keyclass, i_keyboxed still expects comparisons defined.
- - Define i_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.
+- **coroutines**: much improved with some new API and added features.
+- **cspan**: Rewritten to add support for **column-major** order (fortran) multidim spans and transposed views.
+- Removed default comparison for **clist**, **cvec** and **cdeq** (like cstack and cqueue).
+ - Define `i_cmp_native` to enable built-in i_key types comparisons (<, ==).
+ - Use of `i_keyclass` still expects comparison functions defined.
+ - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined.
+- **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including.
+- All new faster and smaller **cqueue** and **cdeq** implementations, using a circular buffer.
+- Renamed i_extern => `i_import`.
+ - Define `i_import` before `#include <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 initializing containers with element lists.
+- Renamed input enum flags for ***cregex***-functions.
+- Removed deprecated <stc/crandom.h>. Use `<stc/crand.h>` with the new API.
- Removed deprecated uppercase flow-control macro names.
- Improved default string hash function.
@@ -640,7 +640,6 @@ STC is generally very memory efficient. Memory usage for the different container
- Added new crand.h API & header. Old crandom.h is deprecated.
- Added `c_const_cast()` typesafe macro.
- Removed RAII macros usage from examples
-- Renamed c_foreach_r => `c_foreach_rv`
- Renamed c_flt_count(i) => `c_flt_counter(i)`
- Renamed c_flt_last(i) => `c_flt_getcount(i)`
- Renamed c_ARRAYLEN() => c_arraylen()
@@ -654,8 +653,8 @@ Major changes:
- Customizable allocator [per templated container type](https://github.com/tylov/STC/discussions/44#discussioncomment-4891925).
- Updates on **cregex** with several [new unicode character classes](docs/cregex_api.md#regex-cheatsheet).
- Algorithms:
- - [crange](docs/ccommon_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator.
- - [c_forfilter](docs/ccommon_api.md#c_forfilter) - ranges-like view filtering.
+ - [crange](docs/algorithm_api.md#crange) - similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html) integer range generator.
+ - [c_forfilter](docs/algorithm_api.md#c_forfilter) - ranges-like view filtering.
- [csort](include/stc/algo/sort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison.
- Renamed `c_ARGSV()` => `c_SV()`: **csview** print arg. Note `c_sv()` is shorthand for *csview_from()*.
- Support for [uppercase flow-control](include/stc/priv/altnames.h) macro names in ccommon.h.
@@ -716,10 +715,10 @@ Major changes:
- Renamed: *csptr_X_make()* to `carc_X_from()`.
- Renamed: *cstr_new()* to `cstr_lit(literal)`, and *cstr_assign_fmt()* to `cstr_printf()`.
- Renamed: *c_default_fromraw()* to `c_default_from()`.
-- Changed: the [**c_apply**](docs/ccommon_api.md) macros API.
+- Changed: the [**c_apply**](docs/algorithm_api.md) macros API.
- Replaced: *csview_first_token()* and *csview_next_token()* with one function: `csview_token()`.
- Added: **checkauto** tool for checking that c-source files uses `c_auto*` macros correctly.
- Added: general `i_keyclass` / `i_valclass` template parameters which auto-binds template functions.
- Added: `i_opt` template parameter: compile-time options: `c_no_cmp`, `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|`
- Added: [**cbox**](docs/cbox_api.md) type: smart pointer, similar to [Rust Box](https://doc.rust-lang.org/rust-by-example/std/box.html) and [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr).
-- Added: [**c_forpair**](docs/ccommon_api.md) macro: for-loop with "structured binding"
+- Added: [**c_forpair**](docs/algorithm_api.md) macro: for-loop with "structured binding"
diff --git a/docs/ccommon_api.md b/docs/algorithm_api.md
index e053f743..490771b5 100644
--- a/docs/ccommon_api.md
+++ b/docs/algorithm_api.md
@@ -1,15 +1,17 @@
# STC Algorithms
----
+"No raw loops" - Sean Parent
## Ranged for-loops
-### c_foreach, c_foreach_rv, c_forpair
+### c_foreach, c_forpair
+```c
+#include <stc/ccommon.h>
+```
| Usage | Description |
|:-----------------------------------------|:------------------------------------------|
| `c_foreach (it, ctype, container)` | Iteratate all elements |
| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) |
-| `c_foreach_rv (it, ctype, container)` | Iteratate in reverse (cstack, cvec, cdeq) |
| `c_forpair (key, val, ctype, container)` | Iterate with structured binding |
```c
@@ -54,9 +56,9 @@ c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} })
c_forlist (i, const char*, {"Hello", "crazy", "world"})
cstack_str_emplace(&stk, *i.ref);
```
-
---
-## Range algorithms
+
+## Integer range loops
### c_forrange
Abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop.
@@ -79,19 +81,19 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i);
// 30 25 20 15 10 5
```
-### crange
+### crange: Integer range generator object
A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*:
```c
-crange crange_make(stop); // will generate 0, 1, ..., stop-1
-crange crange_make(start, stop); // will generate start, start+1, ... stop-1
-crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop
+crange crange_init(stop); // will generate 0, 1, ..., stop-1
+crange crange_init(start, stop); // will generate start, start+1, ... stop-1
+crange crange_init(start, stop, step); // will generate start, start+step, ... upto-not-including stop
// note that step may be negative.
crange_iter crange_begin(crange* self);
crange_iter crange_end(crange* self);
void crange_next(crange_iter* it);
// 1. All primes less than 32:
-crange r1 = crange_make(3, 32, 2);
+crange r1 = crange_init(3, 32, 2);
printf("2"); // first prime
c_forfilter (i, crange, r1, isPrime(*i.ref))
printf(" %lld", *i.ref);
@@ -99,7 +101,7 @@ c_forfilter (i, crange, r1, isPrime(*i.ref))
// 2. The first 11 primes:
printf("2");
-crange range = crange_make(3, INT64_MAX, 2);
+crange range = crange_init(3, INT64_MAX, 2);
c_forfilter (i, crange, range,
isPrime(*i.ref) &&
c_flt_take(10)
@@ -110,12 +112,12 @@ c_forfilter (i, crange, range,
```
### c_forfilter
-Iterate a container/range with chained range filtering.
+Iterate a container or a crange with chained `&&` filtering.
| Usage | Description |
|:----------------------------------------------------|:---------------------------------------|
| `c_forfilter (it, ctype, container, filter)` | Filter out items in chain with && |
-| `c_forfilter_it (it, ctype, startit, filter)` | Filter from startit position |
+| `c_forfilter_it (it, ctype, startit, filter)` | Filter from startit iterator position |
| Built-in filter | Description |
|:----------------------------------|:-------------------------------------------|
@@ -140,7 +142,7 @@ bool isPrime(long long i) {
int main(void) {
// Get 10 prime numbers starting from 1000. Skip the first 15 primes,
// then select every 25th prime (including the initial).
- crange R = crange_make(1001, INT64_MAX, 2); // 1001, 1003, ...
+ crange R = crange_init(1001, INT64_MAX, 2); // 1001, 1003, ...
c_forfilter (i, crange, R,
isPrime(*i.ref) &&
@@ -216,7 +218,7 @@ There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c).
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));
+ ints_sort_n(nums, c_arraylen(nums)); // note: function name derived from i_key
c_forrange (i, c_arraylen(arr)) printf(" %d", arr[i]);
}
```
@@ -290,132 +292,6 @@ Type c_default_clone(Type val); // return val
Type c_default_toraw(const Type* p); // return *p
void c_default_drop(Type* p); // does nothing
```
-
----
-## Coroutines
-This is a much improved implementation of
-[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html),
-which utilizes the *Duff's device* trick. Tatham's implementation is not typesafe,
-and it always allocates the coroutine's internal state dynamically. But crucially,
-it does not let the coroutine do self-cleanup on early finish - i.e. it
-only frees the initial dynamically allocated memory.
-
-In this implementation, a coroutine may have any signature, but it should
-take a struct pointer as parameter, which must contain the member `int cco_state;`
-The struct should normally store all the *local* variables to be used in the
-coroutine. It can also store input and output data if desired.
-
-The coroutine example below generates Pythagorian triples, but the calling loop
-skips the triples which are upscaled version of smaller ones, by checking
-the gcd() function. It also ensures that it stops when the diagonal size >= 100:
-
-[ [Run this code](https://godbolt.org/z/coqqrfbd5) ]
-```c
-#include <stc/calgo.h>
-#include <stdio.h>
-
-struct triples {
- int n; // input: max number of triples to be generated.
- int a, b, c;
- int cco_state; // required member
-};
-
-int triples(struct triples* i) { // coroutine
- cco_routine(i) {
- for (i->c = 5; i->n; ++i->c) {
- for (i->a = 1; i->a < i->c; ++i->a) {
- for (i->b = i->a + 1; i->b < i->c; ++i->b) {
- if ((int64_t)i->a*i->a + (int64_t)i->b*i->b == (int64_t)i->c*i->c) {
- cco_yield();
- if (--i->n == 0)
- cco_return;
- }
- }
- }
- }
- cco_cleanup:
- puts("done");
- }
- return 0;
-}
-
-int gcd(int a, int b) { // greatest common denominator
- while (b) {
- int t = a % b;
- a = b;
- b = t;
- }
- return a;
-}
-
-int main(void)
-{
- struct triples t = {.n=INT32_MAX};
- int n = 0;
-
- while (triples(&t)) {
- // Skip triples with GCD(a,b) > 1
- if (gcd(t.a, t.b) > 1)
- continue;
-
- // Stop when c >= 100
- if (t.c < 100)
- printf("%d: [%d, %d, %d]\n", ++n, t.a, t.b, t.c);
- else
- cco_stop(&t); // cleanup in next coroutine call/resume
- }
-}
-```
-### Coroutine API
-To resume the coroutine from where it was suspended with *cco_yield()*: call the coroutine again.
-
-**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement from a
-cco_routine scope; Use `if-else-if` constructs instead.
-
-| | Function / operator | Description |
-|:----------|:-------------------------------------|:----------------------------------------|
-| | 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
General ***defer*** mechanics for resource acquisition. These macros allows you to specify the
diff --git a/docs/carc_api.md b/docs/carc_api.md
index 8b7b67a1..fb79019a 100644
--- a/docs/carc_api.md
+++ b/docs/carc_api.md
@@ -20,15 +20,21 @@ See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory
## Header file and declaration
```c
-#define i_type // full typename of the carc
-#define i_key // element type: REQUIRED
-
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined.
-#define i_keyfrom // convertion func i_keyraw => i_key
-
-#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc.
-#define i_tag // alternative typename: carc_{i_tag}. i_tag defaults to i_key
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // carc container type name
+#define i_cmp <f> // three-way compareison. REQUIRED IF i_key is a non-integral type
+ // Note that containers of carcs will "inherit" i_cmp
+ // when using carc in containers with i_valboxed MyArc - ie. the i_type.
+#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type.
+#define i_keydrop <f> // destroy element func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined.
+
+#define i_keyraw <t> // convertion type (lookup): default to {i_key}
+#define i_keyto <f> // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined.
+#define i_keyfrom <f> // from-raw func.
+
+#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc.
+#define i_tag <s> // 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.
diff --git a/docs/cbox_api.md b/docs/cbox_api.md
index b6c76d2f..0e6fca64 100644
--- a/docs/cbox_api.md
+++ b/docs/cbox_api.md
@@ -14,18 +14,23 @@ See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory
## Header file and declaration
```c
-#define i_type // full typename of the cbox
-#define i_key // element type: REQUIRED
-#define i_cmp // three-way compare two i_key* : REQUIRED IF i_key is a non-integral type
-#define i_keydrop // destroy element func - defaults to empty destruct
-#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined.
-
-#define i_keyraw // convertion type (lookup): default to {i_key}
-#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined.
-#define i_keyfrom // from-raw func.
-
-#define i_keyclass // alt. to i_key: REQUIRES that {i_key}_clone, {i_key}_drop, {i_keyraw}_cmp exist.
-#define i_tag // alternative typename: cbox_{i_tag}. i_tag defaults to i_key
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // cbox container type name
+#define i_cmp <f> // three-way compareison. REQUIRED IF i_key is a non-integral type
+ // Note that containers of carcs will "inherit" i_cmp
+ // when using carc in containers with i_valboxed MyArc - ie. the i_type.
+#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type.
+#define i_keydrop <f> // destroy element func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined.
+
+#define i_keyraw <t> // convertion type (lookup): default to {i_key}
+#define i_keyto <f> // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined.
+#define i_keyfrom <f> // from-raw func.
+
+#define i_tag <s> // alternative typename: cbox_{i_tag}. i_tag defaults to i_key
+#define i_keyclass <t> // Use instead of i_key when functions {i_key}_clone,
+ // {i_key}_drop and {i_keyraw}_cmp exist.
+#define i_keyboxed <t> // Use instead of i_key when key is a carc- or a cbox-type.
#include <stc/cbox.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md
index c6de6cd6..38de7f66 100644
--- a/docs/cdeq_api.md
+++ b/docs/cdeq_api.md
@@ -10,17 +10,18 @@ See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque
## Header file and declaration
```c
-#define i_type // full typename of the container
-#define i_key // value: REQUIRED
-#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
-#define i_keydrop // destroy value func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
-
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key
-#define i_keyto // convertion func i_key* => i_keyraw
-
-#define i_tag // alternative typename: cdeq_{i_tag}. i_tag defaults to i_key
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // cdeq container type name
+#define i_cmp <f> // three-way compare of two i_keyraw*.
+#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type.
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop is defined
+
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
+
+#define i_tag <s> // 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.
diff --git a/docs/clist_api.md b/docs/clist_api.md
index 3d785789..d8d614c2 100644
--- a/docs/clist_api.md
+++ b/docs/clist_api.md
@@ -22,16 +22,17 @@ See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list)
## Header file and declaration
```c
-#define i_type // container type name (default: clist_{i_key})
-#define i_key // value: REQUIRED
-#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
-#define i_keydrop // destroy value func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
-
-#define i_keyraw // convertion "raw" type (default: {i_key})
-#define i_keyto // convertion func i_key* => i_keyraw
-#define i_keyfrom // convertion func i_keyraw => i_key
-#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // clist container type name
+#define i_cmp <f> // three-way compare two i_keyraw*
+#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type.
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
+
+#define i_keyraw <t> // convertion "raw" type (default: {i_key})
+#define i_keyto <f> // convertion func i_key* => i_keyraw
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_tag <s> // alternative typename: cpque_{i_tag}. i_tag defaults to i_key
#include <stc/clist.h>
```
diff --git a/docs/cmap_api.md b/docs/cmap_api.md
index eca350b4..17f27662 100644
--- a/docs/cmap_api.md
+++ b/docs/cmap_api.md
@@ -17,26 +17,25 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain
## Header file and declaration
```c
-#define i_type // container type name (default: cmap_{i_key})
-#define i_key // hash key: REQUIRED
-#define i_val // map value: REQUIRED
-#define i_hash // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type
-#define i_eq // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a
- // non-integral type. Three-way i_cmp may alternatively be specified.
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key
-#define i_keyto // convertion func i_key* => i_keyraw
-
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
-#define i_valraw // convertion "raw" type - defaults to i_val
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_valto // convertion func i_val* => i_valraw
-
-#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val
-#define i_expandby // default 1. If 2, table expand 2x (else 1.5x)
+#define i_key <t> // key type: REQUIRED.
+#define i_val <t> // mapped value type: REQUIRED.
+#define i_type <t> // container type name (default: cmap_{i_key})
+#define i_hash <f> // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type
+#define i_eq <f> // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a
+ // non-integral type. Three-way i_cmp may alternatively be specified.
+#define i_keydrop <f> // destroy key func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
+
+#define i_valdrop <f> // destroy value func - defaults to empty destruct
+#define i_valclone <f> // REQUIRED IF i_valdrop defined
+#define i_valraw <t> // convertion "raw" type - defaults to i_val
+#define i_valfrom <f> // convertion func i_valraw => i_val
+#define i_valto <f> // convertion func i_val* => i_valraw
+
+#define i_tag <s> // alternative typename: cmap_{i_tag}. i_tag defaults to i_val
#include <stc/cmap.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md
new file mode 100644
index 00000000..30b85640
--- /dev/null
+++ b/docs/coroutine_api.md
@@ -0,0 +1,292 @@
+# STC [coroutine](../include/stc/coroutine.h): Coroutines
+![Coroutine](pics/coroutine.jpg)
+
+An implementation of stackless coroutines, which are lightweight threads, providing a blocking
+context cheaply using little memory per coroutine.
+
+Coroutines are used to accomplish a non-preempted form of concurrency known as cooperative multitasking and, therefore, do not incur context switching when yielding to another thread. Within a coroutine, **yield** and **await** is accomplished by utilizing Duff's device within a thread's function and an external variable used in within the switch statement. This allows jumping (resuming) from a yield upon another function call. In order to block threads, these yields may be guarded by a conditional so that successive calls to the same function will yield unless the guard conditional is true.
+
+Because these coroutines are stackless, local variables within the coroutine where usage crosses `cco_yield` or `cco_await` must be stored in a struct which is passed as pointer to the coroutine. This has the advantages that they become very lightweight and therefore useful on severely memory constrained systems like small microcontrollers where other solutions are impractical or less desirable.
+
+### Coroutine API
+
+NB! ***cco_yield\*()*** / ***cco_await\*()*** may not be called from within a `switch` statement in a
+`cco_routine` scope; Use `if-else-if` constructs instead.
+
+| | Function / operator | Description |
+|:----------|:-------------------------------------|:----------------------------------------|
+|`cco_result` | `CCO_DONE`, `CCO_AWAIT`, `CCO_YIELD` | Default set of return values from coroutines |
+| | `cco_cleanup:` | Label for cleanup position in coroutine |
+| `bool` | `cco_done(co)` | Is coroutine done? |
+| | `cco_routine(co) {}` | The coroutine scope |
+| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)|
+| | `cco_yield_v(ret);` | Yield/suspend execution (return ret) |
+| | `cco_yield_final();` | Yield final suspend, enter cleanup-state |
+| | `cco_yield_final(ret);` | Yield a final value |
+| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)|
+| | `cco_call_await(cocall);` | Await for subcoro to finish (returns its ret value) |
+| | `cco_call_await(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) |
+| | `cco_return;` | Return from coroutine (inside cco_routine) |
+| | Task objects: | |
+| | `cco_task_struct(Name, ...);` | Define a coroutine task struct |
+| | `cco_task_await(task, cco_runtime* rt);`| Await for task to finish |
+| | `cco_task_await(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) |
+|`cco_result`| `cco_task_resume(task, rt);` | Resume suspended task |
+| | Semaphores: | |
+| | `cco_sem` | Semaphore type |
+| `cco_sem` | `cco_sem_from(long value)` | Create semaphore |
+| | `cco_sem_set(sem, long value)` | Set semaphore value |
+| | `cco_sem_await(sem)` | Await for the semaphore count > 0 |
+| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) |
+| | Timers: | |
+| | `cco_timer` | Timer type |
+| | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)|
+| | `cco_timer_start(tm, double sec)` | Start timer for secs duration |
+| | `cco_timer_restart(tm)` | Restart timer with same duration |
+| `bool` | `cco_timer_expired(tm)` | Return true if timer is expired |
+| `double` | `cco_timer_elapsed(tm)` | Return seconds elapsed |
+| `double` | `cco_timer_remaining(tm)` | Return seconds remaining |
+| | From caller side: | |
+| `void` | `cco_stop(co)` | Next call of coroutine finalizes |
+| `void` | `cco_reset(co)` | Reset state to initial (for reuse) |
+| `void` | `cco_call_blocking(cocall) {}` | Run blocking until cocall is finished |
+| `void` | `cco_call_blocking(cocall, int* outres) {}`| Run blocking until cocall is finished |
+| | `cco_task_blocking(task) {}` | Run blocking until task is finished |
+| | `cco_task_blocking(task, rt, STACKSZ) {}`| Run blocking until task is finished |
+| | Time functions: | |
+| `double` | `cco_time(void)` | Return secs with usec prec. since Epoch |
+| | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) |
+
+
+## Implementation and examples
+
+This small implementation of coroutines is inspired by
+[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html) and
+[Adam Dunkel's photothreads](https://dunkels.com/adam/pt), but provides big improvements regarding
+ergonomics, features, and type-safety. Crucially, it also allows coroutines to self-cleanup when
+cancelled (not resumed until they are done).
+
+A coroutine function may have almost any signature, but the implementation adds support for
+coroutines which returns an int, indicating CCO_DONE, CCO_AWAIT, or CCO_YIELD. It should also
+take a struct pointer as parameter which must contains the member `int cco_state`. The struct should
+normally store all *local* variables to be used within the coroutine, along with *input* and *output* data
+for the coroutine.
+
+Note that this implementation is not limited to support a certain set of coroutine types,
+like generators. It can even operate like stackfull coroutines, i.e. you can efficiently
+yield or await from a (deeply) nested coroutine call using cco_task objects described later.
+
+The first example is a generator of Pythagorian triples, and stops when diagonal size > max_c.
+
+[ [Run this code](https://godbolt.org/z/3Efn17cP6) ]
+```c
+#include <stc/coroutine.h>
+#include <stdio.h>
+#include <stdio.h>
+// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
+
+struct triples {
+ int max_c; // input: max c.
+ int a, b, c; // output
+ int cco_state; // required member
+};
+
+int triples(struct triples* i) {
+ cco_routine(i) { // the coroutine scope!
+ for (i->c = 5;; ++i->c) {
+ for (i->a = 1; i->a < i->c; ++i->a) {
+ for (i->b = i->a + 1; i->b < i->c; ++i->b) {
+ if ((int64_t)i->a * i->a +
+ (int64_t)i->b * i->b ==
+ (int64_t)i->c * i->c)
+ {
+ if (i->c > i->max_c)
+ cco_return; // "jump" to cco_cleanup if defined, else exit scope.
+ cco_yield();
+ }
+ }
+ }
+ }
+ cco_cleanup:
+ puts("done");
+ }
+ return 0; // CCO_DONE
+}
+
+int main(void) {
+ struct triples co = {.max_c = 25};
+ int n = 0;
+
+ cco_call_blocking(triples(&co)) {
+ printf("%d: [%d, %d, %d]\n", ++n, co.a, co.b, co.c);
+ }
+}
+```
+The next variant skips the triples which are upscaled version of smaller ones by checking
+the gcd() function. Note that the gcd1_triples struct contains the triples struct so that
+both functions have separate call frames:
+
+[ [Run this code](https://godbolt.org/z/ndhMq1haj) ]
+```c
+int gcd(int a, int b) { // greatest common denominator
+ while (b) {
+ int t = a % b;
+ a = b;
+ b = t;
+ }
+ return a;
+}
+
+struct gcd1_triples {
+ int max_n, max_c, count; // input: max_n, max_c limit #triples to be generated.
+ struct triples tri; // triples call frame
+ int cco_state;
+};
+
+int gcd1_triples(struct gcd1_triples* i)
+{
+ cco_routine(i) {
+ cco_reset(&i->tri);
+ i->tri.max_c = i->max_c;
+
+ while (triples(&i->tri) != CCO_DONE) {
+ // Skip triples with GCD(a,b) > 1
+ if (gcd(i->tri.a, i->tri.b) > 1)
+ continue;
+
+ // Done when count > max_n
+ if (++i->count > i->max_n)
+ cco_return;
+ else
+ cco_yield();
+ }
+ cco_cleanup:
+ cco_stop(&i->tri); // to cleanup state if still active
+ triples(&i->tri); // do cleanup (or no-op if done)
+ }
+ return 0;
+}
+
+int main(void) {
+ struct gcd1_triples co = {.max_n = 100, .max_c = 100};
+ int n = 0;
+
+ cco_call_blocking(gcd1_triples(&co)) {
+ printf("%d: [%d, %d, %d]\n", ++n, co.tri.a, co.tri.b, co.tri.c);
+ }
+}
+```
+When using ***cco_call_blocking()***, the coroutine is continuously resumed after each yield suspension.
+However, this means that it first calls ***gcd1_triples()***, which immediately jumps to after the `cco_yield`
+-statement and calls ***triples()***, which again jumps and resumes after its `cco_yield`-statement. This
+is efficient only when yielding or awaiting from the top- or second-level call like here, but naturally not
+when couroutine calls are more deeply nested or recursive.
+
+The STC coroutine implementation therefore also contains task-objects (`cco_task`), which are base-coroutine
+objects/enclosures. These can be executed using ***cco_task_blocking()*** instead of ***cco_call_blocking()***.
+Inner coroutine calls are done by ***cco_task_await()***, where you may await for a certain return value, normally CCO_YIELD or just CCO_DONE. It uses a stack of pointers of task-enclosures to call the current
+inner-level function directly. The task-objects have the added benefit that coroutines can be managed
+by a scheduler, which is useful when dealing with large numbers of coroutines (like in many games and
+simulations).
+
+Note that these two modes may be mixed, and that for short-lived coroutines (only a few suspends),
+it is often beneficial to call the sub-coroutine directly rather than via ***cco_task_await()***
+(which pushes the task on top of the runtime stack and yields - then executed on next resume).
+
+The following example uses task-objects with 3-levels deep coroutine calls. It emulates an async generator
+by awaiting a few seconds before producing a number, using a timer.
+```c
+// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/
+#include <time.h>
+#include <stdio.h>
+#define i_static
+#include <stc/cstr.h>
+#include <stc/coroutine.h>
+
+cco_task_struct (next_value,
+ int val;
+ cco_timer tm;
+);
+
+int next_value(struct next_value* co, cco_runtime* rt)
+{
+ cco_routine (co) {
+ while (true) {
+ cco_timer_await(&co->tm, 1 + rand() % 2); // suspend with CCO_AWAIT
+ co->val = rand();
+ cco_yield(); // suspend with CCO_YIELD
+ }
+ }
+ return 0;
+}
+
+void print_time()
+{
+ time_t now = time(NULL);
+ char mbstr[64];
+ strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now));
+ printf("%s ", mbstr);
+}
+
+// PRODUCER
+cco_task_struct (produce_items,
+ struct next_value next;
+ cstr str;
+);
+
+int produce_items(struct produce_items* p, cco_runtime* rt)
+{
+ cco_routine (p) {
+ p->str = cstr_null;
+ p->next.cco_func = next_value;
+ while (true)
+ {
+ // await for CCO_YIELD (or CCO_DONE)
+ cco_task_await(&p->next, rt, CCO_YIELD);
+ cstr_printf(&p->str, "item %d", p->next.val);
+ print_time();
+ printf("produced %s\n", cstr_str(&p->str));
+ cco_yield();
+ }
+ cco_cleanup:
+ cstr_drop(&p->str);
+ puts("done produce");
+ }
+ return 0;
+}
+
+// CONSUMER
+cco_task_struct (consume_items,
+ int n, i;
+ struct produce_items produce;
+);
+
+int consume_items(struct consume_items* c, cco_runtime* rt)
+{
+ cco_routine (c) {
+ c->produce.cco_func = produce_items;
+
+ for (c->i = 1; c->i <= c->n; ++c->i)
+ {
+ printf("consume #%d\n", c->i);
+ cco_task_await(&c->produce, rt, CCO_YIELD);
+ print_time();
+ printf("consumed %s\n", cstr_str(&c->produce.str));
+ }
+ cco_cleanup:
+ cco_stop(&c->produce);
+ cco_task_resume(&c->produce, rt);
+ puts("done consume");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct consume_items consume = {
+ .n = 5,
+ .cco_func = consume_items,
+ };
+ cco_task_blocking(&consume);
+}
+``` \ No newline at end of file
diff --git a/docs/cpque_api.md b/docs/cpque_api.md
index 5b63dfd1..247424b4 100644
--- a/docs/cpque_api.md
+++ b/docs/cpque_api.md
@@ -8,17 +8,17 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai
## Header file and declaration
```c
-#define i_type // define type name of the container (default cpque_{i_key})
-#define i_key // value: REQUIRED
-#define i_less // compare two i_key* : REQUIRED IF i_key/i_keyraw is a non-integral type
-#define i_keydrop // destroy value func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // cpque container type name
+#define i_less <f> // compare two i_key* : REQUIRED IF i_key/i_keyraw is a non-integral type
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
-#define i_keyraw // convertion type
-#define i_keyfrom // convertion func i_keyraw => i_key
-#define i_keyto // convertion func i_key* => i_keyraw.
+#define i_keyraw <t> // convertion type
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw.
-#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key
+#define i_tag <s> // 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.
@@ -72,14 +72,14 @@ int main(void)
{
intptr_t N = 10000000;
crand_t rng = crand_init(1234);
- crand_unif_t dist = crand_unif_init(0, N * 10);
+ crand_uniform_t dist = crand_uniform_init(0, N * 10);
// Define heap
cpque_i heap = {0};
// Push ten million random numbers to priority queue.
c_forrange (N)
- cpque_i_push(&heap, crand_unif(&rng, &dist));
+ cpque_i_push(&heap, crand_uniform(&rng, &dist));
// Add some negative ones.
int nums[] = {-231, -32, -873, -4, -343};
diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md
index b324e5fc..1834baf9 100644
--- a/docs/cqueue_api.md
+++ b/docs/cqueue_api.md
@@ -7,16 +7,16 @@ See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue
## Header file and declaration
```c
-#define i_type // container type name (default: cqueue_{i_key})
-#define i_key // value: REQUIRED
-#define i_keydrop // destroy value func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // cqueue container type name
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key
-#define i_keyto // convertion func i_key* => i_keyraw
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
-#define i_tag // alternative typename: cqueue_{i_tag}. i_tag defaults to i_key
+#define i_tag <s> // 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.
diff --git a/docs/crandom_api.md b/docs/crandom_api.md
index 22a4f4dd..88924784 100644
--- a/docs/crandom_api.md
+++ b/docs/crandom_api.md
@@ -1,30 +1,29 @@
# STC [crand](../include/stc/crand.h): Pseudo Random Number Generator
![Random](pics/random.jpg)
-This features a *64-bit PRNG* named **stc64**, and can generate bounded uniform and normal
+This features a *64-bit PRNG* named **crand64**, and can generate bounded uniform and normal
distributed random numbers.
See [random](https://en.cppreference.com/w/cpp/header/random) for similar c++ functionality.
## Description
-**stc64** is a novel, extremely fast PRNG by Tyge Løvset, suited for parallel usage. It features
-Weyl-sequences as part of its state. It is inspired on *sfc64*, but has a different output function
+**crand64** is a novel, very fast PRNG, suited for parallel usage. It features a
+Weyl-sequence as part of its state. It is based on *sfc64*, but has a different output function
and state size.
-**sfc64** is the fastest among *pcg*, *xoshiro`**`*, and *lehmer*. It is equally fast as *sfc64* on
-most platforms. *wyrand* is faster on platforms with fast 128-bit multiplication, and has 2^64 period
-length (https://github.com/lemire/SwiftWyhash/issues/10). However, *wyrand* is not suited for massive
-parallel usage due to its limited total minimal period length.
+**sfc64** is the fastest among *pcg*, *xoshiro`**`*, and *lehmer*. It is equally fast or faster than
+*sfc64* on most platforms. *wyrand* is faster on platforms with fast 128-bit multiplication, and has
+2^64 period (https://github.com/lemire/SwiftWyhash/issues/10). *wyrand* is not suited for massive
+parallel usage due to its limited minimal period.
-**stc64** does not require multiplication or 128-bit integer operations. It has 320 bit state,
-but updates only 256 bit per generated number.
+**crand64** does not require multiplication or 128-bit integer operations. It has 320 bit state,
+where 64-bits are constant per prng instance created.
There is no *jump function*, but each odd number Weyl-increment (state[4]) starts a new
-unique 2^64 *minimum* length period. For a single thread, a minimum period of 2^127 is generated
-when the Weyl-increment is incremented by 2 every 2^64 output.
+unique 2^64 *minimum* length period, i.e. virtually unlimitied number of unique threads.
-**stc64** passes *PractRand* (tested up to 8TB output), Vigna's Hamming weight test, and simple
+**crand64** passes *PractRand* (tested up to 8TB output), Vigna's Hamming weight test, and simple
correlation tests, i.e. *n* interleaved streams with only one-bit differences in initial state.
Also 32-bit and 16-bit versions passes PractRand up to their size limits.
@@ -41,27 +40,27 @@ All crand definitions and prototypes are available by including a single header
## Methods
```c
-void csrand(uint64_t seed); // seed global stc64 prng
+void csrand(uint64_t seed); // seed global crand64 prng
uint64_t crand(void); // global crand_u64(rng)
double crandf(void); // global crand_f64(rng)
-crand_t crand_init(uint64_t seed); // stc64_init(s) is deprecated
+crand_t crand_init(uint64_t seed);
uint64_t crand_u64(crand_t* rng); // range [0, 2^64 - 1]
double crand_f64(crand_t* rng); // range [0.0, 1.0)
-crand_unif_t crand_unif_init(int64_t low, int64_t high); // uniform-distribution
-int64_t crand_unif(crand_t* rng, crand_unif_t* dist); // range [low, high]
+crand_uniform_t crand_uniform_init(int64_t low, int64_t high); // uniform-distribution range
+int64_t crand_uniform(crand_t* rng, crand_uniform_t* dist);
-crand_norm_t crand_norm_init(double mean, double stddev); // normal-distribution
-double crand_norm(crand_t* rng, crand_norm_t* dist);
+crand_normal_t crand_normal_init(double mean, double stddev); // normal-gauss distribution
+double crand_normal(crand_t* rng, crand_normal_t* dist);
```
## Types
| Name | Type definition | Used to represent... |
|:-------------------|:------------------------------------------|:-----------------------------|
| `crand_t` | `struct {uint64_t state[4];}` | The PRNG engine type |
-| `crand_unif_t` | `struct {int64_t lower; uint64_t range;}` | Integer uniform distribution |
-| `crand_norm_t` | `struct {double mean, stddev;}` | Normal distribution type |
+| `crand_uniform_t` | `struct {int64_t lower; uint64_t range;}` | Integer uniform distribution |
+| `crand_normal_t` | `struct {double mean, stddev;}` | Normal distribution type |
## Example
```c
@@ -86,17 +85,17 @@ int main(void)
// Setup random engine with normal distribution.
uint64_t seed = time(NULL);
crand_t rng = crand_init(seed);
- crand_norm_t dist = crand_norm_init(Mean, StdDev);
+ crand_normal_t dist = crand_normal_init(Mean, StdDev);
// Create histogram map
- csmap_i mhist = csmap_i_init();
+ csmap_i mhist = {0};
c_forrange (N) {
- int index = (int)round(crand_norm(&rng, &dist));
+ int index = (int)round(crand_normal(&rng, &dist));
csmap_i_emplace(&mhist, index, 0).ref->second += 1;
}
// Print the gaussian bar chart
- cstr bar = cstr_init();
+ cstr bar = {0};
c_foreach (i, csmap_i, mhist) {
int n = (int)(i.ref->second * StdDev * Scale * 2.5 / N);
if (n > 0) {
diff --git a/docs/cset_api.md b/docs/cset_api.md
index e894ad4f..928d63a8 100644
--- a/docs/cset_api.md
+++ b/docs/cset_api.md
@@ -7,19 +7,19 @@ A **cset** is an associative container that contains a set of unique objects of
## Header file and declaration
```c
-#define i_type // container type name (default: cset_{i_key})
-#define i_key // hash key: REQUIRED.
-#define i_hash // hash func: REQUIRED IF i_keyraw is a non-pod type.
-#define i_eq // equality comparison two i_keyraw*: !i_cmp is used if not defined.
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
-
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
-#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
-
-#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_key
-#define i_expandby // default 1. If 2, table expand 2x (else 1.5x)
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // container type name
+#define i_hash <f> // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type
+#define i_eq <f> // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a
+ // non-integral type. Three-way i_cmp may alternatively be specified.
+#define i_keydrop <f> // destroy key func: defaults to empty destruct
+#define i_keyclone <f> // clone func: REQUIRED IF i_keydrop defined
+
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key - defaults to plain copy
+#define i_keyto <f> // convertion func i_key* => i_keyraw - defaults to plain copy
+
+#define i_tag <s> // alternative typename: cmap_{i_tag}. i_tag defaults to i_key
#include <stc/cset.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
diff --git a/docs/csmap_api.md b/docs/csmap_api.md
index 099d7dfc..164b0f8a 100644
--- a/docs/csmap_api.md
+++ b/docs/csmap_api.md
@@ -15,24 +15,24 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo
## Header file and declaration
```c
-#define i_type // container type name (default: cmap_{i_key})
-#define i_key // key: REQUIRED
-#define i_val // value: REQUIRED
-#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
-
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_valdrop defined
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key
-#define i_keyto // convertion func i_key* => i_keyraw
-
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
-#define i_valraw // convertion "raw" type - defaults to i_val
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_valto // convertion func i_val* => i_valraw
-
-#define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val
+#define i_key <t> // key type: REQUIRED.
+#define i_val <t> // mapped value type: REQUIRED.
+#define i_type <t> // container type name (default: cmap_{i_key})
+#define i_cmp <f> // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
+
+#define i_keydrop <f> // destroy key func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_valdrop defined
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
+
+#define i_valdrop <f> // destroy value func - defaults to empty destruct
+#define i_valclone <f> // REQUIRED IF i_valdrop defined
+#define i_valraw <t> // convertion "raw" type - defaults to i_val
+#define i_valfrom <f> // convertion func i_valraw => i_val
+#define i_valto <f> // convertion func i_val* => i_valraw
+
+#define i_tag <s> // alternative typename: csmap_{i_tag}. i_tag defaults to i_val
#include <stc/csmap.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -148,7 +148,7 @@ Translate a
[C++ example using *insert* and *emplace*](https://en.cppreference.com/w/cpp/container/map/try_emplace)
to STC:
-[ [Run this code](https://godbolt.org/z/9d1PP77Pa) ]
+[ [Run this code](https://godbolt.org/z/b46W5Ezrb) ]
```c
#define i_implement
#include <stc/cstr.h>
diff --git a/docs/cspan_api.md b/docs/cspan_api.md
index 09821450..1312ae6d 100644
--- a/docs/cspan_api.md
+++ b/docs/cspan_api.md
@@ -21,19 +21,20 @@ using_cspan4(S, ValueType); // define span types S, S2, S3, S4 with
```
## Methods
-All functions are type-safe. Note that the span argument itself is generally not side-effect safe,
-i.e., it may be expanded multiple times. However, all index arguments are safe, e.g.
-`cspan_at(&ms3, i++, j++, k++)` is allowed. If the number of arguments does not match the span rank,
-a compile error is issued. Runtime bounds checks are enabled by default (define `STC_NDEBUG` or `NDEBUG` to disable).
+All functions are type-safe. NOTE: the span argument itself is generally **not** side-effect safe -
+it may be expanded multiple times. However, all index arguments are safe, e.g.
+`cspan_at(&ms3, i++, j++, k++)` is safe, but `cspan_at(&spans[n++], i, j)` is an error! If the number
+of arguments does not match the span rank, a compile error is issued. Runtime bounds checks are enabled
+by default (define `STC_NDEBUG` or `NDEBUG` to disable).
```c
-SpanType cspan_init(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values
-SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from compatible STC container
-SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from C array
-
+SpanType cspan_init(TYPE SpanType, {v1, v2, ...}); // make a 1-d cspan from values
+SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from a cvec, cstack, cpque (heap)
+SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from a C array
+
intptr_t cspan_size(const SpanTypeN* self); // return number of elements
intptr_t cspan_rank(const SpanTypeN* self); // dimensions; compile time constant
intptr_t cspan_index(const SpanTypeN* self, intptr_t x, ..); // index of element
-
+
ValueType* cspan_at(const SpanTypeN* self, intptr_t x, ...); // #args must match input span rank
ValueType* cspan_front(const SpanTypeN* self);
ValueType* cspan_back(const SpanTypeN* self);
@@ -45,7 +46,7 @@ void SpanType_next(SpanTypeN_iter* it);
SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // make a multi-dim cspan, row-major order.
SpanTypeN cspan_md_order(char order, ValueType* data, d1, d2, ...); // order='C': row-major, 'F': column-major (FORTRAN).
- // transpose a md span (inverse axes). no changes to the underlying array.
+ // transpose a md span (inverse axes). No changes to the underlying array.
void cspan_transpose(const SpanTypeN* self);
bool cspan_is_order_F(const SpanTypeN* self);
@@ -55,13 +56,13 @@ SpanType2 cspan_subspan2(const SpanType2* span, intptr_t offset, intptr_t
SpanType3 cspan_subspan3(const SpanType3* span, intptr_t offset, intptr_t count);
// create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL});
-OutSpan1 cspan_submd2(const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span.
+OutSpan cspan_submd2(const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span.
OutSpanN cspan_submd3(const SpanType3* parent, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span.
OutSpanN cspan_submd4(const SpanType4* parent, intptr_t x, ...); // number of args decides rank of output span.
// general slicing of an md span.
// {i}: reduce rank. {i,c_END}: slice to end. {c_ALL}: use full extent.
-OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeN* parent, {x0,x1}, {y0,y1}.., {N0,N1});
+OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeM* parent, {x0,x1}, {y0,y1}.., {N0,N1});
```
## TypesPd
| Type name | Type definition / usage | Used to represent... |
diff --git a/docs/csset_api.md b/docs/csset_api.md
index aef3af3c..21e38f61 100644
--- a/docs/csset_api.md
+++ b/docs/csset_api.md
@@ -8,17 +8,17 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo
## Header file and declaration
```c
-#define i_type // full typename of the container
-#define i_key // key: REQUIRED
-#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // container type name
+#define i_cmp <f> // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
+#define i_keydrop <f> // destroy key func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
-#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key - defaults to plain copy
+#define i_keyto <f> // convertion func i_key* => i_keyraw - defaults to plain copy
-#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_key
+#define i_tag <s> // 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.
diff --git a/docs/cstack_api.md b/docs/cstack_api.md
index e799b152..fb629392 100644
--- a/docs/cstack_api.md
+++ b/docs/cstack_api.md
@@ -8,16 +8,16 @@ See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack
## Header file and declaration
```c
-#define i_type // full typename of the container
-#define i_key // value: REQUIRED
-#define i_keydrop // destroy value func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // container type name
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key
-#define i_keyto // convertion func i_key* => i_keyraw
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
-#define i_tag // alternative typename: cstack_{i_tag}. i_tag defaults to i_key
+#define i_tag <s> // 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.
diff --git a/docs/cvec_api.md b/docs/cvec_api.md
index d38ef23f..9cba74b5 100644
--- a/docs/cvec_api.md
+++ b/docs/cvec_api.md
@@ -12,17 +12,18 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect
## Header file and declaration
```c
-#define i_type // full typename of the container
-#define i_key // value: REQUIRED
-#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
-#define i_keydrop // destroy value func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
-
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key
-#define i_keyto // convertion func i_key* => i_keyraw
-
-#define i_tag // alternative typename: cvec_{i_tag}. i_tag defaults to i_key
+#define i_type <t> // container type name
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_cmp <f> // three-way compare two i_keyraw*
+#define i_cmp_native // define instead of i_cmp only when i_key is an integral/native-type.
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
+
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
+
+#define i_tag <s> // 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.
diff --git a/docs/pics/Figure_1.png b/docs/pics/Figure_1.png
new file mode 100644
index 00000000..263303d2
--- /dev/null
+++ b/docs/pics/Figure_1.png
Binary files differ
diff --git a/docs/pics/coroutine.jpg b/docs/pics/coroutine.jpg
new file mode 100644
index 00000000..e5fceab3
--- /dev/null
+++ b/docs/pics/coroutine.jpg
Binary files differ
diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h
index 03162a2d..faeda162 100644
--- a/include/stc/algo/crange.h
+++ b/include/stc/algo/crange.h
@@ -27,14 +27,14 @@
int main(void)
{
- crange r1 = crange_make(80, 90);
+ crange r1 = crange_init(80, 90);
c_foreach (i, crange, r1)
printf(" %lld", *i.ref);
puts("");
// use a temporary crange object.
int a = 100, b = INT32_MAX;
- crange r2 = crange_make(a, b, 8);
+ crange r2 = crange_init(a, b, 8);
c_forfilter (i, crange, r2,
c_flt_skip(i, 10) &&
c_flt_take(i, 3))
@@ -51,11 +51,12 @@ typedef long long crange_value;
typedef struct { crange_value start, end, step, value; } crange;
typedef struct { crange_value *ref, end, step; } crange_iter;
-#define crange_make(...) c_MACRO_OVERLOAD(crange_make, __VA_ARGS__)
-#define crange_make_1(stop) crange_make_3(0, stop, 1)
-#define crange_make_2(start, stop) crange_make_3(start, stop, 1)
+#define crange_make crange_init // [deprecated]
+#define crange_init(...) c_MACRO_OVERLOAD(crange_init, __VA_ARGS__)
+#define crange_init_1(stop) crange_init_3(0, stop, 1)
+#define crange_init_2(start, stop) crange_init_3(start, stop, 1)
-STC_INLINE crange crange_make_3(crange_value start, crange_value stop, crange_value step)
+STC_INLINE crange crange_init_3(crange_value start, crange_value stop, crange_value step)
{ crange r = {start, stop - (step > 0), step}; return r; }
STC_INLINE crange_iter crange_begin(crange* self)
diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h
index 4a227927..1a62c3e1 100644
--- a/include/stc/algo/filter.h
+++ b/include/stc/algo/filter.h
@@ -85,6 +85,21 @@ int main(void)
if (it.ref == _endref) it.ref = NULL; \
} while (0)
+#define c_all_of(boolptr, it, C, cnt, pred) do { \
+ C##_iter it; \
+ c_find_if_4(it, C, cnt, !(pred)); \
+ *(boolptr) = it.ref == NULL; \
+} while (0)
+#define c_any_of(boolptr, it, C, cnt, pred) do { \
+ C##_iter it; \
+ c_find_if_4(it, C, cnt, pred); \
+ *(boolptr) = it.ref != NULL; \
+} while (0)
+#define c_none_of(boolptr, it, C, cnt, pred) do { \
+ C##_iter it; \
+ c_find_if_4(it, C, cnt, pred); \
+ *(boolptr) = it.ref == NULL; \
+} while (0)
// Use with: clist, cmap, cset, csmap, csset:
#define c_erase_if(it, C, cnt, pred) do { \
@@ -95,7 +110,6 @@ int main(void)
} \
} while (0)
-
// Use with: cstack, cvec, cdeq, cqueue:
#define c_eraseremove_if(it, C, cnt, pred) do { \
C* _cnt = &cnt; \
diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h
index 06d7395f..86c9b9f1 100644
--- a/include/stc/algo/sort.h
+++ b/include/stc/algo/sort.h
@@ -70,7 +70,7 @@ int main(void) {
#ifndef i_tag
#define i_tag i_key
#endif
- #define i_type c_PASTE(i_tag, array)
+ #define i_type c_PASTE(i_tag, s)
typedef i_key i_type;
#endif
#ifndef i_at
diff --git a/include/stc/calgo.h b/include/stc/algorithm.h
index 63ef97b9..cf3ab328 100644
--- a/include/stc/calgo.h
+++ b/include/stc/algorithm.h
@@ -4,6 +4,5 @@
#include "algo/raii.h"
#include "algo/crange.h"
#include "algo/filter.h"
-#include "algo/coroutine.h"
#endif
diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h
index 1f9ea80d..77f754fa 100644
--- a/include/stc/ccommon.h
+++ b/include/stc/ccommon.h
@@ -69,7 +69,7 @@ typedef long long _llong;
#define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T)))
#define c_LITERAL(T) (T)
#endif
-#define c_new_n(T, n) ((T*)malloc(sizeof(T)*(n)))
+#define c_new_n(T, n) ((T*)malloc(sizeof(T)*(size_t)(n)))
#define c_malloc(sz) malloc(c_i2u(sz))
#define c_calloc(n, sz) calloc(c_i2u(n), c_i2u(sz))
#define c_realloc(p, sz) realloc(p, c_i2u(sz))
@@ -191,10 +191,6 @@ STC_INLINE intptr_t cnextpow2(intptr_t n) {
for (C##_iter it = start, *_endref = (C##_iter*)(finish).ref \
; it.ref != (C##_value*)_endref; C##_next(&it))
-#define c_foreach_rv(it, C, cnt) \
- for (C##_iter it = {.ref=C##_end(&cnt).end - 1, .end=(cnt).data - 1} \
- ; it.ref != it.end; --it.ref)
-
#define c_forpair(key, val, C, cnt) /* structured binding */ \
for (struct {C##_iter it; const C##_key* key; C##_mapped* val;} _ = {.it=C##_begin(&cnt)} \
; _.it.ref && (_.key = &_.it.ref->first, _.val = &_.it.ref->second) \
diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h
index 056ef005..9892f6f1 100644
--- a/include/stc/cdeq.h
+++ b/include/stc/cdeq.h
@@ -20,16 +20,19 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#include "priv/linkage.h"
+
+#ifndef CDEQ_H_INCLUDED
+#include "ccommon.h"
+#include "forward.h"
+#include <stdlib.h>
+#include <string.h>
+#endif // CDEQ_H_INCLUDED
+
#define _i_prefix cdeq_
#define _pop _pop_front
#define _pull _pull_front
-#ifdef i_more
- #include "cqueue.h"
- #define i_more
-#else
- #define i_more
- #include "cqueue.h"
-#endif
+#include "priv/cqueue_hdr.h"
#undef _pop
STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value);
@@ -122,6 +125,8 @@ _cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw raw)
/* -------------------------- IMPLEMENTATION ------------------------- */
#if defined(i_implement) || defined(i_static)
+#include "priv/cqueue_imp.h"
+
STC_DEF _cx_value*
_cx_MEMB(_push_front)(_cx_Self* self, i_key value) {
intptr_t start = (self->start - 1) & self->capmask;
diff --git a/include/stc/algo/coroutine.h b/include/stc/coroutine.h
index 3a5382f3..42905744 100644
--- a/include/stc/algo/coroutine.h
+++ b/include/stc/coroutine.h
@@ -24,7 +24,7 @@
#define STC_COROUTINE_INCLUDED
/*
#include <stdio.h>
-#include <stc/algo/coroutine.h>
+#include <stc/coroutine.h>
struct iterpair {
int max_x, max_y;
@@ -56,7 +56,7 @@ int main(void) {
return 0;
}
*/
-#include "../ccommon.h"
+#include "ccommon.h"
enum {
CCO_STATE_CLEANUP = -1,
@@ -64,9 +64,8 @@ enum {
};
typedef enum {
CCO_DONE = 0,
- CCO_YIELD = 1,
- CCO_AWAIT = 2,
- CCO_ERROR = -1,
+ CCO_AWAIT = 1<<0,
+ CCO_YIELD = 1<<1,
} cco_result;
#define cco_initial(co) ((co)->cco_state == 0)
@@ -74,7 +73,7 @@ typedef enum {
#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) \
+ 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)
@@ -84,26 +83,27 @@ typedef enum {
case __LINE__:; \
} while (0)
-#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT)
-#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__)
-#define cco_await_v_1(promise) cco_await_v_2(promise, )
-#define cco_await_v_2(promise, ret) \
+#define cco_await(promise) cco_await_and_return(promise, CCO_AWAIT)
+#define cco_await_v(promise) cco_await_and_return(promise, )
+#define cco_await_and_return(promise, ret) \
do { \
*_state = __LINE__; \
case __LINE__: if (!(promise)) {return ret; goto _resume;} \
} while (0)
-/* cco_await_on(): assumes coroutine returns a cco_result value (int) */
-#define cco_await_on(corocall) \
+/* cco_call_await(): assumes coroutine returns a cco_result value (int) */
+#define cco_call_await(...) c_MACRO_OVERLOAD(cco_call_await, __VA_ARGS__)
+#define cco_call_await_1(corocall) cco_call_await_2(corocall, CCO_DONE)
+#define cco_call_await_2(corocall, resultbits) \
do { \
*_state = __LINE__; \
- case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \
+ case __LINE__: { int _r = corocall; if (!(_r & ~(resultbits))) {return _r; goto _resume;} } \
} while (0)
-/* cco_block_on(): assumes coroutine returns a cco_result value (int) */
-#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__)
-#define cco_block_on_1(corocall) while ((corocall) != CCO_DONE)
-#define cco_block_on_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE)
+/* cco_call_blocking(): assumes coroutine returns a cco_result value (int) */
+#define cco_call_blocking(...) c_MACRO_OVERLOAD(cco_call_blocking, __VA_ARGS__)
+#define cco_call_blocking_1(corocall) while ((corocall) != CCO_DONE)
+#define cco_call_blocking_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE)
#define cco_cleanup \
*_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP
@@ -132,26 +132,44 @@ typedef enum {
(void)((co)->cco_state = 0)
/*
- * Closure (optional)
+ * Tasks (optional)
*/
-#define cco_closure(Name, ...) \
+struct cco_runtime;
+
+#define cco_task_struct(Name, ...) \
struct Name { \
- int (*cco_fn)(struct Name*); \
- int cco_state; \
+ int (*cco_func)(struct Name*, struct cco_runtime*); \
+ int cco_state, cco_expect; \
__VA_ARGS__ \
}
-typedef struct cco_base {
- int (*cco_fn)(struct cco_base*);
- int cco_state;
-} cco_base;
+typedef cco_task_struct(cco_task, /**/) cco_task;
+
+typedef struct cco_runtime {
+ int result, top; cco_task* stack[];
+} cco_runtime;
+
+#define cco_cast_task(task) \
+ ((cco_task *)(task) + 0*sizeof((task)->cco_func(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state)))
+
+#define cco_task_resume(task, rt) \
+ (task)->cco_func(task, rt)
-#define cco_resume(closure) \
- (closure)->cco_fn(closure)
+#define cco_task_await(...) c_MACRO_OVERLOAD(cco_task_await, __VA_ARGS__)
+#define cco_task_await_2(task, rt) cco_task_await_3(task, rt, CCO_DONE)
+#define cco_task_await_3(task, rt, resultbits) \
+ do { \
+ cco_runtime* _rt = rt; \
+ (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = (resultbits); \
+ cco_yield_v(CCO_AWAIT); \
+ } while (0)
-#define cco_cast(closure) \
- ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state)))
+#define cco_task_blocking(...) c_MACRO_OVERLOAD(cco_task_blocking, __VA_ARGS__)
+#define cco_task_blocking_1(task) cco_task_blocking_3(task, _rt, 16)
+#define cco_task_blocking_3(task, rt, STACKDEPTH) \
+ for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \
+ (((rt.result = cco_task_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); )
/*
* Semaphore
@@ -159,12 +177,11 @@ typedef struct cco_base {
typedef struct { intptr_t count; } cco_sem;
-#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT)
-#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__)
-#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, )
-#define cco_sem_await_v_2(sem, ret) \
+#define cco_sem_await(sem) cco_sem_await_and_return(sem, CCO_AWAIT)
+#define cco_sem_await_v(sem) cco_sem_await_and_return(sem, )
+#define cco_sem_await_and_return(sem, ret) \
do { \
- cco_await_v_2((sem)->count > 0, ret); \
+ cco_await_and_return((sem)->count > 0, ret); \
--(sem)->count; \
} while (0)
@@ -178,17 +195,22 @@ typedef struct { intptr_t count; } cco_sem;
#ifdef _WIN32
#ifdef __cplusplus
- #define _c_LINKC extern "C" __declspec(dllimport)
+ #define _c_LINKC extern "C" __declspec(dllimport)
+ #else
+ #define _c_LINKC __declspec(dllimport)
+ #endif
+ #if 1 // _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__
+ #define _c_getsystime GetSystemTimeAsFileTime
#else
- #define _c_LINKC __declspec(dllimport)
+ #define _c_getsystime GetSystemTimePreciseAsFileTime
#endif
struct _FILETIME;
- _c_LINKC void GetSystemTimePreciseAsFileTime(struct _FILETIME*);
+ _c_LINKC void _c_getsystime(struct _FILETIME*);
_c_LINKC void Sleep(unsigned long);
static inline double cco_time(void) { /* seconds since epoch */
unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */
- GetSystemTimePreciseAsFileTime((struct _FILETIME*)&quad);
+ _c_getsystime((struct _FILETIME*)&quad);
return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */
}
@@ -219,7 +241,7 @@ typedef struct { double interval, start; } cco_timer;
#define cco_timer_await_v_3(tm, sec, ret) \
do { \
cco_timer_start(tm, sec); \
- cco_await_v_2(cco_timer_expired(tm), ret); \
+ cco_await_and_return(cco_timer_expired(tm), ret); \
} while (0)
static inline void cco_timer_start(cco_timer* tm, double sec) {
diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h
index 5d38ca89..8a609b96 100644
--- a/include/stc/cqueue.h
+++ b/include/stc/cqueue.h
@@ -32,211 +32,11 @@
#ifndef _i_prefix
#define _i_prefix cqueue_
#endif
-#include "priv/template.h"
-
-#ifndef i_is_forward
-_cx_DEFTYPES(_c_cdeq_types, _cx_Self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
-
-STC_API _cx_Self _cx_MEMB(_with_capacity)(const intptr_t n);
-STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n);
-STC_API void _cx_MEMB(_clear)(_cx_Self* self);
-STC_API void _cx_MEMB(_drop)(_cx_Self* self);
-STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); // push_back
-STC_API void _cx_MEMB(_shrink_to_fit)(_cx_Self *self);
-STC_API _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n);
-
-#define _cdeq_toidx(self, pos) (((pos) - (self)->start) & (self)->capmask)
-#define _cdeq_topos(self, idx) (((self)->start + (idx)) & (self)->capmask)
-
-STC_INLINE _cx_Self _cx_MEMB(_init)(void)
- { _cx_Self cx = {0}; return cx; }
-STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n)
- { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); }
-STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n)
- { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; }
-STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); }
-
-#if !defined i_no_emplace
-STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw)
- { return _cx_MEMB(_push)(self, i_keyfrom(raw)); }
-#endif
-
-#if defined _i_has_eq || defined _i_has_cmp
-STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other);
-#endif
-
-#if !defined i_no_clone
-STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx);
-STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val)
- { return i_keyclone(val); }
-#endif // !i_no_clone
-STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self)
- { return _cdeq_toidx(self, self->end); }
-STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self)
- { return self->capmask; }
-STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self)
- { return self->start == self->end; }
-STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval)
- { return i_keyto(pval); }
-
-STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self)
- { return self->data + self->start; }
-
-STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self)
- { return self->data + ((self->end - 1) & self->capmask); }
-
-STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { // pop_front
- c_assert(!_cx_MEMB(_empty)(self));
- i_keydrop((self->data + self->start));
- self->start = (self->start + 1) & self->capmask;
-}
-
-STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { // move front out of queue
- c_assert(!_cx_MEMB(_empty)(self));
- intptr_t s = self->start;
- self->start = (s + 1) & self->capmask;
- return self->data[s];
-}
-
-STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) {
- if (self->data == other->data) return;
- _cx_MEMB(_drop)(self);
- *self = _cx_MEMB(_clone)(*other);
-}
-
-STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) {
- return c_LITERAL(_cx_iter){
- _cx_MEMB(_empty)(self) ? NULL : self->data + self->start,
- self->start, self
- };
-}
-
-STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self)
- { return c_LITERAL(_cx_iter){.pos=self->end, ._s=self}; }
-
-STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) {
- if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; }
- else { it->ref -= it->pos; it->pos = 0; }
- if (it->pos == it->_s->end) it->ref = NULL;
-}
-
-STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it)
- { return _cdeq_toidx(self, it.pos); }
-
-STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n)
- { self->end = (self->end + n) & self->capmask; }
+#include "priv/cqueue_hdr.h"
/* -------------------------- IMPLEMENTATION ------------------------- */
#if defined(i_implement) || defined(i_static)
-
-STC_DEF _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n) {
- intptr_t len = _cx_MEMB(_size)(it._s);
- intptr_t pos = it.pos, idx = _cdeq_toidx(it._s, pos);
- it.pos = (pos + n) & it._s->capmask;
- it.ref += it.pos - pos;
- if (!c_LTu(idx + n, len)) it.ref = NULL;
- return it;
-}
-
-STC_DEF void
-_cx_MEMB(_clear)(_cx_Self* self) {
- c_foreach (i, _cx_Self, *self)
- { i_keydrop(i.ref); }
- self->start = 0, self->end = 0;
-}
-
-STC_DEF void
-_cx_MEMB(_drop)(_cx_Self* self) {
- _cx_MEMB(_clear)(self);
- i_free(self->data);
-}
-
-STC_DEF _cx_Self
-_cx_MEMB(_with_capacity)(const intptr_t n) {
- _cx_Self cx = {0};
- _cx_MEMB(_reserve)(&cx, n);
- return cx;
-}
-
-STC_DEF bool
-_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n) {
- if (n <= self->capmask)
- return true;
- intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1);
- _cx_value* d = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data);
- if (!d)
- return false;
- intptr_t head = oldcap - self->start;
- if (self->start <= self->end)
- ;
- else if (head < self->end) {
- self->start = newcap - head;
- c_memmove(d + self->start, d + oldcap - head, head*c_sizeof *d);
- } else {
- c_memmove(d + oldcap, d, self->end*c_sizeof *d);
- self->end += oldcap;
- }
- self->capmask = newcap - 1;
- self->data = d;
- return true;
-}
-
-STC_DEF _cx_value*
-_cx_MEMB(_push)(_cx_Self* self, i_key value) { // push_back
- intptr_t end = (self->end + 1) & self->capmask;
- if (end == self->start) { // full
- _cx_MEMB(_reserve)(self, self->capmask + 3); // => 2x expand
- end = (self->end + 1) & self->capmask;
- }
- _cx_value *v = self->data + self->end;
- self->end = end;
- *v = value;
- return v;
-}
-
-STC_DEF void
-_cx_MEMB(_shrink_to_fit)(_cx_Self *self) {
- intptr_t sz = _cx_MEMB(_size)(self), j = 0;
- if (sz > self->capmask/2)
- return;
- _cx_Self out = _cx_MEMB(_with_capacity)(sz);
- if (!out.data)
- return;
- c_foreach (i, _cx_Self, *self)
- out.data[j++] = *i.ref;
- out.end = sz;
- i_free(self->data);
- *self = out;
-}
-
-#if !defined i_no_clone
-STC_DEF _cx_Self
-_cx_MEMB(_clone)(_cx_Self cx) {
- intptr_t sz = _cx_MEMB(_size)(&cx), j = 0;
- _cx_Self out = _cx_MEMB(_with_capacity)(sz);
- if (out.data)
- c_foreach (i, _cx_Self, cx)
- out.data[j++] = i_keyclone((*i.ref));
- out.end = sz;
- return out;
-}
-#endif // i_no_clone
-
-#if defined _i_has_eq || defined _i_has_cmp
-STC_DEF bool
-_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
- if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false;
- for (_cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other);
- i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j))
- {
- const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref);
- if (!(i_eq((&_rx), (&_ry)))) return false;
- }
- return true;
-}
-#endif
+#include "priv/cqueue_imp.h"
#endif // IMPLEMENTATION
-#include "priv/template2.h"
#define CQUEUE_H_INCLUDED
+#include "priv/template2.h"
diff --git a/include/stc/crand.h b/include/stc/crand.h
index 0a6aa9e0..32722762 100644
--- a/include/stc/crand.h
+++ b/include/stc/crand.h
@@ -32,20 +32,20 @@
int main(void) {
uint64_t seed = 123456789;
crand_t rng = crand_init(seed);
- crand_unif_t dist1 = crand_unif_init(1, 6);
- crand_norm_t dist3 = crand_norm_init(1.0, 10.0);
+ crand_uniform_t dist1 = crand_uniform_init(1, 6);
+ crand_normal_t dist3 = crand_normal_init(1.0, 10.0);
uint64_t i = crand_u64(&rng);
- int64_t iu = crand_unif(&rng, &dist1);
- double xn = crand_norm(&rng, &dist3);
+ int64_t iu = crand_uniform(&rng, &dist1);
+ double xn = crand_normal(&rng, &dist3);
}
*/
#include <string.h>
#include <math.h>
typedef struct crand { uint64_t state[5]; } crand_t;
-typedef struct crand_unif { int64_t lower; uint64_t range, threshold; } crand_unif_t;
-typedef struct crand_norm { double mean, stddev, next; int has_next; } crand_norm_t;
+typedef struct crand_uniform { int64_t lower; uint64_t range, threshold; } crand_uniform_t;
+typedef struct crand_normal { double mean, stddev, next; int has_next; } crand_normal_t;
/* PRNG crand_t.
* Very fast PRNG suited for parallel usage with Weyl-sequence parameter.
@@ -67,14 +67,14 @@ STC_API double crandf(void);
STC_API crand_t crand_init(uint64_t seed);
/* Unbiased bounded uniform distribution. range [low, high] */
-STC_API crand_unif_t crand_unif_init(int64_t low, int64_t high);
-STC_API int64_t crand_unif(crand_t* rng, crand_unif_t* dist);
+STC_API crand_uniform_t crand_uniform_init(int64_t low, int64_t high);
+STC_API int64_t crand_uniform(crand_t* rng, crand_uniform_t* dist);
/* Normal/gaussian distribution. */
-STC_INLINE crand_norm_t crand_norm_init(double mean, double stddev)
- { crand_norm_t r = {mean, stddev, 0.0, 0}; return r; }
+STC_INLINE crand_normal_t crand_normal_init(double mean, double stddev)
+ { crand_normal_t r = {mean, stddev, 0.0, 0}; return r; }
-STC_API double crand_norm(crand_t* rng, crand_norm_t* dist);
+STC_API double crand_normal(crand_t* rng, crand_normal_t* dist);
/* Main crand_t prng */
STC_INLINE uint64_t crand_u64(crand_t* rng) {
@@ -95,11 +95,10 @@ STC_INLINE double crand_f64(crand_t* rng) {
/* -------------------------- IMPLEMENTATION ------------------------- */
#if defined(i_implement) || defined(i_static)
-/* Global random() */
-static crand_t crand_global = {{
- 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04,
- 0x504f333d3aa0b359, 0x9e3779b97f4a7c15,
- 0x6a09e667a754166b
+/* Global random seed */
+static crand_t crand_global = {{ // csrand(0)
+ 0x9e3779b97f4a7c15, 0x6f68261b57e7a770,
+ 0xe220a838bf5c9dde, 0x7c17d1800457b1ba, 0x1,
}};
STC_DEF void csrand(uint64_t seed)
@@ -116,20 +115,20 @@ STC_DEF crand_t crand_init(uint64_t seed) {
s[0] = seed + 0x9e3779b97f4a7c15;
s[1] = (s[0] ^ (s[0] >> 30))*0xbf58476d1ce4e5b9;
s[2] = (s[1] ^ (s[1] >> 27))*0x94d049bb133111eb;
- s[3] = (s[2] ^ (s[2] >> 31));
- s[4] = ((seed + 0x6aa069ea2fb1a4d) << 1) | 1;
+ s[3] = s[0] ^ s[2] ^ (s[2] >> 31);
+ s[4] = (seed << 1) | 1;
return rng;
}
/* Init unbiased uniform uint RNG with bounds [low, high] */
-STC_DEF crand_unif_t crand_unif_init(int64_t low, int64_t high) {
- crand_unif_t dist = {low, (uint64_t) (high - low + 1)};
+STC_DEF crand_uniform_t crand_uniform_init(int64_t low, int64_t high) {
+ crand_uniform_t dist = {low, (uint64_t) (high - low + 1)};
dist.threshold = (uint64_t)(0 - dist.range) % dist.range;
return dist;
}
/* Int64 uniform distributed RNG, range [low, high]. */
-STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) {
+STC_DEF int64_t crand_uniform(crand_t* rng, crand_uniform_t* d) {
uint64_t lo, hi;
#ifdef c_umul128
do { c_umul128(crand_u64(rng), d->range, &lo, &hi); } while (lo < d->threshold);
@@ -140,7 +139,7 @@ STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) {
}
/* Normal distribution PRNG. Marsaglia polar method */
-STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) {
+STC_DEF double crand_normal(crand_t* rng, crand_normal_t* dist) {
double u1, u2, s, m;
if (dist->has_next++ & 1)
return dist->next*dist->stddev + dist->mean;
diff --git a/include/stc/cspan.h b/include/stc/cspan.h
index dcb02961..08045010 100644
--- a/include/stc/cspan.h
+++ b/include/stc/cspan.h
@@ -80,19 +80,19 @@ int demo2() {
STC_INLINE Self Self##_from_n(Self##_raw* raw, const intptr_t n) { \
return (Self){.data=raw, .shape={(int32_t)n}}; \
} \
- STC_INLINE Self Self##_slice_(Self##_value* v, const int32_t shape[], const int32_t stri[], \
+ STC_INLINE Self Self##_slice_(Self##_value* d, const int32_t shape[], const int32_t stri[], \
const int rank, const int32_t a[][2]) { \
- Self s; s.data = v; int outrank; \
- s.data += _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \
+ Self s; int outrank; \
+ s.data = d + _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \
c_assert(outrank == RANK); \
return s; \
} \
STC_INLINE Self##_iter Self##_begin(const Self* self) { \
- Self##_iter it = {.ref=self->data, .pos={0}, ._s=self}; \
+ Self##_iter it = {.ref=self->data, ._s=self}; \
return it; \
} \
STC_INLINE Self##_iter Self##_end(const Self* self) { \
- Self##_iter it = {.ref=NULL}; \
+ Self##_iter it = {0}; \
return it; \
} \
STC_INLINE void Self##_next(Self##_iter* it) { \
@@ -120,7 +120,7 @@ using_cspan_tuple(7); using_cspan_tuple(8);
#define cspan_init(SpanType, ...) \
{.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}, .stride={.d={1}}}
-/* create a cspan from a cvec, cstack, cdeq, cqueue, or cpque (heap) */
+/* create a cspan from a cvec, cstack, or cpque (heap) */
#define cspan_from(container) \
{.data=(container)->data, .shape={(int32_t)(container)->_len}, .stride={.d={1}}}
diff --git a/include/stc/cstr.h b/include/stc/cstr.h
index 17943ad5..2648e267 100644
--- a/include/stc/cstr.h
+++ b/include/stc/cstr.h
@@ -170,14 +170,14 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self)
// utf8 methods defined in/depending on src/utf8code.c:
-STC_API cstr cstr_casefold_sv(csview sv);
-STC_API cstr cstr_tolower_sv(csview sv);
-STC_API cstr cstr_toupper_sv(csview sv);
-STC_API cstr cstr_tolower(const char* str);
-STC_API cstr cstr_toupper(const char* str);
-STC_API void cstr_lowercase(cstr* self);
-STC_API void cstr_uppercase(cstr* self);
-STC_API bool cstr_valid_utf8(const cstr* self);
+extern cstr cstr_casefold_sv(csview sv);
+extern cstr cstr_tolower_sv(csview sv);
+extern cstr cstr_toupper_sv(csview sv);
+extern cstr cstr_tolower(const char* str);
+extern cstr cstr_toupper(const char* str);
+extern void cstr_lowercase(cstr* self);
+extern void cstr_uppercase(cstr* self);
+extern bool cstr_valid_utf8(const cstr* self);
// other utf8
@@ -394,7 +394,7 @@ fn_tocase[] = {{tolower, utf8_casefold},
{tolower, utf8_tolower},
{toupper, utf8_toupper}};
-STC_DEF cstr cstr_tocase(csview sv, int k) {
+static cstr cstr_tocase(csview sv, int k) {
cstr out = cstr_init();
char *buf = cstr_reserve(&out, sv.size*3/2);
const char *end = sv.str + sv.size;
@@ -415,28 +415,28 @@ STC_DEF cstr cstr_tocase(csview sv, int k) {
return out;
}
-STC_DEF cstr cstr_casefold_sv(csview sv)
+cstr cstr_casefold_sv(csview sv)
{ return cstr_tocase(sv, 0); }
-STC_DEF cstr cstr_tolower_sv(csview sv)
+cstr cstr_tolower_sv(csview sv)
{ return cstr_tocase(sv, 1); }
-STC_DEF cstr cstr_toupper_sv(csview sv)
+cstr cstr_toupper_sv(csview sv)
{ return cstr_tocase(sv, 2); }
-STC_DEF cstr cstr_tolower(const char* str)
+cstr cstr_tolower(const char* str)
{ return cstr_tolower_sv(c_sv(str, c_strlen(str))); }
-STC_DEF cstr cstr_toupper(const char* str)
+cstr cstr_toupper(const char* str)
{ return cstr_toupper_sv(c_sv(str, c_strlen(str))); }
-STC_DEF void cstr_lowercase(cstr* self)
+void cstr_lowercase(cstr* self)
{ cstr_take(self, cstr_tolower_sv(cstr_sv(self))); }
-STC_DEF void cstr_uppercase(cstr* self)
+void cstr_uppercase(cstr* self)
{ cstr_take(self, cstr_toupper_sv(cstr_sv(self))); }
-STC_DEF bool cstr_valid_utf8(const cstr* self)
+bool cstr_valid_utf8(const cstr* self)
{ return utf8_valid(cstr_str(self)); }
#endif // i_import
diff --git a/include/stc/priv/cqueue_hdr.h b/include/stc/priv/cqueue_hdr.h
new file mode 100644
index 00000000..90539f36
--- /dev/null
+++ b/include/stc/priv/cqueue_hdr.h
@@ -0,0 +1,117 @@
+/* MIT License
+ *
+ * Copyright (c) 2023 Tyge Løvset
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "template.h"
+#ifndef i_is_forward
+_cx_DEFTYPES(_c_cdeq_types, _cx_Self, i_key);
+#endif
+typedef i_keyraw _cx_raw;
+
+STC_API _cx_Self _cx_MEMB(_with_capacity)(const intptr_t n);
+STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n);
+STC_API void _cx_MEMB(_clear)(_cx_Self* self);
+STC_API void _cx_MEMB(_drop)(_cx_Self* self);
+STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value); // push_back
+STC_API void _cx_MEMB(_shrink_to_fit)(_cx_Self *self);
+STC_API _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n);
+
+#define _cdeq_toidx(self, pos) (((pos) - (self)->start) & (self)->capmask)
+#define _cdeq_topos(self, idx) (((self)->start + (idx)) & (self)->capmask)
+
+STC_INLINE _cx_Self _cx_MEMB(_init)(void)
+ { _cx_Self cx = {0}; return cx; }
+STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n)
+ { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); }
+STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n)
+ { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; }
+STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); }
+
+#if !defined i_no_emplace
+STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw)
+ { return _cx_MEMB(_push)(self, i_keyfrom(raw)); }
+#endif
+
+#if defined _i_has_eq || defined _i_has_cmp
+STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other);
+#endif
+
+#if !defined i_no_clone
+STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx);
+STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val)
+ { return i_keyclone(val); }
+#endif // !i_no_clone
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self)
+ { return _cdeq_toidx(self, self->end); }
+STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self)
+ { return self->capmask; }
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self)
+ { return self->start == self->end; }
+STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval)
+ { return i_keyto(pval); }
+
+STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self)
+ { return self->data + self->start; }
+
+STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self)
+ { return self->data + ((self->end - 1) & self->capmask); }
+
+STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self) { // pop_front
+ c_assert(!_cx_MEMB(_empty)(self));
+ i_keydrop((self->data + self->start));
+ self->start = (self->start + 1) & self->capmask;
+}
+
+STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self) { // move front out of queue
+ c_assert(!_cx_MEMB(_empty)(self));
+ intptr_t s = self->start;
+ self->start = (s + 1) & self->capmask;
+ return self->data[s];
+}
+
+STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) {
+ if (self->data == other->data) return;
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_clone)(*other);
+}
+
+STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) {
+ return c_LITERAL(_cx_iter){
+ _cx_MEMB(_empty)(self) ? NULL : self->data + self->start,
+ self->start, self
+ };
+}
+
+STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self)
+ { return c_LITERAL(_cx_iter){.pos=self->end, ._s=self}; }
+
+STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) {
+ if (it->pos != it->_s->capmask) { ++it->ref; ++it->pos; }
+ else { it->ref -= it->pos; it->pos = 0; }
+ if (it->pos == it->_s->end) it->ref = NULL;
+}
+
+STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it)
+ { return _cdeq_toidx(self, it.pos); }
+
+STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n)
+ { self->end = (self->end + n) & self->capmask; }
diff --git a/include/stc/priv/cqueue_imp.h b/include/stc/priv/cqueue_imp.h
new file mode 100644
index 00000000..2ad9c811
--- /dev/null
+++ b/include/stc/priv/cqueue_imp.h
@@ -0,0 +1,129 @@
+/* MIT License
+ *
+ * Copyright (c) 2023 Tyge Løvset
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+STC_DEF _cx_iter _cx_MEMB(_advance)(_cx_iter it, intptr_t n) {
+ intptr_t len = _cx_MEMB(_size)(it._s);
+ intptr_t pos = it.pos, idx = _cdeq_toidx(it._s, pos);
+ it.pos = (pos + n) & it._s->capmask;
+ it.ref += it.pos - pos;
+ if (!c_LTu(idx + n, len)) it.ref = NULL;
+ return it;
+}
+
+STC_DEF void
+_cx_MEMB(_clear)(_cx_Self* self) {
+ c_foreach (i, _cx_Self, *self)
+ { i_keydrop(i.ref); }
+ self->start = 0, self->end = 0;
+}
+
+STC_DEF void
+_cx_MEMB(_drop)(_cx_Self* self) {
+ _cx_MEMB(_clear)(self);
+ i_free(self->data);
+}
+
+STC_DEF _cx_Self
+_cx_MEMB(_with_capacity)(const intptr_t n) {
+ _cx_Self cx = {0};
+ _cx_MEMB(_reserve)(&cx, n);
+ return cx;
+}
+
+STC_DEF bool
+_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t n) {
+ if (n <= self->capmask)
+ return true;
+ intptr_t oldcap = self->capmask + 1, newcap = cnextpow2(n + 1);
+ _cx_value* d = (_cx_value *)i_realloc(self->data, newcap*c_sizeof *self->data);
+ if (!d)
+ return false;
+ intptr_t head = oldcap - self->start;
+ if (self->start <= self->end)
+ ;
+ else if (head < self->end) {
+ self->start = newcap - head;
+ c_memmove(d + self->start, d + oldcap - head, head*c_sizeof *d);
+ } else {
+ c_memmove(d + oldcap, d, self->end*c_sizeof *d);
+ self->end += oldcap;
+ }
+ self->capmask = newcap - 1;
+ self->data = d;
+ return true;
+}
+
+STC_DEF _cx_value*
+_cx_MEMB(_push)(_cx_Self* self, i_key value) { // push_back
+ intptr_t end = (self->end + 1) & self->capmask;
+ if (end == self->start) { // full
+ _cx_MEMB(_reserve)(self, self->capmask + 3); // => 2x expand
+ end = (self->end + 1) & self->capmask;
+ }
+ _cx_value *v = self->data + self->end;
+ self->end = end;
+ *v = value;
+ return v;
+}
+
+STC_DEF void
+_cx_MEMB(_shrink_to_fit)(_cx_Self *self) {
+ intptr_t sz = _cx_MEMB(_size)(self), j = 0;
+ if (sz > self->capmask/2)
+ return;
+ _cx_Self out = _cx_MEMB(_with_capacity)(sz);
+ if (!out.data)
+ return;
+ c_foreach (i, _cx_Self, *self)
+ out.data[j++] = *i.ref;
+ out.end = sz;
+ i_free(self->data);
+ *self = out;
+}
+
+#if !defined i_no_clone
+STC_DEF _cx_Self
+_cx_MEMB(_clone)(_cx_Self cx) {
+ intptr_t sz = _cx_MEMB(_size)(&cx), j = 0;
+ _cx_Self out = _cx_MEMB(_with_capacity)(sz);
+ if (out.data)
+ c_foreach (i, _cx_Self, cx)
+ out.data[j++] = i_keyclone((*i.ref));
+ out.end = sz;
+ return out;
+}
+#endif // i_no_clone
+
+#if defined _i_has_eq || defined _i_has_cmp
+STC_DEF bool
+_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false;
+ for (_cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other);
+ i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j))
+ {
+ const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref);
+ if (!(i_eq((&_rx), (&_ry)))) return false;
+ }
+ return true;
+}
+#endif
diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h
index 30ed5732..ccdce718 100644
--- a/include/stc/priv/template.h
+++ b/include/stc/priv/template.h
@@ -103,7 +103,7 @@
#define i_no_emplace
#endif
#if c_option(c_native_cmp)
- #define i_native_cmp
+ #define i_cmp_native
#endif
#if c_option(c_no_clone) || defined _i_carc
#define i_no_clone
@@ -203,10 +203,10 @@
#endif
#ifndef i_no_cmp
- #if defined i_cmp || defined i_less || defined i_native_cmp
+ #if defined i_cmp || defined i_less || defined i_cmp_native
#define _i_has_cmp
#endif
- #if defined i_eq || defined i_native_cmp
+ #if defined i_eq || defined i_cmp_native
#define _i_has_eq
#endif
@@ -228,7 +228,7 @@
#endif
#endif
-#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_native_cmp)
+#if !defined i_hash && (!(defined _i_cbox || defined _i_carc) || defined i_cmp_native)
#define i_hash c_default_hash
#endif
diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h
index def5d01e..351defde 100644
--- a/include/stc/priv/template2.h
+++ b/include/stc/priv/template2.h
@@ -67,7 +67,7 @@
#undef i_realloc
#undef i_free
-#undef i_native_cmp
+#undef i_cmp_native
#undef i_no_cmp
#undef i_no_hash
#undef i_no_clone
diff --git a/misc/benchmarks/plotbench/cvec_benchmark.cpp b/misc/benchmarks/plotbench/cvec_benchmark.cpp
index 3b4c3d7d..45b9cf93 100644
--- a/misc/benchmarks/plotbench/cvec_benchmark.cpp
+++ b/misc/benchmarks/plotbench/cvec_benchmark.cpp
@@ -71,18 +71,18 @@ Sample test_stc_vector() {
s.test[INSERT].t1 = clock();
container con = cvec_x_init();
csrand(seed);
- c_forrange (N) cvec_x_push_back(&con, crand() & mask1);
+ c_forrange (N) cvec_x_push(&con, crand() & mask1);
s.test[INSERT].t2 = clock();
s.test[INSERT].sum = cvec_x_size(&con);
s.test[ERASE].t1 = clock();
- c_forrange (N) { cvec_x_pop_back(&con); }
+ c_forrange (N) { cvec_x_pop(&con); }
s.test[ERASE].t2 = clock();
s.test[ERASE].sum = cvec_x_size(&con);
cvec_x_drop(&con);
}{
csrand(seed);
container con = cvec_x_init();
- c_forrange (N) cvec_x_push_back(&con, crand() & mask2);
+ c_forrange (N) cvec_x_push(&con, crand() & mask2);
s.test[FIND].t1 = clock();
size_t sum = 0;
//cvec_x_iter it, end = cvec_x_end(&con);
diff --git a/misc/benchmarks/plotbench/plot.py b/misc/benchmarks/plotbench/plot.py
index e65631b7..8e684ccc 100644
--- a/misc/benchmarks/plotbench/plot.py
+++ b/misc/benchmarks/plotbench/plot.py
@@ -4,7 +4,7 @@ import pandas as pd
import matplotlib.pyplot as plt
#sns.set_theme(style="whitegrid")
-comp = ['All compilers', 'Mingw-g++-11.3.0', 'Win-Clang-14.0.1', 'VC-19.28']
+comp = ['All compilers', 'Mingw-g++-13.1.0', 'Win-Clang-16.0.5', 'VC-19.36']
n = int(sys.argv[1]) if len(sys.argv) > 1 else 0
file = sys.argv[2] if len(sys.argv) > 2 else 'plot_win.csv'
df = pd.read_csv(file)
diff --git a/misc/benchmarks/plotbench/run_all.bat b/misc/benchmarks/plotbench/run_all.bat
index 98913a50..23a62eed 100644
--- a/misc/benchmarks/plotbench/run_all.bat
+++ b/misc/benchmarks/plotbench/run_all.bat
@@ -4,4 +4,4 @@ echo gcc
sh run_gcc.sh >> %out%
echo clang
sh run_clang.sh >> %out%
-REM call run_vc.bat >> %out%
+call run_vc.bat >> %out%
diff --git a/misc/benchmarks/plotbench/run_clang.sh b/misc/benchmarks/plotbench/run_clang.sh
index 59d577d9..fc3e90ec 100644
--- a/misc/benchmarks/plotbench/run_clang.sh
+++ b/misc/benchmarks/plotbench/run_clang.sh
@@ -6,7 +6,7 @@ clang++ -DNDEBUG -I../../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp
clang++ -DNDEBUG -I../../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp
clang++ -DNDEBUG -I../../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp
-c='Win-Clang-14.0.1'
+c='Win-Clang-16.0.5'
./cdeq_benchmark$exe $c
./clist_benchmark$exe $c
./cmap_benchmark$exe $c
diff --git a/misc/benchmarks/plotbench/run_gcc.sh b/misc/benchmarks/plotbench/run_gcc.sh
index 73b979d3..0bd2d6ee 100644
--- a/misc/benchmarks/plotbench/run_gcc.sh
+++ b/misc/benchmarks/plotbench/run_gcc.sh
@@ -4,7 +4,7 @@ g++ -DNDEBUG -I../../include -O3 -o cmap_benchmark cmap_benchmark.cpp
g++ -DNDEBUG -I../../include -O3 -o csmap_benchmark csmap_benchmark.cpp
g++ -DNDEBUG -I../../include -O3 -o cvec_benchmark cvec_benchmark.cpp
-c='Mingw-g++-11.3.0'
+c='Mingw-g++-13.1.0'
./cdeq_benchmark $c
./clist_benchmark $c
./cmap_benchmark $c
diff --git a/misc/benchmarks/plotbench/run_vc.bat b/misc/benchmarks/plotbench/run_vc.bat
index dc4938f8..a162fb64 100644
--- a/misc/benchmarks/plotbench/run_vc.bat
+++ b/misc/benchmarks/plotbench/run_vc.bat
@@ -6,9 +6,9 @@ cl.exe -nologo -EHsc -std:c++latest -I../include -O2 clist_benchmark.cpp >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cmap_benchmark.cpp >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 csmap_benchmark.cpp >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cvec_benchmark.cpp >nul
-del *.obj >nul
+if exist *obj del *.obj
-set c=VC-19.28
+set c=VC-19.36
cdeq_benchmark.exe %c%
clist_benchmark.exe %c%
cmap_benchmark.exe %c%
diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c
index f6b7f1db..793a0503 100644
--- a/misc/benchmarks/various/csort_bench.c
+++ b/misc/benchmarks/various/csort_bench.c
@@ -48,7 +48,7 @@ int main(int argc, char *argv[]) {
Ints a = Ints_with_capacity(size);
for (i = 0; i < size; i++)
- *Ints_push(&a, romutrio(s) & (1U << 30) - 1);
+ Ints_push(&a, romutrio(s) & (1U << 30) - 1);
testsort(&a, size, "random");
for (i = 0; i < 20; i++)
printf(" %d", (int)*Ints_at(&a, i));
diff --git a/misc/examples/forfilter.c b/misc/examples/algorithms/forfilter.c
index f3c008b3..c1426045 100644
--- a/misc/examples/forfilter.c
+++ b/misc/examples/algorithms/forfilter.c
@@ -3,8 +3,7 @@
#include <stc/cstr.h>
#define i_implement
#include <stc/csview.h>
-#include <stc/algo/filter.h>
-#include <stc/algo/crange.h>
+#include <stc/algorithm.h>
#define i_type IVec
#define i_key int
@@ -55,7 +54,7 @@ fn main() {
void demo2(void)
{
IVec vector = {0};
- crange r = crange_make(INT64_MAX);
+ crange r = crange_init(INT64_MAX);
c_forfilter (x, crange, r,
c_flt_skipwhile(x, *x.ref != 11) &&
(*x.ref % 2) != 0 &&
@@ -125,7 +124,7 @@ void demo5(void)
{
#define flt_even(i) ((*i.ref & 1) == 0)
#define flt_mid_decade(i) ((*i.ref % 10) != 0)
- crange R = crange_make(1963, INT32_MAX);
+ crange R = crange_init(1963, INT32_MAX);
c_forfilter (i, crange, R,
c_flt_skip(i,15) &&
diff --git a/misc/examples/forloops.c b/misc/examples/algorithms/forloops.c
index 47cced8f..a83d4a53 100644
--- a/misc/examples/forloops.c
+++ b/misc/examples/algorithms/forloops.c
@@ -1,69 +1,65 @@
-#include <stdio.h>
-#include <stc/algo/filter.h>
-
-#define i_type IVec
-#define i_key int
-#include <stc/cstack.h>
-
-#define i_type IMap
-#define i_key int
-#define i_val int
-#include <stc/cmap.h>
-
-
-int main(void)
-{
- puts("c_forrange:");
- c_forrange (30) printf(" xx");
- puts("");
-
- c_forrange (i, 30) printf(" %lld", i);
- puts("");
-
- c_forrange (i, 30, 60) printf(" %lld", i);
- puts("");
-
- c_forrange (i, 30, 90, 2) printf(" %lld", i);
-
- puts("\n\nc_forlist:");
- c_forlist (i, int, {12, 23, 453, 65, 676})
- printf(" %d", *i.ref);
- puts("");
-
- c_forlist (i, const char*, {"12", "23", "453", "65", "676"})
- printf(" %s", *i.ref);
- puts("");
-
- IVec vec = c_init(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199});
- IMap map = c_init(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}});
-
- puts("\n\nc_foreach:");
- c_foreach (i, IVec, vec)
- printf(" %d", *i.ref);
-
- puts("\n\nc_foreach_r: reverse");
- c_foreach_rv (i, IVec, vec)
- printf(" %d", *i.ref);
-
- puts("\n\nc_foreach in map:");
- c_foreach (i, IMap, map)
- printf(" (%d %d)", i.ref->first, i.ref->second);
-
- puts("\n\nc_forpair:");
- c_forpair (key, val, IMap, map)
- printf(" (%d %d)", *_.key, *_.val);
-
- #define isOdd(i) (*i.ref & 1)
-
- puts("\n\nc_forfilter:");
- c_forfilter (i, IVec, vec,
- isOdd(i) &&
- c_flt_skip(i, 4) &&
- c_flt_take(i, 4)
- ){
- printf(" %d", *i.ref);
- }
-
- IVec_drop(&vec);
- IMap_drop(&map);
-}
+#include <stdio.h>
+#include <stc/algorithm.h>
+
+#define i_type IVec
+#define i_key int
+#include <stc/cstack.h>
+
+#define i_type IMap
+#define i_key int
+#define i_val int
+#include <stc/cmap.h>
+
+
+int main(void)
+{
+ puts("c_forrange:");
+ c_forrange (30) printf(" xx");
+ puts("");
+
+ c_forrange (i, 30) printf(" %lld", i);
+ puts("");
+
+ c_forrange (i, 30, 60) printf(" %lld", i);
+ puts("");
+
+ c_forrange (i, 30, 90, 2) printf(" %lld", i);
+
+ puts("\n\nc_forlist:");
+ c_forlist (i, int, {12, 23, 453, 65, 676})
+ printf(" %d", *i.ref);
+ puts("");
+
+ c_forlist (i, const char*, {"12", "23", "453", "65", "676"})
+ printf(" %s", *i.ref);
+ puts("");
+
+ IVec vec = c_init(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199});
+ IMap map = c_init(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}});
+
+ puts("\n\nc_foreach:");
+ c_foreach (i, IVec, vec)
+ printf(" %d", *i.ref);
+
+ puts("\n\nc_foreach in map:");
+ c_foreach (i, IMap, map)
+ printf(" (%d %d)", i.ref->first, i.ref->second);
+
+ puts("\n\nc_forpair:");
+ c_forpair (key, val, IMap, map)
+ printf(" (%d %d)", *_.key, *_.val);
+
+ #define isOdd(i) (*i.ref & 1)
+
+ puts("\n\nc_forfilter:");
+ c_forfilter (i, IVec, vec,
+ isOdd(i) &&
+ c_flt_skip(i, 4) &&
+ c_flt_take(i, 4)
+ ){
+ printf(" %d", *i.ref);
+ }
+
+ IVec_drop(&vec);
+ IMap_drop(&map);
+}
diff --git a/misc/examples/random.c b/misc/examples/algorithms/random.c
index a36b2389..9522c16d 100644
--- a/misc/examples/random.c
+++ b/misc/examples/algorithms/random.c
@@ -4,11 +4,11 @@
int main(void)
{
- const int N = 10000000;
+ const long long N = 10000000;
const uint64_t seed = (uint64_t)time(NULL), range = 1000000;
crand_t rng = crand_init(seed);
- int64_t sum;
+ long long sum;
clock_t diff, before;
printf("Compare speed of full and unbiased ranged random numbers...\n");
@@ -18,19 +18,19 @@ int main(void)
sum += (uint32_t)crand_u64(&rng);
}
diff = clock() - before;
- printf("full range\t\t: %f secs, %d, avg: %f\n",
- (double)diff/CLOCKS_PER_SEC, N, (double)sum/N);
+ printf("full range\t\t: %f secs, %lld, avg: %f\n",
+ (double)diff/(double)CLOCKS_PER_SEC, N, (double)(sum/N));
- crand_unif_t dist1 = crand_unif_init(0, range);
+ crand_uniform_t dist1 = crand_uniform_init(0, range);
rng = crand_init(seed);
sum = 0;
before = clock();
c_forrange (N) {
- sum += crand_unif(&rng, &dist1); // unbiased
+ sum += crand_uniform(&rng, &dist1); // unbiased
}
diff = clock() - before;
- printf("unbiased 0-%" PRIu64 "\t: %f secs, %d, avg: %f\n",
- range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N);
+ printf("unbiased 0-%lld\t: %f secs, %lld, avg: %f\n",
+ (long long)range, (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N));
sum = 0;
rng = crand_init(seed);
@@ -39,7 +39,7 @@ int main(void)
sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased
}
diff = clock() - before;
- printf("biased 0-%" PRIu64 " \t: %f secs, %d, avg: %f\n",
- range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N);
+ printf("biased 0-%" PRIu64 " \t: %f secs, %lld, avg: %f\n",
+ (long long)range, (double)diff/CLOCKS_PER_SEC, N, (double)(sum/N));
}
diff --git a/misc/examples/shape.c b/misc/examples/algorithms/shape.c
index bd4bdd5a..bd4bdd5a 100644
--- a/misc/examples/shape.c
+++ b/misc/examples/algorithms/shape.c
diff --git a/misc/examples/shape.cpp b/misc/examples/algorithms/shape.cpp
index ea1f53d2..ea1f53d2 100644
--- a/misc/examples/shape.cpp
+++ b/misc/examples/algorithms/shape.cpp
diff --git a/misc/examples/bits.c b/misc/examples/bitsets/bits.c
index e0a11346..e0a11346 100644
--- a/misc/examples/bits.c
+++ b/misc/examples/bitsets/bits.c
diff --git a/misc/examples/bits2.c b/misc/examples/bitsets/bits2.c
index de2f16f4..de2f16f4 100644
--- a/misc/examples/bits2.c
+++ b/misc/examples/bitsets/bits2.c
diff --git a/misc/examples/prime.c b/misc/examples/bitsets/prime.c
index e7b3d993..7e5a2b3f 100644
--- a/misc/examples/prime.c
+++ b/misc/examples/bitsets/prime.c
@@ -2,12 +2,10 @@
#include <math.h>
#include <time.h>
#include <stc/cbits.h>
-#include <stc/algo/filter.h>
-#include <stc/algo/crange.h>
+#include <stc/algorithm.h>
typedef long long llong;
-
cbits sieveOfEratosthenes(llong n)
{
cbits bits = cbits_with_size(n/2 + 1, true);
@@ -28,17 +26,16 @@ 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();
+ t = clock() - t;
- printf("Number of primes: %lld, time: %f\n\n", np, (float)(t2 - t1) / (float)CLOCKS_PER_SEC);
+ printf("Number of primes: %lld, time: %f\n\n", np, (double)t/CLOCKS_PER_SEC);
puts("Show all the primes in the range [2, 1000):");
printf("2");
@@ -47,7 +44,7 @@ int main(void)
puts("\n");
puts("Show the last 50 primes using a temporary crange generator:");
- crange range = crange_make(n - 1, 0, -2);
+ crange range = crange_init(n - 1, 0, -2);
c_forfilter (i, crange, range,
cbits_test(&primes, *i.ref/2) &&
diff --git a/misc/examples/cointerleave.c b/misc/examples/coroutines/cointerleave.c
index 599ceaab..f3710ba3 100644
--- a/misc/examples/cointerleave.c
+++ b/misc/examples/coroutines/cointerleave.c
@@ -1,6 +1,6 @@
// https://www.youtube.com/watch?v=8sEe-4tig_A
#include <stdio.h>
-#include <stc/calgo.h>
+#include <stc/coroutine.h>
#define i_type IVec
#define i_key int
#include <stc/cvec.h>
@@ -49,7 +49,7 @@ void Use(void)
struct Generator g = {{&a}, {&b}};
- cco_block_on(interleaved(&g)) {
+ cco_call_blocking(interleaved(&g)) {
printf("%d ", g.value);
}
puts("");
diff --git a/misc/examples/coread.c b/misc/examples/coroutines/coread.c
index a13f6be5..ebaaf19d 100644
--- a/misc/examples/coread.c
+++ b/misc/examples/coroutines/coread.c
@@ -1,6 +1,6 @@
#define i_implement
#include <stc/cstr.h>
-#include <stc/algo/coroutine.h>
+#include <stc/coroutine.h>
#include <errno.h>
// Read file line by line using coroutines:
@@ -33,7 +33,7 @@ int main(void)
{
struct file_read g = {__FILE__};
int n = 0;
- cco_block_on(file_read(&g))
+ cco_call_blocking(file_read(&g))
{
printf("%3d %s\n", ++n, cstr_str(&g.line));
//if (n == 10) cco_stop(&g);
diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines/coroutines.c
index b8dfaa13..489c3ed6 100644
--- a/misc/examples/coroutines.c
+++ b/misc/examples/coroutines/coroutines.c
@@ -1,4 +1,4 @@
-#include <stc/algo/coroutine.h>
+#include <stc/coroutine.h>
#include <stdio.h>
#include <stdint.h>
@@ -84,13 +84,13 @@ struct combined {
int combined(struct combined* g) {
cco_routine(g) {
- cco_await_on(prime(&g->prm));
- cco_await_on(fibonacci(&g->fib));
+ cco_call_await(prime(&g->prm));
+ cco_call_await(fibonacci(&g->fib));
// Reuse the g->prm context and extend the count:
g->prm.count = 8, g->prm.result += 2;
cco_reset(&g->prm);
- cco_await_on(prime(&g->prm));
+ cco_call_await(prime(&g->prm));
cco_cleanup:
puts("final combined");
@@ -103,7 +103,7 @@ int main(void)
struct combined c = {.prm={.count=8}, .fib={14}};
int res;
- cco_block_on(combined(&c), &res) {
+ cco_call_blocking(combined(&c), &res) {
if (res == CCO_YIELD)
printf("Prime(%d)=%lld, Fib(%d)=%lld\n",
c.prm.idx, c.prm.result,
diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c
new file mode 100644
index 00000000..e4afbe2b
--- /dev/null
+++ b/misc/examples/coroutines/cotasks1.c
@@ -0,0 +1,100 @@
+// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/
+
+#include <time.h>
+#include <stdio.h>
+#define i_static
+#include <stc/cstr.h>
+#include <stc/coroutine.h>
+
+struct next_value {
+ int val;
+ int cco_state;
+ cco_timer tm;
+};
+
+int next_value(struct next_value* co)
+{
+ cco_routine (co) {
+ while (true) {
+ cco_timer_await(&co->tm, 1 + rand() % 2);
+ co->val = rand();
+ cco_yield();
+ }
+ }
+ return 0;
+}
+
+void print_time()
+{
+ time_t now = time(NULL);
+ char mbstr[64];
+ strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now));
+ printf("%s ", mbstr);
+}
+
+// PRODUCER
+
+struct produce_items {
+ struct next_value next;
+ cstr str;
+ int cco_state;
+};
+
+int produce_items(struct produce_items* p)
+{
+ cco_routine (p) {
+ p->str = cstr_null;
+ while (true)
+ {
+ cco_await(next_value(&p->next) != CCO_AWAIT);
+ cstr_printf(&p->str, "item %d", p->next.val);
+ print_time();
+ printf("produced %s\n", cstr_str(&p->str));
+ cco_yield();
+ }
+ cco_cleanup:
+ cstr_drop(&p->str);
+ puts("done produce");
+ }
+ return 0;
+}
+
+// CONSUMER
+
+struct consume_items {
+ int n, i;
+ int cco_state;
+};
+
+int consume_items(struct consume_items* c, struct produce_items* p)
+{
+ cco_routine (c) {
+ for (c->i = 1; c->i <= c->n; ++c->i)
+ {
+ printf("consume #%d\n", c->i);
+ cco_await(produce_items(p) != CCO_AWAIT);
+ print_time();
+ printf("consumed %s\n", cstr_str(&p->str));
+ }
+ cco_cleanup:
+ puts("done consume");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct produce_items produce = {0};
+ struct consume_items consume = {.n=5};
+ int count = 0;
+
+ cco_call_blocking(consume_items(&consume, &produce))
+ {
+ ++count;
+ //cco_sleep(0.001);
+ //if (consume.i == 3) cco_stop(&consume);
+ }
+ cco_stop(&produce);
+ produce_items(&produce);
+ printf("count: %d\n", count);
+} \ No newline at end of file
diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c
new file mode 100644
index 00000000..4fdf98d9
--- /dev/null
+++ b/misc/examples/coroutines/cotasks2.c
@@ -0,0 +1,98 @@
+// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/
+
+#include <time.h>
+#include <stdio.h>
+#define i_static
+#include <stc/cstr.h>
+#include <stc/coroutine.h>
+
+cco_task_struct (next_value,
+ int val;
+ cco_timer tm;
+);
+
+int next_value(struct next_value* co, cco_runtime* rt)
+{
+ cco_routine (co) {
+ while (true) {
+ cco_timer_await(&co->tm, 1 + rand() % 2);
+ co->val = rand();
+ cco_yield();
+ }
+ }
+ return 0;
+}
+
+void print_time()
+{
+ time_t now = time(NULL);
+ char mbstr[64];
+ strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now));
+ printf("%s ", mbstr);
+}
+
+// PRODUCER
+
+cco_task_struct (produce_items,
+ struct next_value next;
+ cstr str;
+);
+
+int produce_items(struct produce_items* p, cco_runtime* rt)
+{
+ cco_routine (p) {
+ p->str = cstr_null;
+ p->next.cco_func = next_value;
+ while (true)
+ {
+ // await for next CCO_YIELD (or CCO_DONE) in next_value
+ cco_task_await(&p->next, rt, CCO_YIELD);
+ cstr_printf(&p->str, "item %d", p->next.val);
+ print_time();
+ printf("produced %s\n", cstr_str(&p->str));
+ cco_yield();
+ }
+
+ cco_cleanup:
+ cstr_drop(&p->str);
+ puts("done produce");
+ }
+ return 0;
+}
+
+// CONSUMER
+
+cco_task_struct (consume_items,
+ int n, i;
+ struct produce_items produce;
+);
+
+int consume_items(struct consume_items* c, cco_runtime* rt)
+{
+ cco_routine (c) {
+ c->produce.cco_func = produce_items;
+
+ for (c->i = 1; c->i <= c->n; ++c->i)
+ {
+ printf("consume #%d\n", c->i);
+ cco_task_await(&c->produce, rt, CCO_YIELD);
+ print_time();
+ printf("consumed %s\n", cstr_str(&c->produce.str));
+ }
+
+ cco_cleanup:
+ cco_stop(&c->produce);
+ cco_task_resume(&c->produce, rt);
+ puts("done consume");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct consume_items consume = {
+ .cco_func = consume_items,
+ .n = 5,
+ };
+ cco_task_blocking(&consume);
+}
diff --git a/misc/examples/dining_philosophers.c b/misc/examples/coroutines/dining_philosophers.c
index a5063a42..abe09204 100644
--- a/misc/examples/dining_philosophers.c
+++ b/misc/examples/coroutines/dining_philosophers.c
@@ -2,7 +2,7 @@
#include <stdio.h>
#include <time.h>
#include <stc/crand.h>
-#include <stc/algo/coroutine.h>
+#include <stc/coroutine.h>
// Define the number of philosophers and forks
enum {
diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c
new file mode 100644
index 00000000..bfce7810
--- /dev/null
+++ b/misc/examples/coroutines/filetask.c
@@ -0,0 +1,80 @@
+// https://github.com/lewissbaker/cppcoro#taskt
+
+#include <time.h>
+#include <stdio.h>
+#define i_static
+#include <stc/cstr.h>
+#include <stc/coroutine.h>
+
+cco_task_struct(file_read,
+ const char* path;
+ cstr line;
+ FILE* fp;
+ cco_timer tm;
+);
+
+int file_read(struct file_read* co, cco_runtime* rt)
+{
+ cco_routine (co) {
+ co->fp = fopen(co->path, "r");
+ co->line = cstr_null;
+
+ while (true) {
+ // emulate async io: await 10ms per line
+ cco_timer_await(&co->tm, 0.003);
+
+ if (!cstr_getline(&co->line, co->fp))
+ break;
+ cco_yield();
+ }
+
+ cco_cleanup:
+ fclose(co->fp);
+ cstr_drop(&co->line);
+ puts("done file_read");
+ }
+ return 0;
+}
+
+cco_task_struct(count_line,
+ cstr path;
+ struct file_read reader;
+ int lineCount;
+);
+
+int count_line(struct count_line* co, cco_runtime* rt)
+{
+ cco_routine (co) {
+ co->reader.cco_func = file_read;
+ co->reader.path = cstr_str(&co->path);
+ while (true)
+ {
+ // await for next CCO_YIELD (or CCO_DONE) in file_read()
+ cco_task_await(&co->reader, rt, CCO_YIELD);
+ if (rt->result == CCO_DONE) break;
+ co->lineCount += 1;
+ cco_yield();
+ }
+
+ cco_cleanup:
+ cstr_drop(&co->path);
+ puts("done count_line");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ // Creates a new task
+ struct count_line countTask = {
+ .cco_func = count_line,
+ .path = cstr_from(__FILE__),
+ };
+
+ // Execute coroutine as top-level blocking
+ int loop = 0;
+ cco_task_blocking(&countTask) { ++loop; }
+
+ printf("line count = %d\n", countTask.lineCount);
+ printf("exec count = %d\n", loop);
+}
diff --git a/misc/examples/generator.c b/misc/examples/coroutines/generator.c
index a15f9ba5..f9e59fea 100644
--- a/misc/examples/generator.c
+++ b/misc/examples/coroutines/generator.c
@@ -1,7 +1,7 @@
// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
-#include <stc/algo/coroutine.h>
#include <stdio.h>
+#include <stc/coroutine.h>
typedef struct {
int size;
diff --git a/misc/examples/scheduler.c b/misc/examples/coroutines/scheduler.c
index 38defd0f..78461277 100644
--- a/misc/examples/scheduler.c
+++ b/misc/examples/coroutines/scheduler.c
@@ -1,6 +1,6 @@
// https://www.youtube.com/watch?v=8sEe-4tig_A
#include <stdio.h>
-#include <stc/calgo.h>
+#include <stc/coroutine.h>
struct Task {
int (*fn)(struct Task*);
diff --git a/misc/examples/triples.c b/misc/examples/coroutines/triples.c
index 9f2fcc1e..9fd771ce 100644
--- a/misc/examples/triples.c
+++ b/misc/examples/coroutines/triples.c
@@ -1,24 +1,16 @@
// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
-#include <stc/algo/coroutine.h>
#include <stdio.h>
+#include <stc/coroutine.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, i = 0; n; ++c) {
+void triples_vanilla(int max_c) {
+ for (int c = 5, i = 0;; ++c) {
for (int a = 1; a < c; ++a) {
for (int b = a + 1; b < c; ++b) {
- if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c && gcd(a, b) == 1) {
+ if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) {
+ if (c > max_c)
+ goto done;
printf("%d: {%d, %d, %d}\n", ++i, a, b, c);
- if (--n == 0) goto done;
}
}
}
@@ -27,19 +19,21 @@ void triples_vanilla(int n) {
}
struct triples {
- int size, count;
+ int max_c;
int a, b, c;
int cco_state;
};
int triples_coro(struct triples* t) {
cco_routine(t) {
- t->count = 0;
- for (t->c = 5; t->size; ++t->c) {
+ for (t->c = 5;; ++t->c) {
for (t->a = 1; t->a < t->c; ++t->a) {
for (t->b = t->a + 1; t->b < t->c; ++t->b) {
- if ((int64_t)t->a*t->a + (int64_t)t->b*t->b == (int64_t)t->c*t->c) {
- if (t->count++ == t->size)
+ if ((int64_t)t->a * t->a +
+ (int64_t)t->b * t->b ==
+ (int64_t)t->c * t->c)
+ {
+ if (t->c > t->max_c)
cco_return;
cco_yield();
}
@@ -52,20 +46,29 @@ int triples_coro(struct triples* t) {
return 0;
}
+int gcd(int a, int b) {
+ while (b) {
+ int t = a % b;
+ a = b;
+ b = t;
+ }
+ return a;
+}
+
int main(void)
{
puts("Vanilla triples:");
- triples_vanilla(5);
+ triples_vanilla(20);
- puts("\nCoroutine triples:");
- struct triples t = {.size=INT32_MAX};
+ puts("\nCoroutine triples with GCD = 1:");
+ struct triples t = {.max_c = 100};
int n = 0;
- while (triples_coro(&t)) {
+ cco_call_blocking(triples_coro(&t)) {
if (gcd(t.a, t.b) > 1)
continue;
- if (t.c < 100)
- printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c);
+ if (++n <= 20)
+ printf("%d: {%d, %d, %d}\n", n, t.a, t.b, t.c);
else
cco_stop(&t);
}
diff --git a/misc/examples/birthday.c b/misc/examples/hashmaps/birthday.c
index 4742cb45..4742cb45 100644
--- a/misc/examples/birthday.c
+++ b/misc/examples/hashmaps/birthday.c
diff --git a/misc/examples/books.c b/misc/examples/hashmaps/books.c
index 1fd57f27..1fd57f27 100644
--- a/misc/examples/books.c
+++ b/misc/examples/hashmaps/books.c
diff --git a/misc/examples/hashmap.c b/misc/examples/hashmaps/hashmap.c
index cf11b7f7..cf11b7f7 100644
--- a/misc/examples/hashmap.c
+++ b/misc/examples/hashmaps/hashmap.c
diff --git a/misc/examples/new_map.c b/misc/examples/hashmaps/new_map.c
index de990040..de990040 100644
--- a/misc/examples/new_map.c
+++ b/misc/examples/hashmaps/new_map.c
diff --git a/misc/examples/phonebook.c b/misc/examples/hashmaps/phonebook.c
index faf7566e..faf7566e 100644
--- a/misc/examples/phonebook.c
+++ b/misc/examples/hashmaps/phonebook.c
diff --git a/misc/examples/unordered_set.c b/misc/examples/hashmaps/unordered_set.c
index dd899d78..dd899d78 100644
--- a/misc/examples/unordered_set.c
+++ b/misc/examples/hashmaps/unordered_set.c
diff --git a/misc/examples/vikings.c b/misc/examples/hashmaps/vikings.c
index d6125854..d6125854 100644
--- a/misc/examples/vikings.c
+++ b/misc/examples/hashmaps/vikings.c
diff --git a/misc/examples/intrusive.c b/misc/examples/linkedlists/intrusive.c
index 80c1f63b..c7402d09 100644
--- a/misc/examples/intrusive.c
+++ b/misc/examples/linkedlists/intrusive.c
@@ -4,7 +4,7 @@
#define i_type List
#define i_key int
-#define i_native_cmp
+#define i_cmp_native
#include <stc/clist.h>
void printList(List list) {
diff --git a/misc/examples/list.c b/misc/examples/linkedlists/list.c
index fa33305a..518cc09b 100644
--- a/misc/examples/list.c
+++ b/misc/examples/linkedlists/list.c
@@ -1,21 +1,21 @@
#include <stdio.h>
#include <time.h>
-#include <stc/algo/filter.h>
+#include <stc/algorithm.h>
#include <stc/crand.h>
#define i_type DList
#define i_key double
-#define i_native_cmp
+#define i_cmp_native
#include <stc/clist.h>
int main(void) {
const int n = 3000000;
DList list = {0};
- crand_t rng = crand_init(1234567);
+ csrand(1234567);
int m = 0;
c_forrange (n)
- DList_push_back(&list, crand_f64(&rng)*n + 100), ++m;
+ DList_push_back(&list, crandf()*n + 100), ++m;
double sum = 0.0;
printf("sumarize %d:\n", m);
diff --git a/misc/examples/list_erase.c b/misc/examples/linkedlists/list_erase.c
index 211c5a5d..211c5a5d 100644
--- a/misc/examples/list_erase.c
+++ b/misc/examples/linkedlists/list_erase.c
diff --git a/misc/examples/list_splice.c b/misc/examples/linkedlists/list_splice.c
index f1fd6e1f..f1fd6e1f 100644
--- a/misc/examples/list_splice.c
+++ b/misc/examples/linkedlists/list_splice.c
diff --git a/misc/examples/new_list.c b/misc/examples/linkedlists/new_list.c
index 9676e7b4..2112bf1f 100644
--- a/misc/examples/new_list.c
+++ b/misc/examples/linkedlists/new_list.c
@@ -27,7 +27,7 @@ int point_cmp(const Point* a, const Point* b) {
#include <stc/clist.h>
#define i_key float
-#define i_native_cmp // use < and == operators for comparison
+#define i_cmp_native // use < and == operators for comparison
#include <stc/clist.h>
void MyStruct_drop(MyStruct* s);
diff --git a/misc/examples/make.sh b/misc/examples/make.sh
index cf224950..b362f275 100755
--- a/misc/examples/make.sh
+++ b/misc/examples/make.sh
@@ -37,18 +37,20 @@ else
fi
if [ $run = 0 ] ; then
- for i in *.c ; do
- echo $comp -I../../include $i $clibs $oflag$(basename $i .c).exe
- $comp -I../../include $i $clibs $oflag$(basename $i .c).exe
+ for i in */*.c ; do
+ out=$(basename $i .c).exe
+ #out=$(dirname $i)/$(basename $i .c).exe
+ echo $comp -I../../include $i $clibs $oflag$out
+ $comp -I../../include $i $clibs $oflag$out
done
else
- for i in *.c ; do
+ for i in */*.c ; do
echo $comp -I../../include $i $clibs
$comp -I../../include $i $clibs
- if [ -f $(basename -s .c $i).exe ]; then ./$(basename -s .c $i).exe; fi
- if [ -f ./a.exe ]; then ./a.exe; fi
- if [ -f ./a.out ]; then ./a.out; fi
+ out=$(basename $i .c).exe
+ #out=$(dirname $i)/$(basename $i .c).exe
+ if [ -f $out ]; then ./$out; fi
done
fi
-rm -f a.out *.o *.obj # *.exe
+#rm -f a.out *.o *.obj # *.exe
diff --git a/misc/examples/astar.c b/misc/examples/mixed/astar.c
index 590b7952..590b7952 100644
--- a/misc/examples/astar.c
+++ b/misc/examples/mixed/astar.c
diff --git a/misc/examples/complex.c b/misc/examples/mixed/complex.c
index 4eb1574b..4eb1574b 100644
--- a/misc/examples/complex.c
+++ b/misc/examples/mixed/complex.c
diff --git a/misc/examples/convert.c b/misc/examples/mixed/convert.c
index fa64560e..fa64560e 100644
--- a/misc/examples/convert.c
+++ b/misc/examples/mixed/convert.c
diff --git a/misc/examples/demos.c b/misc/examples/mixed/demos.c
index ecc89f2e..1a604d9f 100644
--- a/misc/examples/demos.c
+++ b/misc/examples/mixed/demos.c
@@ -74,7 +74,7 @@ void vectordemo2(void)
#define i_key int
#define i_tag ix
-#define i_native_cmp
+#define i_cmp_native
#include <stc/clist.h>
void listdemo1(void)
diff --git a/misc/examples/inits.c b/misc/examples/mixed/inits.c
index 53a49f1f..53a49f1f 100644
--- a/misc/examples/inits.c
+++ b/misc/examples/mixed/inits.c
diff --git a/misc/examples/read.c b/misc/examples/mixed/read.c
index b12f7409..de04fd31 100644
--- a/misc/examples/read.c
+++ b/misc/examples/mixed/read.c
@@ -7,9 +7,9 @@
cvec_str read_file(const char* name)
{
- cvec_str vec = cvec_str_init();
+ cvec_str vec = {0};
c_with (FILE* f = fopen(name, "r"), fclose(f))
- c_with (cstr line = cstr_null, cstr_drop(&line))
+ c_with (cstr line = {0}, cstr_drop(&line))
while (cstr_getline(&line, f))
cvec_str_push(&vec, cstr_clone(line));
return vec;
diff --git a/misc/examples/functor.c b/misc/examples/priorityqueues/functor.c
index e3bde1dd..e3bde1dd 100644
--- a/misc/examples/functor.c
+++ b/misc/examples/priorityqueues/functor.c
diff --git a/misc/examples/new_pque.c b/misc/examples/priorityqueues/new_pque.c
index 16823bb6..16823bb6 100644
--- a/misc/examples/new_pque.c
+++ b/misc/examples/priorityqueues/new_pque.c
diff --git a/misc/examples/priority.c b/misc/examples/priorityqueues/priority.c
index bf2e188a..18684e73 100644
--- a/misc/examples/priority.c
+++ b/misc/examples/priorityqueues/priority.c
@@ -11,21 +11,21 @@
int main(void) {
intptr_t N = 10000000;
crand_t rng = crand_init((uint64_t)time(NULL));
- crand_unif_t dist = crand_unif_init(0, N * 10);
+ crand_uniform_t dist = crand_uniform_init(0, N * 10);
cpque_i heap = {0};
// Push ten million random numbers to priority queue
printf("Push %" c_ZI " numbers\n", N);
c_forrange (N)
- cpque_i_push(&heap, crand_unif(&rng, &dist));
+ cpque_i_push(&heap, crand_uniform(&rng, &dist));
// push some negative numbers too.
c_forlist (i, int, {-231, -32, -873, -4, -343})
cpque_i_push(&heap, *i.ref);
c_forrange (N)
- cpque_i_push(&heap, crand_unif(&rng, &dist));
+ cpque_i_push(&heap, crand_uniform(&rng, &dist));
puts("Extract the hundred smallest.");
c_forrange (100) {
diff --git a/misc/examples/new_queue.c b/misc/examples/queues/new_queue.c
index f3592df6..3904c50c 100644
--- a/misc/examples/new_queue.c
+++ b/misc/examples/queues/new_queue.c
@@ -23,19 +23,19 @@ int point_cmp(const Point* a, const Point* b) {
int main(void) {
int n = 50000000;
crand_t rng = crand_init((uint64_t)time(NULL));
- crand_unif_t dist = crand_unif_init(0, n);
+ crand_uniform_t dist = crand_uniform_init(0, n);
IQ Q = {0};
// Push 50'000'000 random numbers onto the queue.
c_forrange (n)
- IQ_push(&Q, (int)crand_unif(&rng, &dist));
+ IQ_push(&Q, (int)crand_uniform(&rng, &dist));
// Push or pop on the queue 50 million times
printf("befor: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q));
c_forrange (n) {
- int r = (int)crand_unif(&rng, &dist);
+ int r = (int)crand_uniform(&rng, &dist);
if (r & 3)
IQ_push(&Q, r);
else
diff --git a/misc/examples/queue.c b/misc/examples/queues/queue.c
index 867a6c7b..5b1f7606 100644
--- a/misc/examples/queue.c
+++ b/misc/examples/queues/queue.c
@@ -5,22 +5,22 @@
#define i_tag i
#include <stc/cqueue.h>
-int main() {
+int main(void) {
int n = 1000000;
- crand_unif_t dist;
+ crand_uniform_t dist;
crand_t rng = crand_init(1234);
- dist = crand_unif_init(0, n);
+ dist = crand_uniform_init(0, n);
cqueue_i queue = {0};
// Push ten million random numbers onto the queue.
c_forrange (n)
- cqueue_i_push(&queue, (int)crand_unif(&rng, &dist));
+ cqueue_i_push(&queue, (int)crand_uniform(&rng, &dist));
// Push or pop on the queue ten million times
printf("%d\n", n);
c_forrange (n) { // forrange uses initial n only.
- int r = (int)crand_unif(&rng, &dist);
+ int r = (int)crand_uniform(&rng, &dist);
if (r & 1)
++n, cqueue_i_push(&queue, r);
else
diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c
deleted file mode 100644
index 694ce12e..00000000
--- a/misc/examples/rawptr_elements.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <stc/ccommon.h>
-#include <stdio.h>
-#define i_implement
-#include <stc/cstr.h>
-
-// Create cmap of cstr => long*
-#define i_type SIPtrMap
-#define i_key_str
-#define i_val long*
-#define i_valraw long
-#define i_valfrom(raw) c_new(long, raw)
-#define i_valto(x) **x
-#define i_valclone(x) c_new(long, *x)
-#define i_valdrop(x) c_free(*x)
-#include <stc/cmap.h>
-
-// Alternatively, using cbox:
-#define i_type IBox
-#define i_key long
-#include <stc/cbox.h> // unique_ptr<long> alike.
-
-// cmap of cstr => IBox
-#define i_type SIBoxMap
-#define i_key_str
-#define i_valboxed IBox // i_valboxed: use properties from IBox automatically
-#include <stc/cmap.h>
-
-int main(void)
-{
- // These have the same behaviour, except IBox has a get member:
- SIPtrMap map1 = {0};
- SIBoxMap map2 = {0};
-
- printf("\nMap cstr => long*:\n");
- SIPtrMap_insert(&map1, cstr_from("Test1"), c_new(long, 1));
- SIPtrMap_insert(&map1, cstr_from("Test2"), c_new(long, 2));
-
- // Emplace implicitly creates cstr from const char* and an owned long* from long!
- SIPtrMap_emplace(&map1, "Test3", 3);
- SIPtrMap_emplace(&map1, "Test4", 4);
-
- c_forpair (name, number, SIPtrMap, map1)
- printf("%s: %ld\n", cstr_str(_.name), **_.number);
-
- puts("\nMap cstr => IBox:");
- SIBoxMap_insert(&map2, cstr_from("Test1"), IBox_make(1));
- SIBoxMap_insert(&map2, cstr_from("Test2"), IBox_make(2));
-
- // Emplace implicitly creates cstr from const char* and IBox from long!
- SIBoxMap_emplace(&map2, "Test3", 3);
- SIBoxMap_emplace(&map2, "Test4", 4);
-
- c_forpair (name, number, SIBoxMap, map2)
- printf("%s: %ld\n", cstr_str(_.name), *_.number->get);
- puts("");
-
- SIPtrMap_drop(&map1);
- SIBoxMap_drop(&map2);
-}
diff --git a/misc/examples/regex1.c b/misc/examples/regularexpressions/regex1.c
index d8032358..d8032358 100644
--- a/misc/examples/regex1.c
+++ b/misc/examples/regularexpressions/regex1.c
diff --git a/misc/examples/regex2.c b/misc/examples/regularexpressions/regex2.c
index a798b1a1..a798b1a1 100644
--- a/misc/examples/regex2.c
+++ b/misc/examples/regularexpressions/regex2.c
diff --git a/misc/examples/regex_match.c b/misc/examples/regularexpressions/regex_match.c
index 11426d2d..11426d2d 100644
--- a/misc/examples/regex_match.c
+++ b/misc/examples/regularexpressions/regex_match.c
diff --git a/misc/examples/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c
index f1ea2711..f1ea2711 100644
--- a/misc/examples/regex_replace.c
+++ b/misc/examples/regularexpressions/regex_replace.c
diff --git a/misc/examples/sidebyside.cpp b/misc/examples/sidebyside.cpp
deleted file mode 100644
index 9414b691..00000000
--- a/misc/examples/sidebyside.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#include <iostream>
-#include <map>
-#include <string>
-#include <stc/cstr.h>
-
-#define i_type IIMap
-#define i_key int
-#define i_val int
-#include <stc/csmap.h>
-
-#define i_type SIMap
-#define i_key_str
-#define i_val int
-#include <stc/cmap.h>
-
-int main(void) {
- {
- std::map<int, int> hist;
- hist.emplace(12, 100).first->second += 1;
- hist.emplace(13, 100).first->second += 1;
- hist.emplace(12, 100).first->second += 1;
-
- for (auto i: hist)
- std::cout << i.first << ", " << i.second << std::endl;
- std::cout << std::endl;
- }
- {
- IIMap hist = {0};
- IIMap_insert(&hist, 12, 100).ref->second += 1;
- IIMap_insert(&hist, 13, 100).ref->second += 1;
- IIMap_insert(&hist, 12, 100).ref->second += 1;
-
- c_foreach (i, IIMap, hist)
- printf("%d, %d\n", i.ref->first, i.ref->second);
- puts("");
- IIMap_drop(&hist);
- }
- // ===================================================
- {
- std::map<std::string, int> food =
- {{"burger", 5}, {"pizza", 12}, {"steak", 15}};
-
- for (auto i: food)
- std::cout << i.first << ", " << i.second << std::endl;
- std::cout << std::endl;
- }
- {
- SIMap food = {0};
- c_forlist (i, SIMap_raw, {{"burger", 5}, {"pizza", 12}, {"steak", 15}})
- SIMap_emplace(&food, i.ref->first, i.ref->second);
-
- c_foreach (i, SIMap, food)
- printf("%s, %d\n", cstr_str(&i.ref->first), i.ref->second);
- puts("");
- SIMap_drop(&food);
- }
-}
diff --git a/misc/examples/arc_containers.c b/misc/examples/smartpointers/arc_containers.c
index 2fb04c56..2fb04c56 100644
--- a/misc/examples/arc_containers.c
+++ b/misc/examples/smartpointers/arc_containers.c
diff --git a/misc/examples/arc_demo.c b/misc/examples/smartpointers/arc_demo.c
index 87d64e67..929a48a1 100644
--- a/misc/examples/arc_demo.c
+++ b/misc/examples/smartpointers/arc_demo.c
@@ -11,7 +11,7 @@ void int_drop(int* x) {
#define i_type Arc // set type name to be defined (instead of 'carc_int')
#define i_key int
#define i_keydrop int_drop // optional, just to display the elements destroyed
-#define i_native_cmp // use int comparison (x < y, x == y).
+#define i_cmp_native // use int comparison (x < y, x == y).
#include <stc/carc.h> // Arc
#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements
diff --git a/misc/examples/arcvec_erase.c b/misc/examples/smartpointers/arcvec_erase.c
index addef8b7..ba54c1c7 100644
--- a/misc/examples/arcvec_erase.c
+++ b/misc/examples/smartpointers/arcvec_erase.c
@@ -5,7 +5,7 @@ void show_drop(int* x) { printf("drop: %d\n", *x); }
#define i_type Arc
#define i_key int
#define i_keydrop show_drop
-#define i_native_cmp // enable sort/search for int type
+#define i_cmp_native // enable sort/search for int type
#include <stc/carc.h> // Shared pointer to int
#define i_type Vec
diff --git a/misc/examples/box.c b/misc/examples/smartpointers/box.c
index 94d126c0..94d126c0 100644
--- a/misc/examples/box.c
+++ b/misc/examples/smartpointers/box.c
diff --git a/misc/examples/box2.c b/misc/examples/smartpointers/box2.c
index eaab1c47..eaab1c47 100644
--- a/misc/examples/box2.c
+++ b/misc/examples/smartpointers/box2.c
diff --git a/misc/examples/smartpointers/map_box.c b/misc/examples/smartpointers/map_box.c
new file mode 100644
index 00000000..f651b302
--- /dev/null
+++ b/misc/examples/smartpointers/map_box.c
@@ -0,0 +1,34 @@
+#include <stc/ccommon.h>
+#include <stdio.h>
+#define i_implement
+#include <stc/cstr.h>
+
+#define i_type IBox
+#define i_key long
+#include <stc/cbox.h> // unique_ptr<long> alike.
+
+// cmap of cstr => IBox
+#define i_type Boxmap
+#define i_key_str
+#define i_valboxed IBox // i_valboxed: use properties from IBox automatically
+#include <stc/cmap.h>
+
+
+int main(void)
+{
+ Boxmap map = {0};
+
+ puts("Map cstr => IBox:");
+ Boxmap_insert(&map, cstr_from("Test1"), IBox_make(1));
+ Boxmap_insert(&map, cstr_from("Test2"), IBox_make(2));
+
+ // Simpler: emplace() implicitly creates cstr from const char* and IBox from long!
+ Boxmap_emplace(&map, "Test3", 3);
+ Boxmap_emplace(&map, "Test4", 4);
+
+ c_forpair (name, number, Boxmap, map)
+ printf("%s: %ld\n", cstr_str(_.name), *_.number->get);
+ puts("");
+
+ Boxmap_drop(&map);
+}
diff --git a/misc/examples/smartpointers/map_ptr.c b/misc/examples/smartpointers/map_ptr.c
new file mode 100644
index 00000000..453322c5
--- /dev/null
+++ b/misc/examples/smartpointers/map_ptr.c
@@ -0,0 +1,34 @@
+#include <stc/ccommon.h>
+#include <stdio.h>
+#define i_implement
+#include <stc/cstr.h>
+
+// cmap of cstr => long*
+#define i_type Ptrmap
+#define i_key_str
+#define i_val long*
+#define i_valraw long
+#define i_valfrom(raw) c_new(long, raw)
+#define i_valto(x) **x
+#define i_valclone(x) c_new(long, *x)
+#define i_valdrop(x) c_free(*x)
+#include <stc/cmap.h>
+
+int main(void)
+{
+ Ptrmap map = {0};
+
+ puts("Map cstr => long*:");
+ Ptrmap_insert(&map, cstr_from("Test1"), c_new(long, 1));
+ Ptrmap_insert(&map, cstr_from("Test2"), c_new(long, 2));
+
+ // Simple: emplace() implicitly creates cstr from const char* and an owned long* from long!
+ Ptrmap_emplace(&map, "Test3", 3);
+ Ptrmap_emplace(&map, "Test4", 4);
+
+ c_forpair (name, number, Ptrmap, map)
+ printf("%s: %ld\n", cstr_str(_.name), **_.number);
+ puts("");
+
+ Ptrmap_drop(&map);
+}
diff --git a/misc/examples/music_arc.c b/misc/examples/smartpointers/music_arc.c
index 16111b0b..13d368c3 100644
--- a/misc/examples/music_arc.c
+++ b/misc/examples/smartpointers/music_arc.c
@@ -12,7 +12,7 @@ typedef struct
int Song_cmp(const Song* x, const Song* y)
{ return cstr_cmp(&x->title, &y->title); }
-Song Song_make(const char* artist, const char* title)
+Song Song_init(const char* artist, const char* title)
{ return c_LITERAL(Song){cstr_from(artist), cstr_from(title)}; }
void Song_drop(Song* s) {
@@ -34,9 +34,9 @@ void Song_drop(Song* s) {
void example3(void)
{
SongVec vec1 = c_init(SongVec, {
- Song_make("Bob Dylan", "The Times They Are A Changing"),
- Song_make("Aretha Franklin", "Bridge Over Troubled Water"),
- Song_make("Thalia", "Entre El Mar y Una Estrella")
+ Song_init("Bob Dylan", "The Times They Are A Changing"),
+ Song_init("Aretha Franklin", "Bridge Over Troubled Water"),
+ Song_init("Thalia", "Entre El Mar y Una Estrella")
});
SongVec vec2 = {0};
@@ -47,8 +47,8 @@ void example3(void)
// Add a few more to vec2. We can use emplace when creating new entries
// Emplace calls SongArc_from() on the argument to create the Arc:
- SongVec_emplace(&vec2, Song_make("Michael Jackson", "Billie Jean"));
- SongVec_emplace(&vec2, Song_make("Rihanna", "Stay"));
+ SongVec_emplace(&vec2, Song_init("Michael Jackson", "Billie Jean"));
+ SongVec_emplace(&vec2, Song_init("Rihanna", "Stay"));
// We now have two vectors with some shared, some unique entries.
c_forlist (i, SongVec, {vec1, vec2}) {
diff --git a/misc/examples/new_sptr.c b/misc/examples/smartpointers/new_sptr.c
index 7fef5d1f..3c6fa16c 100644
--- a/misc/examples/new_sptr.c
+++ b/misc/examples/smartpointers/new_sptr.c
@@ -15,7 +15,7 @@ uint64_t Person_hash(const Person* p);
#define i_type IPtr
#define i_key int
#define i_keydrop(x) printf("drop: %d\n", *x)
-#define i_native_cmp
+#define i_cmp_native
#include <stc/carc.h>
#define i_type IPStack
diff --git a/misc/examples/person_arc.c b/misc/examples/smartpointers/person_arc.c
index 38c883a7..38c883a7 100644
--- a/misc/examples/person_arc.c
+++ b/misc/examples/smartpointers/person_arc.c
diff --git a/misc/examples/csmap_erase.c b/misc/examples/sortedmaps/csmap_erase.c
index 8d4eeae3..8d4eeae3 100644
--- a/misc/examples/csmap_erase.c
+++ b/misc/examples/sortedmaps/csmap_erase.c
diff --git a/misc/examples/csmap_find.c b/misc/examples/sortedmaps/csmap_find.c
index c392338d..c392338d 100644
--- a/misc/examples/csmap_find.c
+++ b/misc/examples/sortedmaps/csmap_find.c
diff --git a/misc/examples/csmap_insert.c b/misc/examples/sortedmaps/csmap_insert.c
index c9f02891..c9f02891 100644
--- a/misc/examples/csmap_insert.c
+++ b/misc/examples/sortedmaps/csmap_insert.c
diff --git a/misc/examples/csset_erase.c b/misc/examples/sortedmaps/csset_erase.c
index 9c7f5e1a..9c7f5e1a 100644
--- a/misc/examples/csset_erase.c
+++ b/misc/examples/sortedmaps/csset_erase.c
diff --git a/misc/examples/gauss2.c b/misc/examples/sortedmaps/gauss2.c
index 1ab8ade5..02ce4bc5 100644
--- a/misc/examples/gauss2.c
+++ b/misc/examples/sortedmaps/gauss2.c
@@ -21,14 +21,14 @@ int main(void)
printf("Mean %f, StdDev %f\n", Mean, StdDev);
// Setup random engine with normal distribution.
- crand_norm_t dist = crand_norm_init(Mean, StdDev);
+ crand_normal_t dist = crand_normal_init(Mean, StdDev);
// Create and init histogram map with defered destruct
csmap_int hist = {0};
cstr bar = {0};
c_forrange (N) {
- int index = (int)round(crand_norm(&rng, &dist));
+ int index = (int)round(crand_normal(&rng, &dist));
csmap_int_insert(&hist, index, 0).ref->second += 1;
}
diff --git a/misc/examples/mmap.c b/misc/examples/sortedmaps/listmap.c
index 04a605a7..04a605a7 100644
--- a/misc/examples/mmap.c
+++ b/misc/examples/sortedmaps/listmap.c
diff --git a/misc/examples/mapmap.c b/misc/examples/sortedmaps/mapmap.c
index d3065659..d3065659 100644
--- a/misc/examples/mapmap.c
+++ b/misc/examples/sortedmaps/mapmap.c
diff --git a/misc/examples/multimap.c b/misc/examples/sortedmaps/multimap.c
index 1068a5dc..1068a5dc 100644
--- a/misc/examples/multimap.c
+++ b/misc/examples/sortedmaps/multimap.c
diff --git a/misc/examples/new_smap.c b/misc/examples/sortedmaps/new_smap.c
index ee946c9a..ee946c9a 100644
--- a/misc/examples/new_smap.c
+++ b/misc/examples/sortedmaps/new_smap.c
diff --git a/misc/examples/sorted_map.c b/misc/examples/sortedmaps/sorted_map.c
index 89381554..89381554 100644
--- a/misc/examples/sorted_map.c
+++ b/misc/examples/sortedmaps/sorted_map.c
diff --git a/misc/examples/spans/mdspan.c b/misc/examples/spans/mdspan.c
new file mode 100644
index 00000000..db601850
--- /dev/null
+++ b/misc/examples/spans/mdspan.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stc/cspan.h>
+#include <stdlib.h>
+
+using_cspan3(DSpan, double);
+
+int main(void) {
+ const int nx=5, ny=4, nz=3;
+ double* data = c_new_n(double, nx*ny*nz);
+
+ printf("\nMultidim span ms[5, 4, 3], fortran ordered");
+ DSpan3 ms = cspan_md_order('F', data, nx, ny, nz); // Fortran, not 'C'
+
+ int idx = 0;
+ for (int i = 0; i < ms.shape[0]; ++i)
+ for (int j = 0; j < ms.shape[1]; ++j)
+ for (int k = 0; k < ms.shape[2]; ++k)
+ *cspan_at(&ms, i, j, k) = ++idx;
+
+ cspan_transpose(&ms);
+
+ printf(", transposed:\n\n");
+ for (int i = 0; i < ms.shape[0]; ++i) {
+ for (int j = 0; j < ms.shape[1]; ++j) {
+ for (int k = 0; k < ms.shape[2]; ++k)
+ printf(" %3g", *cspan_at(&ms, i, j, k));
+ puts("");
+ }
+ puts("");
+ }
+
+ DSpan2 sub;
+
+ puts("Slicing:");
+ printf("\nms[0, :, :] ");
+ sub = cspan_slice(DSpan2, &ms, {0}, {c_ALL}, {c_ALL});
+ c_foreach (i, DSpan2, sub) printf(" %g", *i.ref);
+ puts("");
+
+ printf("\nms[:, 0, :] ");
+ sub = cspan_slice(DSpan2, &ms, {c_ALL}, {0}, {c_ALL});
+ c_foreach (i, DSpan2, sub) printf(" %g", *i.ref);
+ puts("");
+
+ sub = cspan_slice(DSpan2, &ms, {c_ALL}, {c_ALL}, {0});
+ printf("\nms[:, :, 0] ");
+ c_foreach (i, DSpan2, sub) printf(" %g", *i.ref);
+ puts("");
+
+ free(data);
+}
diff --git a/misc/examples/multidim.c b/misc/examples/spans/multidim.c
index 798a1126..798a1126 100644
--- a/misc/examples/multidim.c
+++ b/misc/examples/spans/multidim.c
diff --git a/misc/examples/printspan.c b/misc/examples/spans/printspan.c
index cd3c5f4f..cd3c5f4f 100644
--- a/misc/examples/printspan.c
+++ b/misc/examples/spans/printspan.c
diff --git a/misc/examples/cstr_match.c b/misc/examples/strings/cstr_match.c
index be03e981..be03e981 100644
--- a/misc/examples/cstr_match.c
+++ b/misc/examples/strings/cstr_match.c
diff --git a/misc/examples/replace.c b/misc/examples/strings/replace.c
index 59a56bf7..59a56bf7 100644
--- a/misc/examples/replace.c
+++ b/misc/examples/strings/replace.c
diff --git a/misc/examples/splitstr.c b/misc/examples/strings/splitstr.c
index ef7ed174..ef7ed174 100644
--- a/misc/examples/splitstr.c
+++ b/misc/examples/strings/splitstr.c
diff --git a/misc/examples/sso_map.c b/misc/examples/strings/sso_map.c
index 4f84b651..4f84b651 100644
--- a/misc/examples/sso_map.c
+++ b/misc/examples/strings/sso_map.c
diff --git a/misc/examples/sso_substr.c b/misc/examples/strings/sso_substr.c
index 687658df..687658df 100644
--- a/misc/examples/sso_substr.c
+++ b/misc/examples/strings/sso_substr.c
diff --git a/misc/examples/sview_split.c b/misc/examples/strings/sview_split.c
index ac275da0..ac275da0 100644
--- a/misc/examples/sview_split.c
+++ b/misc/examples/strings/sview_split.c
diff --git a/misc/examples/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c
index 1d54486f..1d54486f 100644
--- a/misc/examples/utf8replace_c.c
+++ b/misc/examples/strings/utf8replace_c.c
diff --git a/misc/examples/utf8replace_rs.rs b/misc/examples/strings/utf8replace_rs.rs
index 8b163b4e..8b163b4e 100644
--- a/misc/examples/utf8replace_rs.rs
+++ b/misc/examples/strings/utf8replace_rs.rs
diff --git a/misc/examples/lower_bound.c b/misc/examples/vectors/lower_bound.c
index e5d816e9..bea828f2 100644
--- a/misc/examples/lower_bound.c
+++ b/misc/examples/vectors/lower_bound.c
@@ -1,7 +1,7 @@
#include <stdio.h>
#define i_key int
-#define i_native_cmp
+#define i_cmp_native
#include <stc/cvec.h>
#define i_key int
diff --git a/misc/examples/new_vec.c b/misc/examples/vectors/new_vec.c
index 88efd55a..88efd55a 100644
--- a/misc/examples/new_vec.c
+++ b/misc/examples/vectors/new_vec.c
diff --git a/misc/examples/stack.c b/misc/examples/vectors/stack.c
index 6297fb6f..6297fb6f 100644
--- a/misc/examples/stack.c
+++ b/misc/examples/vectors/stack.c
diff --git a/src/singleheader.py b/src/singleheader.py
index 2255568d..637edbcb 100644
--- a/src/singleheader.py
+++ b/src/singleheader.py
@@ -68,12 +68,14 @@ def process_file(
if __name__ == "__main__":
- print(
- process_file(
- abspath(sys.argv[1]),
- [],
- # We use an include guard instead of `#pragma once` because Godbolt will
- # cause complaints about `#pragma once` when they are used in URL includes.
- [abspath(sys.argv[1])],
+ with open(sys.argv[2], "w", newline='\n') as f:
+ print(
+ process_file(
+ abspath(sys.argv[1]),
+ [],
+ # We use an include guard instead of `#pragma once` because Godbolt will
+ # cause complaints about `#pragma once` when they are used in URL includes.
+ [abspath(sys.argv[1])],
+ ),
+ file=f
)
- )
diff --git a/src/singleupdate.sh b/src/singleupdate.sh
index 8a621e57..e706dd97 100644
--- a/src/singleupdate.sh
+++ b/src/singleupdate.sh
@@ -1,27 +1,30 @@
d=$(git rev-parse --show-toplevel)
-mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc
-python singleheader.py $d/include/c11/fmt.h > $d/../stcsingle/c11/fmt.h
-python singleheader.py $d/include/stc/calgo.h > $d/../stcsingle/stc/calgo.h
-python singleheader.py $d/include/stc/carc.h > $d/../stcsingle/stc/carc.h
-python singleheader.py $d/include/stc/cbits.h > $d/../stcsingle/stc/cbits.h
-python singleheader.py $d/include/stc/cbox.h > $d/../stcsingle/stc/cbox.h
-python singleheader.py $d/include/stc/ccommon.h > $d/../stcsingle/stc/ccommon.h
-python singleheader.py $d/include/stc/cdeq.h > $d/../stcsingle/stc/cdeq.h
-python singleheader.py $d/include/stc/clist.h > $d/../stcsingle/stc/clist.h
-python singleheader.py $d/include/stc/cmap.h > $d/../stcsingle/stc/cmap.h
-python singleheader.py $d/include/stc/coption.h > $d/../stcsingle/stc/coption.h
-python singleheader.py $d/include/stc/cpque.h > $d/../stcsingle/stc/cpque.h
-python singleheader.py $d/include/stc/cqueue.h > $d/../stcsingle/stc/cqueue.h
-python singleheader.py $d/include/stc/crand.h > $d/../stcsingle/stc/crand.h
-python singleheader.py $d/include/stc/cregex.h > $d/../stcsingle/stc/cregex.h
-python singleheader.py $d/include/stc/cset.h > $d/../stcsingle/stc/cset.h
-python singleheader.py $d/include/stc/csmap.h > $d/../stcsingle/stc/csmap.h
-python singleheader.py $d/include/stc/cspan.h > $d/../stcsingle/stc/cspan.h
-python singleheader.py $d/include/stc/csset.h > $d/../stcsingle/stc/csset.h
-python singleheader.py $d/include/stc/cstack.h > $d/../stcsingle/stc/cstack.h
-python singleheader.py $d/include/stc/cstr.h > $d/../stcsingle/stc/cstr.h
-python singleheader.py $d/include/stc/csview.h > $d/../stcsingle/stc/csview.h
-python singleheader.py $d/include/stc/cvec.h > $d/../stcsingle/stc/cvec.h
-python singleheader.py $d/include/stc/extend.h > $d/../stcsingle/stc/extend.h
-python singleheader.py $d/include/stc/forward.h > $d/../stcsingle/stc/forward.h
+mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc/algo
+python singleheader.py $d/include/c11/fmt.h $d/../stcsingle/c11/fmt.h
+python singleheader.py $d/include/stc/algorithm.h $d/../stcsingle/stc/algorithm.h
+python singleheader.py $d/include/stc/coroutine.h $d/../stcsingle/stc/coroutine.h
+python singleheader.py $d/include/stc/algo/sort.h $d/../stcsingle/stc/algo/sort.h
+python singleheader.py $d/include/stc/carc.h $d/../stcsingle/stc/carc.h
+python singleheader.py $d/include/stc/cbits.h $d/../stcsingle/stc/cbits.h
+python singleheader.py $d/include/stc/cbox.h $d/../stcsingle/stc/cbox.h
+python singleheader.py $d/include/stc/ccommon.h $d/../stcsingle/stc/ccommon.h
+python singleheader.py $d/include/stc/cdeq.h $d/../stcsingle/stc/cdeq.h
+python singleheader.py $d/include/stc/clist.h $d/../stcsingle/stc/clist.h
+python singleheader.py $d/include/stc/cmap.h $d/../stcsingle/stc/cmap.h
+python singleheader.py $d/include/stc/coption.h $d/../stcsingle/stc/coption.h
+python singleheader.py $d/include/stc/cpque.h $d/../stcsingle/stc/cpque.h
+python singleheader.py $d/include/stc/cqueue.h $d/../stcsingle/stc/cqueue.h
+python singleheader.py $d/include/stc/crand.h $d/../stcsingle/stc/crand.h
+python singleheader.py $d/include/stc/cregex.h $d/../stcsingle/stc/cregex.h
+python singleheader.py $d/include/stc/cset.h $d/../stcsingle/stc/cset.h
+
+python singleheader.py $d/include/stc/csmap.h $d/../stcsingle/stc/csmap.h
+python singleheader.py $d/include/stc/cspan.h $d/../stcsingle/stc/cspan.h
+python singleheader.py $d/include/stc/csset.h $d/../stcsingle/stc/csset.h
+python singleheader.py $d/include/stc/cstack.h $d/../stcsingle/stc/cstack.h
+python singleheader.py $d/include/stc/cstr.h $d/../stcsingle/stc/cstr.h
+python singleheader.py $d/include/stc/csview.h $d/../stcsingle/stc/csview.h
+python singleheader.py $d/include/stc/cvec.h $d/../stcsingle/stc/cvec.h
+python singleheader.py $d/include/stc/extend.h $d/../stcsingle/stc/extend.h
+python singleheader.py $d/include/stc/forward.h $d/../stcsingle/stc/forward.h
echo "$d/../stcsingle headers updated"